/*
This file is part of Ext JS 4.1

Copyright (c) 2011-2012 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
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.

If you are unsure which license is appropriate for your use, please contact the sales department
at http://www.sencha.com/contact.

Build date: 2012-07-04 21:11:01 (65ff594cd80b9bad45df640c22cc0adb52c95a7b)
*/

(function(Ext){
if (typeof Ext === 'undefined') {
	this.Ext = {};
}
Ext.sandboxName = 'Ext4';
Ext.isSandboxed = true;
Ext.buildSettings = {"baseCSSPrefix":"x4-","scopeResetCSS":true};


var Ext = Ext || {};
Ext._startTime = new Date().getTime();
(function() {
    var global = this,
        objectPrototype = Object.prototype,
        toString = objectPrototype.toString,
        enumerables = true,
        enumerablesTest = { toString: 1 },
        emptyFn = function () {},
        
        
        callOverrideParent = function () {
            var method = callOverrideParent.caller.caller; 
            return method.$owner.prototype[method.$name].apply(this, arguments);
        },
        i;

    Ext.global = global;

    for (i in enumerablesTest) {
        enumerables = null;
    }

    if (enumerables) {
        enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
                       'toLocaleString', 'toString', 'constructor'];
    }

    
    Ext.enumerables = enumerables;

    
    Ext.apply = function(object, config, defaults) {
        if (defaults) {
            Ext.apply(object, defaults);
        }

        if (object && config && typeof config === 'object') {
            var i, j, k;

            for (i in config) {
                object[i] = config[i];
            }

            if (enumerables) {
                for (j = enumerables.length; j--;) {
                    k = enumerables[j];
                    if (config.hasOwnProperty(k)) {
                        object[k] = config[k];
                    }
                }
            }
        }

        return object;
    };

    Ext.buildSettings = Ext.apply({
        baseCSSPrefix: 'x-',
        scopeResetCSS: false
    }, Ext.buildSettings || {});

    Ext.apply(Ext, {

        
        name: Ext.sandboxName || 'Ext',

        
        emptyFn: emptyFn,

        
        emptyString: new String(),

        baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,

        
        applyIf: function(object, config) {
            var property;

            if (object) {
                for (property in config) {
                    if (object[property] === undefined) {
                        object[property] = config[property];
                    }
                }
            }

            return object;
        },

        
        iterate: function(object, fn, scope) {
            if (Ext.isEmpty(object)) {
                return;
            }

            if (scope === undefined) {
                scope = object;
            }

            if (Ext.isIterable(object)) {
                Ext.Array.each.call(Ext.Array, object, fn, scope);
            }
            else {
                Ext.Object.each.call(Ext.Object, object, fn, scope);
            }
        }
    });

    Ext.apply(Ext, {

        
        extend: (function() {
            
            var objectConstructor = objectPrototype.constructor,
                inlineOverrides = function(o) {
                for (var m in o) {
                    if (!o.hasOwnProperty(m)) {
                        continue;
                    }
                    this[m] = o[m];
                }
            };

            return function(subclass, superclass, overrides) {
                
                if (Ext.isObject(superclass)) {
                    overrides = superclass;
                    superclass = subclass;
                    subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
                        superclass.apply(this, arguments);
                    };
                }


                
                var F = function() {},
                    subclassProto, superclassProto = superclass.prototype;

                F.prototype = superclassProto;
                subclassProto = subclass.prototype = new F();
                subclassProto.constructor = subclass;
                subclass.superclass = superclassProto;

                if (superclassProto.constructor === objectConstructor) {
                    superclassProto.constructor = superclass;
                }

                subclass.override = function(overrides) {
                    Ext.override(subclass, overrides);
                };

                subclassProto.override = inlineOverrides;
                subclassProto.proto = subclassProto;

                subclass.override(overrides);
                subclass.extend = function(o) {
                    return Ext.extend(subclass, o);
                };

                return subclass;
            };
        }()),

        
        override: function (target, overrides) {
            if (target.$isClass) {
                target.override(overrides);
            } else if (typeof target == 'function') {
                Ext.apply(target.prototype, overrides);
            } else {
                var owner = target.self,
                    name, value;

                if (owner && owner.$isClass) { 
                    for (name in overrides) {
                        if (overrides.hasOwnProperty(name)) {
                            value = overrides[name];

                            if (typeof value == 'function') {

                                value.$name = name;
                                value.$owner = owner;
                                value.$previous = target.hasOwnProperty(name)
                                    ? target[name] 
                                    : callOverrideParent; 
                            }

                            target[name] = value;
                        }
                    }
                } else {
                    Ext.apply(target, overrides);
                }
            }

            return target;
        }
    });

    
    Ext.apply(Ext, {

        
        valueFrom: function(value, defaultValue, allowBlank){
            return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
        },

        
        typeOf: function(value) {
            var type,
                typeToString;
            
            if (value === null) {
                return 'null';
            }

            type = typeof value;

            if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
                return type;
            }

            typeToString = toString.call(value);

            switch(typeToString) {
                case '[object Array]':
                    return 'array';
                case '[object Date]':
                    return 'date';
                case '[object Boolean]':
                    return 'boolean';
                case '[object Number]':
                    return 'number';
                case '[object RegExp]':
                    return 'regexp';
            }

            if (type === 'function') {
                return 'function';
            }

            if (type === 'object') {
                if (value.nodeType !== undefined) {
                    if (value.nodeType === 3) {
                        return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
                    }
                    else {
                        return 'element';
                    }
                }

                return 'object';
            }

        },

        
        isEmpty: function(value, allowEmptyString) {
            return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
        },

        
        isArray: ('isArray' in Array) ? Array.isArray : function(value) {
            return toString.call(value) === '[object Array]';
        },

        
        isDate: function(value) {
            return toString.call(value) === '[object Date]';
        },

        
        isObject: (toString.call(null) === '[object Object]') ?
        function(value) {
            
            return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
        } :
        function(value) {
            return toString.call(value) === '[object Object]';
        },

        
        isSimpleObject: function(value) {
            return value instanceof Object && value.constructor === Object;
        },
        
        isPrimitive: function(value) {
            var type = typeof value;

            return type === 'string' || type === 'number' || type === 'boolean';
        },

        
        isFunction:
        
        
        (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
            return toString.call(value) === '[object Function]';
        } : function(value) {
            return typeof value === 'function';
        },

        
        isNumber: function(value) {
            return typeof value === 'number' && isFinite(value);
        },

        
        isNumeric: function(value) {
            return !isNaN(parseFloat(value)) && isFinite(value);
        },

        
        isString: function(value) {
            return typeof value === 'string';
        },

        
        isBoolean: function(value) {
            return typeof value === 'boolean';
        },

        
        isElement: function(value) {
            return value ? value.nodeType === 1 : false;
        },

        
        isTextNode: function(value) {
            return value ? value.nodeName === "#text" : false;
        },

        
        isDefined: function(value) {
            return typeof value !== 'undefined';
        },

        
        isIterable: function(value) {
            var type = typeof value,
                checkLength = false;
            if (value && type != 'string') {
                
                if (type == 'function') {
                    
                    
                    if (Ext.isSafari) {
                        checkLength = value instanceof NodeList || value instanceof HTMLCollection;
                    }
                } else {
                    checkLength = true;
                }
            }
            return checkLength ? value.length !== undefined : false;
        }
    });

    Ext.apply(Ext, {

        
        clone: function(item) {
            var type,
                i,
                j,
                k,
                clone,
                key;
            
            if (item === null || item === undefined) {
                return item;
            }

            
            
            
            if (item.nodeType && item.cloneNode) {
                return item.cloneNode(true);
            }

            type = toString.call(item);

            
            if (type === '[object Date]') {
                return new Date(item.getTime());
            }


            
            if (type === '[object Array]') {
                i = item.length;

                clone = [];

                while (i--) {
                    clone[i] = Ext.clone(item[i]);
                }
            }
            
            else if (type === '[object Object]' && item.constructor === Object) {
                clone = {};

                for (key in item) {
                    clone[key] = Ext.clone(item[key]);
                }

                if (enumerables) {
                    for (j = enumerables.length; j--;) {
                        k = enumerables[j];
                        clone[k] = item[k];
                    }
                }
            }

            return clone || item;
        },

        
        getUniqueGlobalNamespace: function() {
            var uniqueGlobalNamespace = this.uniqueGlobalNamespace,
                i;

            if (uniqueGlobalNamespace === undefined) {
                i = 0;

                do {
                    uniqueGlobalNamespace = 'ExtBox' + (++i);
                } while (Ext.global[uniqueGlobalNamespace] !== undefined);

                Ext.global[uniqueGlobalNamespace] = Ext;
                this.uniqueGlobalNamespace = uniqueGlobalNamespace;
            }

            return uniqueGlobalNamespace;
        },
        
        
        functionFactoryCache: {},
        
        cacheableFunctionFactory: function() {
            var me = this,
                args = Array.prototype.slice.call(arguments),
                cache = me.functionFactoryCache,
                idx, fn, ln;
                
             if (Ext.isSandboxed) {
                ln = args.length;
                if (ln > 0) {
                    ln--;
                    args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
                }
            }
            idx = args.join('');
            fn = cache[idx];
            if (!fn) {
                fn = Function.prototype.constructor.apply(Function.prototype, args);
                
                cache[idx] = fn;
            }
            return fn;
        },
        
        functionFactory: function() {
            var me = this,
                args = Array.prototype.slice.call(arguments),
                ln;
                
            if (Ext.isSandboxed) {
                ln = args.length;
                if (ln > 0) {
                    ln--;
                    args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
                }
            }
     
            return Function.prototype.constructor.apply(Function.prototype, args);
        },

        
        Logger: {
            verbose: emptyFn,
            log: emptyFn,
            info: emptyFn,
            warn: emptyFn,
            error: function(message) {
                throw new Error(message);
            },
            deprecate: emptyFn
        }
    });

    
    Ext.type = Ext.typeOf;

}());


Ext.globalEval = Ext.global.execScript
    ? function(code) {
        execScript(code);
    }
    : function($$code) {
        
        
        (function(){
            eval($$code);
        }());
    };


(function() {


var version = '4.1.1', Version;
    Ext.Version = Version = Ext.extend(Object, {

        
        constructor: function(version) {
            var parts, releaseStartIndex;

            if (version instanceof Version) {
                return version;
            }

            this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');

            releaseStartIndex = this.version.search(/([^\d\.])/);

            if (releaseStartIndex !== -1) {
                this.release = this.version.substr(releaseStartIndex, version.length);
                this.shortVersion = this.version.substr(0, releaseStartIndex);
            }

            this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');

            parts = this.version.split('.');

            this.major = parseInt(parts.shift() || 0, 10);
            this.minor = parseInt(parts.shift() || 0, 10);
            this.patch = parseInt(parts.shift() || 0, 10);
            this.build = parseInt(parts.shift() || 0, 10);

            return this;
        },

        
        toString: function() {
            return this.version;
        },

        
        valueOf: function() {
            return this.version;
        },

        
        getMajor: function() {
            return this.major || 0;
        },

        
        getMinor: function() {
            return this.minor || 0;
        },

        
        getPatch: function() {
            return this.patch || 0;
        },

        
        getBuild: function() {
            return this.build || 0;
        },

        
        getRelease: function() {
            return this.release || '';
        },

        
        isGreaterThan: function(target) {
            return Version.compare(this.version, target) === 1;
        },

        
        isGreaterThanOrEqual: function(target) {
            return Version.compare(this.version, target) >= 0;
        },

        
        isLessThan: function(target) {
            return Version.compare(this.version, target) === -1;
        },

        
        isLessThanOrEqual: function(target) {
            return Version.compare(this.version, target) <= 0;
        },

        
        equals: function(target) {
            return Version.compare(this.version, target) === 0;
        },

        
        match: function(target) {
            target = String(target);
            return this.version.substr(0, target.length) === target;
        },

        
        toArray: function() {
            return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
        },

        
        getShortVersion: function() {
            return this.shortVersion;
        },

        
        gt: function() {
            return this.isGreaterThan.apply(this, arguments);
        },

        
        lt: function() {
            return this.isLessThan.apply(this, arguments);
        },

        
        gtEq: function() {
            return this.isGreaterThanOrEqual.apply(this, arguments);
        },

        
        ltEq: function() {
            return this.isLessThanOrEqual.apply(this, arguments);
        }
    });

    Ext.apply(Version, {
        
        releaseValueMap: {
            'dev': -6,
            'alpha': -5,
            'a': -5,
            'beta': -4,
            'b': -4,
            'rc': -3,
            '#': -2,
            'p': -1,
            'pl': -1
        },

        
        getComponentValue: function(value) {
            return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
        },

        
        compare: function(current, target) {
            var currentValue, targetValue, i;

            current = new Version(current).toArray();
            target = new Version(target).toArray();

            for (i = 0; i < Math.max(current.length, target.length); i++) {
                currentValue = this.getComponentValue(current[i]);
                targetValue = this.getComponentValue(target[i]);

                if (currentValue < targetValue) {
                    return -1;
                } else if (currentValue > targetValue) {
                    return 1;
                }
            }

            return 0;
        }
    });

    
    Ext.apply(Ext, {
        
        versions: {},

        
        lastRegisteredVersion: null,

        
        setVersion: function(packageName, version) {
            Ext.versions[packageName] = new Version(version);
            Ext.lastRegisteredVersion = Ext.versions[packageName];

            return this;
        },

        
        getVersion: function(packageName) {
            if (packageName === undefined) {
                return Ext.lastRegisteredVersion;
            }

            return Ext.versions[packageName];
        },

        
        deprecate: function(packageName, since, closure, scope) {
            if (Version.compare(Ext.getVersion(packageName), since) < 1) {
                closure.call(scope);
            }
        }
    }); 

    Ext.setVersion('core', version);

}());



Ext.String = (function() {
    var 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,
        escapeRe      = /('|\\)/g,
        formatRe      = /\{(\d+)\}/g,
        escapeRegexRe = /([-.*+?\^${}()|\[\]\/\\])/g,
        basicTrimRe   = /^\s+|\s+$/g,
        whitespaceRe  = /\s+/,
        varReplace    = /(^[^a-z]*|[^\w])/gi,
        charToEntity,
        entityToChar,
        charToEntityRegex,
        entityToCharRegex,
        htmlEncodeReplaceFn = function(match, capture) {
            return charToEntity[capture];
        },
        htmlDecodeReplaceFn = function(match, capture) {
            return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
        };

    return {

        
        createVarName: function(s) {
            return s.replace(varReplace, '');
        },

        
        htmlEncode: function(value) {
            return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
        },

        
        htmlDecode: function(value) {
            return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
        },

        
        addCharacterEntities: function(newEntities) {
            var charKeys = [],
                entityKeys = [],
                key, echar;
            for (key in newEntities) {
                echar = newEntities[key];
                entityToChar[key] = echar;
                charToEntity[echar] = key;
                charKeys.push(echar);
                entityKeys.push(key);
            }
            charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
            entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
        },

        
        resetCharacterEntities: function() {
            charToEntity = {};
            entityToChar = {};
            
            this.addCharacterEntities({
                '&amp;'     :   '&',
                '&gt;'      :   '>',
                '&lt;'      :   '<',
                '&quot;'    :   '"',
                '&#39;'     :   "'"
            });
        },

        
        urlAppend : function(url, string) {
            if (!Ext.isEmpty(string)) {
                return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
            }

            return url;
        },

        
        trim: function(string) {
            return string.replace(trimRegex, "");
        },

        
        capitalize: function(string) {
            return string.charAt(0).toUpperCase() + string.substr(1);
        },

        
        uncapitalize: function(string) {
            return string.charAt(0).toLowerCase() + string.substr(1);
        },

        
        ellipsis: function(value, len, word) {
            if (value && value.length > len) {
                if (word) {
                    var vs = value.substr(0, len - 2),
                    index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
                    if (index !== -1 && index >= (len - 15)) {
                        return vs.substr(0, index) + "...";
                    }
                }
                return value.substr(0, len - 3) + "...";
            }
            return value;
        },

        
        escapeRegex: function(string) {
            return string.replace(escapeRegexRe, "\\$1");
        },

        
        escape: function(string) {
            return string.replace(escapeRe, "\\$1");
        },

        
        toggle: function(string, value, other) {
            return string === value ? other : value;
        },

        
        leftPad: function(string, size, character) {
            var result = String(string);
            character = character || " ";
            while (result.length < size) {
                result = character + result;
            }
            return result;
        },

        
        format: function(format) {
            var args = Ext.Array.toArray(arguments, 1);
            return format.replace(formatRe, function(m, i) {
                return args[i];
            });
        },

        
        repeat: function(pattern, count, sep) {
            for (var buf = [], i = count; i--; ) {
                buf.push(pattern);
            }
            return buf.join(sep || '');
        },

        
        splitWords: function (words) {
            if (words && typeof words == 'string') {
                return words.replace(basicTrimRe, '').split(whitespaceRe);
            }
            return words || [];
        }
    };
}());


Ext.String.resetCharacterEntities();


Ext.htmlEncode = Ext.String.htmlEncode;



Ext.htmlDecode = Ext.String.htmlDecode;


Ext.urlAppend = Ext.String.urlAppend;


Ext.Number = new function() {

    var me = this,
        isToFixedBroken = (0.9).toFixed() !== '1',
        math = Math;

    Ext.apply(this, {
        
        constrain: function(number, min, max) {
            var x = parseFloat(number);

            
            

            
            
            
            
            
            return (x < min) ? min : ((x > max) ? max : x);
        },

        
        snap : function(value, increment, minValue, maxValue) {
            var m;

            
            
            if (value === undefined || value < minValue) {
                return minValue || 0;
            }

            if (increment) {
                m = value % increment;
                if (m !== 0) {
                    value -= m;
                    if (m * 2 >= increment) {
                        value += increment;
                    } else if (m * 2 < -increment) {
                        value -= increment;
                    }
                }
            }
            return me.constrain(value, minValue,  maxValue);
        },

        
        snapInRange : function(value, increment, minValue, maxValue) {
            var tween;

            
            minValue = (minValue || 0);

            
            if (value === undefined || value < minValue) {
                return minValue;
            }

            
            if (increment && (tween = ((value - minValue) % increment))) {
                value -= tween;
                tween *= 2;
                if (tween >= increment) {
                    value += increment;
                }
            }

            
            if (maxValue !== undefined) {
                if (value > (maxValue = me.snapInRange(maxValue, increment, minValue))) {
                    value = maxValue;
                }
            }

            return value;
        },

        
        toFixed: isToFixedBroken ? function(value, precision) {
            precision = precision || 0;
            var pow = math.pow(10, precision);
            return (math.round(value * pow) / pow).toFixed(precision);
        } : function(value, precision) {
            return value.toFixed(precision);
        },

        
        from: function(value, defaultValue) {
            if (isFinite(value)) {
                value = parseFloat(value);
            }

            return !isNaN(value) ? value : defaultValue;
        },

        
        randomInt: function (from, to) {
           return math.floor(math.random() * (to - from + 1) + from);
        }
    });

    
    Ext.num = function() {
        return me.from.apply(this, arguments);
    };
};

(function() {

    var arrayPrototype = Array.prototype,
        slice = arrayPrototype.slice,
        supportsSplice = (function () {
            var array = [],
                lengthBefore,
                j = 20;

            if (!array.splice) {
                return false;
            }

            
            

            while (j--) {
                array.push("A");
            }

            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");

            lengthBefore = array.length; 
            array.splice(13, 0, "XXX"); 

            if (lengthBefore+1 != array.length) {
                return false;
            }
            

            return true;
        }()),
        supportsForEach = 'forEach' in arrayPrototype,
        supportsMap = 'map' in arrayPrototype,
        supportsIndexOf = 'indexOf' in arrayPrototype,
        supportsEvery = 'every' in arrayPrototype,
        supportsSome = 'some' in arrayPrototype,
        supportsFilter = 'filter' in arrayPrototype,
        supportsSort = (function() {
            var a = [1,2,3,4,5].sort(function(){ return 0; });
            return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
        }()),
        supportsSliceOnNodeList = true,
        ExtArray,
        erase,
        replace,
        splice;

    try {
        
        if (typeof document !== 'undefined') {
            slice.call(document.getElementsByTagName('body'));
        }
    } catch (e) {
        supportsSliceOnNodeList = false;
    }

    function fixArrayIndex (array, index) {
        return (index < 0) ? Math.max(0, array.length + index)
                           : Math.min(array.length, index);
    }

    
    function replaceSim (array, index, removeCount, insert) {
        var add = insert ? insert.length : 0,
            length = array.length,
            pos = fixArrayIndex(array, index),
            remove,
            tailOldPos,
            tailNewPos,
            tailCount,
            lengthAfterRemove,
            i;

        
        if (pos === length) {
            if (add) {
                array.push.apply(array, insert);
            }
        } else {
            remove = Math.min(removeCount, length - pos);
            tailOldPos = pos + remove;
            tailNewPos = tailOldPos + add - remove;
            tailCount = length - tailOldPos;
            lengthAfterRemove = length - remove;

            if (tailNewPos < tailOldPos) { 
                for (i = 0; i < tailCount; ++i) {
                    array[tailNewPos+i] = array[tailOldPos+i];
                }
            } else if (tailNewPos > tailOldPos) { 
                for (i = tailCount; i--; ) {
                    array[tailNewPos+i] = array[tailOldPos+i];
                }
            } 

            if (add && pos === lengthAfterRemove) {
                array.length = lengthAfterRemove; 
                array.push.apply(array, insert);
            } else {
                array.length = lengthAfterRemove + add; 
                for (i = 0; i < add; ++i) {
                    array[pos+i] = insert[i];
                }
            }
        }

        return array;
    }

    function replaceNative (array, index, removeCount, insert) {
        if (insert && insert.length) {
            if (index < array.length) {
                array.splice.apply(array, [index, removeCount].concat(insert));
            } else {
                array.push.apply(array, insert);
            }
        } else {
            array.splice(index, removeCount);
        }
        return array;
    }

    function eraseSim (array, index, removeCount) {
        return replaceSim(array, index, removeCount);
    }

    function eraseNative (array, index, removeCount) {
        array.splice(index, removeCount);
        return array;
    }

    function spliceSim (array, index, removeCount) {
        var pos = fixArrayIndex(array, index),
            removed = array.slice(index, fixArrayIndex(array, pos+removeCount));

        if (arguments.length < 4) {
            replaceSim(array, pos, removeCount);
        } else {
            replaceSim(array, pos, removeCount, slice.call(arguments, 3));
        }

        return removed;
    }

    function spliceNative (array) {
        return array.splice.apply(array, slice.call(arguments, 1));
    }

    erase = supportsSplice ? eraseNative : eraseSim;
    replace = supportsSplice ? replaceNative : replaceSim;
    splice = supportsSplice ? spliceNative : spliceSim;

    

    ExtArray = Ext.Array = {
        
        each: function(array, fn, scope, reverse) {
            array = ExtArray.from(array);

            var i,
                ln = array.length;

            if (reverse !== true) {
                for (i = 0; i < ln; i++) {
                    if (fn.call(scope || array[i], array[i], i, array) === false) {
                        return i;
                    }
                }
            }
            else {
                for (i = ln - 1; i > -1; i--) {
                    if (fn.call(scope || array[i], array[i], i, array) === false) {
                        return i;
                    }
                }
            }

            return true;
        },

        
        forEach: supportsForEach ? function(array, fn, scope) {
            return array.forEach(fn, scope);
        } : function(array, fn, scope) {
            var i = 0,
                ln = array.length;

            for (; i < ln; i++) {
                fn.call(scope, array[i], i, array);
            }
        },

        
        indexOf: supportsIndexOf ? function(array, item, from) {
            return array.indexOf(item, from);
         } : function(array, item, from) {
            var i, length = array.length;

            for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
                if (array[i] === item) {
                    return i;
                }
            }

            return -1;
        },

        
        contains: supportsIndexOf ? function(array, item) {
            return array.indexOf(item) !== -1;
        } : function(array, item) {
            var i, ln;

            for (i = 0, ln = array.length; i < ln; i++) {
                if (array[i] === item) {
                    return true;
                }
            }

            return false;
        },

        
        toArray: function(iterable, start, end){
            if (!iterable || !iterable.length) {
                return [];
            }

            if (typeof iterable === 'string') {
                iterable = iterable.split('');
            }

            if (supportsSliceOnNodeList) {
                return slice.call(iterable, start || 0, end || iterable.length);
            }

            var array = [],
                i;

            start = start || 0;
            end = end ? ((end < 0) ? iterable.length + end : end) : iterable.length;

            for (i = start; i < end; i++) {
                array.push(iterable[i]);
            }

            return array;
        },

        
        pluck: function(array, propertyName) {
            var ret = [],
                i, ln, item;

            for (i = 0, ln = array.length; i < ln; i++) {
                item = array[i];

                ret.push(item[propertyName]);
            }

            return ret;
        },

        
        map: supportsMap ? function(array, fn, scope) {
            return array.map(fn, scope);
        } : function(array, fn, scope) {
            var results = [],
                i = 0,
                len = array.length;

            for (; i < len; i++) {
                results[i] = fn.call(scope, array[i], i, array);
            }

            return results;
        },

        
        every: supportsEvery ? function(array, fn, scope) {
            return array.every(fn, scope);
        } : function(array, fn, scope) {
            var i = 0,
                ln = array.length;

            for (; i < ln; ++i) {
                if (!fn.call(scope, array[i], i, array)) {
                    return false;
                }
            }

            return true;
        },

        
        some: supportsSome ? function(array, fn, scope) {
            return array.some(fn, scope);
        } : function(array, fn, scope) {
            var i = 0,
                ln = array.length;

            for (; i < ln; ++i) {
                if (fn.call(scope, array[i], i, array)) {
                    return true;
                }
            }

            return false;
        },

        
        clean: function(array) {
            var results = [],
                i = 0,
                ln = array.length,
                item;

            for (; i < ln; i++) {
                item = array[i];

                if (!Ext.isEmpty(item)) {
                    results.push(item);
                }
            }

            return results;
        },

        
        unique: function(array) {
            var clone = [],
                i = 0,
                ln = array.length,
                item;

            for (; i < ln; i++) {
                item = array[i];

                if (ExtArray.indexOf(clone, item) === -1) {
                    clone.push(item);
                }
            }

            return clone;
        },

        
        filter: supportsFilter ? function(array, fn, scope) {
            return array.filter(fn, scope);
        } : function(array, fn, scope) {
            var results = [],
                i = 0,
                ln = array.length;

            for (; i < ln; i++) {
                if (fn.call(scope, array[i], i, array)) {
                    results.push(array[i]);
                }
            }

            return results;
        },

        
        from: function(value, newReference) {
            if (value === undefined || value === null) {
                return [];
            }

            if (Ext.isArray(value)) {
                return (newReference) ? slice.call(value) : value;
            }

            var type = typeof value;
            
            
            if (value && value.length !== undefined && type !== 'string' && (type !== 'function' || !value.apply)) {
                return ExtArray.toArray(value);
            }

            return [value];
        },

        
        remove: function(array, item) {
            var index = ExtArray.indexOf(array, item);

            if (index !== -1) {
                erase(array, index, 1);
            }

            return array;
        },

        
        include: function(array, item) {
            if (!ExtArray.contains(array, item)) {
                array.push(item);
            }
        },

        
        clone: function(array) {
            return slice.call(array);
        },

        
        merge: function() {
            var args = slice.call(arguments),
                array = [],
                i, ln;

            for (i = 0, ln = args.length; i < ln; i++) {
                array = array.concat(args[i]);
            }

            return ExtArray.unique(array);
        },

        
        intersect: function() {
            var intersection = [],
                arrays = slice.call(arguments),
                arraysLength,
                array,
                arrayLength,
                minArray,
                minArrayIndex,
                minArrayCandidate,
                minArrayLength,
                element,
                elementCandidate,
                elementCount,
                i, j, k;

            if (!arrays.length) {
                return intersection;
            }

            
            arraysLength = arrays.length;
            for (i = minArrayIndex = 0; i < arraysLength; i++) {
                minArrayCandidate = arrays[i];
                if (!minArray || minArrayCandidate.length < minArray.length) {
                    minArray = minArrayCandidate;
                    minArrayIndex = i;
                }
            }

            minArray = ExtArray.unique(minArray);
            erase(arrays, minArrayIndex, 1);

            
            
            
            minArrayLength = minArray.length;
            arraysLength = arrays.length;
            for (i = 0; i < minArrayLength; i++) {
                element = minArray[i];
                elementCount = 0;

                for (j = 0; j < arraysLength; j++) {
                    array = arrays[j];
                    arrayLength = array.length;
                    for (k = 0; k < arrayLength; k++) {
                        elementCandidate = array[k];
                        if (element === elementCandidate) {
                            elementCount++;
                            break;
                        }
                    }
                }

                if (elementCount === arraysLength) {
                    intersection.push(element);
                }
            }

            return intersection;
        },

        
        difference: function(arrayA, arrayB) {
            var clone = slice.call(arrayA),
                ln = clone.length,
                i, j, lnB;

            for (i = 0,lnB = arrayB.length; i < lnB; i++) {
                for (j = 0; j < ln; j++) {
                    if (clone[j] === arrayB[i]) {
                        erase(clone, j, 1);
                        j--;
                        ln--;
                    }
                }
            }

            return clone;
        },

        
        
        slice: ([1,2].slice(1, undefined).length ?
            function (array, begin, end) {
                return slice.call(array, begin, end);
            } :
            
            function (array, begin, end) {
                
                
                if (typeof begin === 'undefined') {
                    return slice.call(array);
                }
                if (typeof end === 'undefined') {
                    return slice.call(array, begin);
                }
                return slice.call(array, begin, end);
            }
        ),

        
        sort: supportsSort ? function(array, sortFn) {
            if (sortFn) {
                return array.sort(sortFn);
            } else {
                return array.sort();
            }
         } : function(array, sortFn) {
            var length = array.length,
                i = 0,
                comparison,
                j, min, tmp;

            for (; i < length; i++) {
                min = i;
                for (j = i + 1; j < length; j++) {
                    if (sortFn) {
                        comparison = sortFn(array[j], array[min]);
                        if (comparison < 0) {
                            min = j;
                        }
                    } else if (array[j] < array[min]) {
                        min = j;
                    }
                }
                if (min !== i) {
                    tmp = array[i];
                    array[i] = array[min];
                    array[min] = tmp;
                }
            }

            return array;
        },

        
        flatten: function(array) {
            var worker = [];

            function rFlatten(a) {
                var i, ln, v;

                for (i = 0, ln = a.length; i < ln; i++) {
                    v = a[i];

                    if (Ext.isArray(v)) {
                        rFlatten(v);
                    } else {
                        worker.push(v);
                    }
                }

                return worker;
            }

            return rFlatten(array);
        },

        
        min: function(array, comparisonFn) {
            var min = array[0],
                i, ln, item;

            for (i = 0, ln = array.length; i < ln; i++) {
                item = array[i];

                if (comparisonFn) {
                    if (comparisonFn(min, item) === 1) {
                        min = item;
                    }
                }
                else {
                    if (item < min) {
                        min = item;
                    }
                }
            }

            return min;
        },

        
        max: function(array, comparisonFn) {
            var max = array[0],
                i, ln, item;

            for (i = 0, ln = array.length; i < ln; i++) {
                item = array[i];

                if (comparisonFn) {
                    if (comparisonFn(max, item) === -1) {
                        max = item;
                    }
                }
                else {
                    if (item > max) {
                        max = item;
                    }
                }
            }

            return max;
        },

        
        mean: function(array) {
            return array.length > 0 ? ExtArray.sum(array) / array.length : undefined;
        },

        
        sum: function(array) {
            var sum = 0,
                i, ln, item;

            for (i = 0,ln = array.length; i < ln; i++) {
                item = array[i];

                sum += item;
            }

            return sum;
        },

        
        toMap: function(array, getKey, scope) {
            var map = {},
                i = array.length;

            if (!getKey) {
                while (i--) {
                    map[array[i]] = i+1;
                }
            } else if (typeof getKey == 'string') {
                while (i--) {
                    map[array[i][getKey]] = i+1;
                }
            } else {
                while (i--) {
                    map[getKey.call(scope, array[i])] = i+1;
                }
            }

            return map;
        },


        
        erase: erase,

        
        insert: function (array, index, items) {
            return replace(array, index, 0, items);
        },

        
        replace: replace,

        
        splice: splice,

        
        push: function(array) {
            var len = arguments.length,
                i = 1,
                newItem;

            if (array === undefined) {
                array = [];
            } else if (!Ext.isArray(array)) {
                array = [array];
            }
            for (; i < len; i++) {
                newItem = arguments[i];
                Array.prototype.push[Ext.isArray(newItem) ? 'apply' : 'call'](array, newItem);
            }
            return array;
        }
    };

    
    Ext.each = ExtArray.each;

    
    ExtArray.union = ExtArray.merge;

    
    Ext.min = ExtArray.min;

    
    Ext.max = ExtArray.max;

    
    Ext.sum = ExtArray.sum;

    
    Ext.mean = ExtArray.mean;

    
    Ext.flatten = ExtArray.flatten;

    
    Ext.clean = ExtArray.clean;

    
    Ext.unique = ExtArray.unique;

    
    Ext.pluck = ExtArray.pluck;

    
    Ext.toArray = function() {
        return ExtArray.toArray.apply(ExtArray, arguments);
    };
}());


Ext.Function = {

    
    flexSetter: function(fn) {
        return function(a, b) {
            var k, i;

            if (a === null) {
                return this;
            }

            if (typeof a !== 'string') {
                for (k in a) {
                    if (a.hasOwnProperty(k)) {
                        fn.call(this, k, a[k]);
                    }
                }

                if (Ext.enumerables) {
                    for (i = Ext.enumerables.length; i--;) {
                        k = Ext.enumerables[i];
                        if (a.hasOwnProperty(k)) {
                            fn.call(this, k, a[k]);
                        }
                    }
                }
            } else {
                fn.call(this, a, b);
            }

            return this;
        };
    },

    
    bind: function(fn, scope, args, appendArgs) {
        if (arguments.length === 2) {
            return function() {
                return fn.apply(scope, arguments);
            };
        }

        var method = fn,
            slice = Array.prototype.slice;

        return function() {
            var callArgs = args || arguments;

            if (appendArgs === true) {
                callArgs = slice.call(arguments, 0);
                callArgs = callArgs.concat(args);
            }
            else if (typeof appendArgs == 'number') {
                callArgs = slice.call(arguments, 0); 
                Ext.Array.insert(callArgs, appendArgs, args);
            }

            return method.apply(scope || Ext.global, callArgs);
        };
    },

    
    pass: function(fn, args, scope) {
        if (!Ext.isArray(args)) {
            if (Ext.isIterable(args)) {
                args = Ext.Array.clone(args);
            } else {
                args = args !== undefined ? [args] : [];
            }
        }

        return function() {
            var fnArgs = [].concat(args);
            fnArgs.push.apply(fnArgs, arguments);
            return fn.apply(scope || this, fnArgs);
        };
    },

    
    alias: function(object, methodName) {
        return function() {
            return object[methodName].apply(object, arguments);
        };
    },

    
    clone: function(method) {
        return function() {
            return method.apply(this, arguments);
        };
    },

    
    createInterceptor: function(origFn, newFn, scope, returnValue) {
        var method = origFn;
        if (!Ext.isFunction(newFn)) {
            return origFn;
        }
        else {
            return function() {
                var me = this,
                    args = arguments;
                newFn.target = me;
                newFn.method = origFn;
                return (newFn.apply(scope || me || Ext.global, args) !== false) ? origFn.apply(me || Ext.global, args) : returnValue || null;
            };
        }
    },

    
    createDelayed: function(fn, delay, scope, args, appendArgs) {
        if (scope || args) {
            fn = Ext.Function.bind(fn, scope, args, appendArgs);
        }

        return function() {
            var me = this,
                args = Array.prototype.slice.call(arguments);

            setTimeout(function() {
                fn.apply(me, args);
            }, delay);
        };
    },

    
    defer: function(fn, millis, scope, args, appendArgs) {
        fn = Ext.Function.bind(fn, scope, args, appendArgs);
        if (millis > 0) {
            return setTimeout(Ext.supports.TimeoutActualLateness ? function () {
                fn();
            } : fn, millis);
        }
        fn();
        return 0;
    },

    
    createSequence: function(originalFn, newFn, scope) {
        if (!newFn) {
            return originalFn;
        }
        else {
            return function() {
                var result = originalFn.apply(this, arguments);
                newFn.apply(scope || this, arguments);
                return result;
            };
        }
    },

    
    createBuffered: function(fn, buffer, scope, args) {
        var timerId;

        return function() {
            var callArgs = args || Array.prototype.slice.call(arguments, 0),
                me = scope || this;

            if (timerId) {
                clearTimeout(timerId);
            }

            timerId = setTimeout(function(){
                fn.apply(me, callArgs);
            }, buffer);
        };
    },

    
    createThrottled: function(fn, interval, scope) {
        var lastCallTime, elapsed, lastArgs, timer, execute = function() {
            fn.apply(scope || this, lastArgs);
            lastCallTime = new Date().getTime();
        };

        return function() {
            elapsed = new Date().getTime() - lastCallTime;
            lastArgs = arguments;

            clearTimeout(timer);
            if (!lastCallTime || (elapsed >= interval)) {
                execute();
            } else {
                timer = setTimeout(execute, interval - elapsed);
            }
        };
    },


    
    interceptBefore: function(object, methodName, fn, scope) {
        var method = object[methodName] || Ext.emptyFn;

        return (object[methodName] = function() {
            var ret = fn.apply(scope || this, arguments);
            method.apply(this, arguments);

            return ret;
        });
    },

    
    interceptAfter: function(object, methodName, fn, scope) {
        var method = object[methodName] || Ext.emptyFn;

        return (object[methodName] = function() {
            method.apply(this, arguments);
            return fn.apply(scope || this, arguments);
        });
    }
};


Ext.defer = Ext.Function.alias(Ext.Function, 'defer');


Ext.pass = Ext.Function.alias(Ext.Function, 'pass');


Ext.bind = Ext.Function.alias(Ext.Function, 'bind');



(function() {


var TemplateClass = function(){},
    ExtObject = Ext.Object = {

    
    chain: function (object) {
        TemplateClass.prototype = object;
        var result = new TemplateClass();
        TemplateClass.prototype = null;
        return result;
    },

    
    toQueryObjects: function(name, value, recursive) {
        var self = ExtObject.toQueryObjects,
            objects = [],
            i, ln;

        if (Ext.isArray(value)) {
            for (i = 0, ln = value.length; i < ln; i++) {
                if (recursive) {
                    objects = objects.concat(self(name + '[' + i + ']', value[i], true));
                }
                else {
                    objects.push({
                        name: name,
                        value: value[i]
                    });
                }
            }
        }
        else if (Ext.isObject(value)) {
            for (i in value) {
                if (value.hasOwnProperty(i)) {
                    if (recursive) {
                        objects = objects.concat(self(name + '[' + i + ']', value[i], true));
                    }
                    else {
                        objects.push({
                            name: name,
                            value: value[i]
                        });
                    }
                }
            }
        }
        else {
            objects.push({
                name: name,
                value: value
            });
        }

        return objects;
    },

    
    toQueryString: function(object, recursive) {
        var paramObjects = [],
            params = [],
            i, j, ln, paramObject, value;

        for (i in object) {
            if (object.hasOwnProperty(i)) {
                paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
            }
        }

        for (j = 0, ln = paramObjects.length; j < ln; j++) {
            paramObject = paramObjects[j];
            value = paramObject.value;

            if (Ext.isEmpty(value)) {
                value = '';
            }
            else if (Ext.isDate(value)) {
                value = Ext.Date.toString(value);
            }

            params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
        }

        return params.join('&');
    },

    
    fromQueryString: function(queryString, recursive) {
        var parts = queryString.replace(/^\?/, '').split('&'),
            object = {},
            temp, components, name, value, i, ln,
            part, j, subLn, matchedKeys, matchedName,
            keys, key, nextKey;

        for (i = 0, ln = parts.length; i < ln; i++) {
            part = parts[i];

            if (part.length > 0) {
                components = part.split('=');
                name = decodeURIComponent(components[0]);
                value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';

                if (!recursive) {
                    if (object.hasOwnProperty(name)) {
                        if (!Ext.isArray(object[name])) {
                            object[name] = [object[name]];
                        }

                        object[name].push(value);
                    }
                    else {
                        object[name] = value;
                    }
                }
                else {
                    matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
                    matchedName = name.match(/^([^\[]+)/);


                    name = matchedName[0];
                    keys = [];

                    if (matchedKeys === null) {
                        object[name] = value;
                        continue;
                    }

                    for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
                        key = matchedKeys[j];
                        key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
                        keys.push(key);
                    }

                    keys.unshift(name);

                    temp = object;

                    for (j = 0, subLn = keys.length; j < subLn; j++) {
                        key = keys[j];

                        if (j === subLn - 1) {
                            if (Ext.isArray(temp) && key === '') {
                                temp.push(value);
                            }
                            else {
                                temp[key] = value;
                            }
                        }
                        else {
                            if (temp[key] === undefined || typeof temp[key] === 'string') {
                                nextKey = keys[j+1];

                                temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
                            }

                            temp = temp[key];
                        }
                    }
                }
            }
        }

        return object;
    },

    
    each: function(object, fn, scope) {
        for (var property in object) {
            if (object.hasOwnProperty(property)) {
                if (fn.call(scope || object, property, object[property], object) === false) {
                    return;
                }
            }
        }
    },

    
    merge: function(destination) {
        var i = 1,
            ln = arguments.length,
            mergeFn = ExtObject.merge,
            cloneFn = Ext.clone,
            object, key, value, sourceKey;

        for (; i < ln; i++) {
            object = arguments[i];

            for (key in object) {
                value = object[key];
                if (value && value.constructor === Object) {
                    sourceKey = destination[key];
                    if (sourceKey && sourceKey.constructor === Object) {
                        mergeFn(sourceKey, value);
                    }
                    else {
                        destination[key] = cloneFn(value);
                    }
                }
                else {
                    destination[key] = value;
                }
            }
        }

        return destination;
    },

    
    mergeIf: function(destination) {
        var i = 1,
            ln = arguments.length,
            cloneFn = Ext.clone,
            object, key, value;

        for (; i < ln; i++) {
            object = arguments[i];

            for (key in object) {
                if (!(key in destination)) {
                    value = object[key];

                    if (value && value.constructor === Object) {
                        destination[key] = cloneFn(value);
                    }
                    else {
                        destination[key] = value;
                    }
                }
            }
        }

        return destination;
    },

    
    getKey: function(object, value) {
        for (var property in object) {
            if (object.hasOwnProperty(property) && object[property] === value) {
                return property;
            }
        }

        return null;
    },

    
    getValues: function(object) {
        var values = [],
            property;

        for (property in object) {
            if (object.hasOwnProperty(property)) {
                values.push(object[property]);
            }
        }

        return values;
    },

    
    getKeys: (typeof Object.keys == 'function')
        ? function(object){
            if (!object) {
                return [];
            }
            return Object.keys(object);
        }
        : function(object) {
            var keys = [],
                property;

            for (property in object) {
                if (object.hasOwnProperty(property)) {
                    keys.push(property);
                }
            }

            return keys;
        },

    
    getSize: function(object) {
        var size = 0,
            property;

        for (property in object) {
            if (object.hasOwnProperty(property)) {
                size++;
            }
        }

        return size;
    },

    
    classify: function(object) {
        var prototype = object,
            objectProperties = [],
            propertyClassesMap = {},
            objectClass = function() {
                var i = 0,
                    ln = objectProperties.length,
                    property;

                for (; i < ln; i++) {
                    property = objectProperties[i];
                    this[property] = new propertyClassesMap[property]();
                }
            },
            key, value;

        for (key in object) {
            if (object.hasOwnProperty(key)) {
                value = object[key];

                if (value && value.constructor === Object) {
                    objectProperties.push(key);
                    propertyClassesMap[key] = ExtObject.classify(value);
                }
            }
        }

        objectClass.prototype = prototype;

        return objectClass;
    }
};


Ext.merge = Ext.Object.merge;


Ext.mergeIf = Ext.Object.mergeIf;


Ext.urlEncode = function() {
    var args = Ext.Array.from(arguments),
        prefix = '';

    
    if ((typeof args[1] === 'string')) {
        prefix = args[1] + '&';
        args[1] = false;
    }

    return prefix + ExtObject.toQueryString.apply(ExtObject, args);
};


Ext.urlDecode = function() {
    return ExtObject.fromQueryString.apply(ExtObject, arguments);
};

}());





(function() {




function xf(format) {
    var args = Array.prototype.slice.call(arguments, 1);
    return format.replace(/\{(\d+)\}/g, function(m, i) {
        return args[i];
    });
}

Ext.Date = {
    
    now: Date.now || function() {
        return +new Date();
    },

    
    toString: function(date) {
        var pad = Ext.String.leftPad;

        return date.getFullYear() + "-"
            + pad(date.getMonth() + 1, 2, '0') + "-"
            + pad(date.getDate(), 2, '0') + "T"
            + pad(date.getHours(), 2, '0') + ":"
            + pad(date.getMinutes(), 2, '0') + ":"
            + pad(date.getSeconds(), 2, '0');
    },

    
    getElapsed: function(dateA, dateB) {
        return Math.abs(dateA - (dateB || new Date()));
    },

    
    useStrict: false,

    
    formatCodeToRegex: function(character, currentGroup) {
        
        var p = utilDate.parseCodes[character];

        if (p) {
          p = typeof p == 'function'? p() : p;
          utilDate.parseCodes[character] = p; 
        }

        return p ? Ext.applyIf({
          c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
        }, p) : {
            g: 0,
            c: null,
            s: Ext.String.escapeRegex(character) 
        };
    },

    
    parseFunctions: {
        "MS": function(input, strict) {
            
            
            var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/'),
                r = (input || '').match(re);
            return r? new Date(((r[1] || '') + r[2]) * 1) : null;
        }
    },
    parseRegexes: [],

    
    formatFunctions: {
        "MS": function() {
            
            return '\\/Date(' + this.getTime() + ')\\/';
        }
    },

    y2kYear : 50,

    
    MILLI : "ms",

    
    SECOND : "s",

    
    MINUTE : "mi",

    
    HOUR : "h",

    
    DAY : "d",

    
    MONTH : "mo",

    
    YEAR : "y",

    
    defaults: {},

    
    
    dayNames : [
        "Sunday",
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday",
        "Saturday"
    ],
    

    
    
    monthNames : [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
        "October",
        "November",
        "December"
    ],
    

    
    
    monthNumbers : {
        January: 0,
        Jan: 0,
        February: 1,
        Feb: 1,
        March: 2,
        Mar: 2,
        April: 3,
        Apr: 3,
        May: 4,
        June: 5,
        Jun: 5,
        July: 6,
        Jul: 6,
        August: 7,
        Aug: 7,
        September: 8,
        Sep: 8,
        October: 9,
        Oct: 9,
        November: 10,
        Nov: 10,
        December: 11,
        Dec: 11
    },
    
    
    
    
    defaultFormat : "m/d/Y",
    
    
    
    getShortMonthName : function(month) {
        return Ext.Date.monthNames[month].substring(0, 3);
    },
    

    
    
    getShortDayName : function(day) {
        return Ext.Date.dayNames[day].substring(0, 3);
    },
    

    
    
    getMonthNumber : function(name) {
        
        return Ext.Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
    },
    

    
    formatContainsHourInfo : (function(){
        var stripEscapeRe = /(\\.)/g,
            hourInfoRe = /([gGhHisucUOPZ]|MS)/;
        return function(format){
            return hourInfoRe.test(format.replace(stripEscapeRe, ''));
        };
    }()),

    
    formatContainsDateInfo : (function(){
        var stripEscapeRe = /(\\.)/g,
            dateInfoRe = /([djzmnYycU]|MS)/;

        return function(format){
            return dateInfoRe.test(format.replace(stripEscapeRe, ''));
        };
    }()),
    
    
    unescapeFormat: (function() { 
        var slashRe = /\\/gi;
        return function(format) {
            
            
            
            return format.replace(slashRe, '');
        }
    }()),

    
    formatCodes : {
        d: "Ext.String.leftPad(this.getDate(), 2, '0')",
        D: "Ext.Date.getShortDayName(this.getDay())", 
        j: "this.getDate()",
        l: "Ext.Date.dayNames[this.getDay()]",
        N: "(this.getDay() ? this.getDay() : 7)",
        S: "Ext.Date.getSuffix(this)",
        w: "this.getDay()",
        z: "Ext.Date.getDayOfYear(this)",
        W: "Ext.String.leftPad(Ext.Date.getWeekOfYear(this), 2, '0')",
        F: "Ext.Date.monthNames[this.getMonth()]",
        m: "Ext.String.leftPad(this.getMonth() + 1, 2, '0')",
        M: "Ext.Date.getShortMonthName(this.getMonth())", 
        n: "(this.getMonth() + 1)",
        t: "Ext.Date.getDaysInMonth(this)",
        L: "(Ext.Date.isLeapYear(this) ? 1 : 0)",
        o: "(this.getFullYear() + (Ext.Date.getWeekOfYear(this) == 1 && this.getMonth() > 0 ? +1 : (Ext.Date.getWeekOfYear(this) >= 52 && this.getMonth() < 11 ? -1 : 0)))",
        Y: "Ext.String.leftPad(this.getFullYear(), 4, '0')",
        y: "('' + this.getFullYear()).substring(2, 4)",
        a: "(this.getHours() < 12 ? 'am' : 'pm')",
        A: "(this.getHours() < 12 ? 'AM' : 'PM')",
        g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
        G: "this.getHours()",
        h: "Ext.String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
        H: "Ext.String.leftPad(this.getHours(), 2, '0')",
        i: "Ext.String.leftPad(this.getMinutes(), 2, '0')",
        s: "Ext.String.leftPad(this.getSeconds(), 2, '0')",
        u: "Ext.String.leftPad(this.getMilliseconds(), 3, '0')",
        O: "Ext.Date.getGMTOffset(this)",
        P: "Ext.Date.getGMTOffset(this, true)",
        T: "Ext.Date.getTimezone(this)",
        Z: "(this.getTimezoneOffset() * -60)",

        c: function() { 
            var c, code, i, l, e;
            for (c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
                e = c.charAt(i);
                code.push(e == "T" ? "'T'" : utilDate.getFormatCode(e)); 
            }
            return code.join(" + ");
        },
        

        U: "Math.round(this.getTime() / 1000)"
    },

    
    isValid : function(y, m, d, h, i, s, ms) {
        
        h = h || 0;
        i = i || 0;
        s = s || 0;
        ms = ms || 0;

        
        var dt = utilDate.add(new Date(y < 100 ? 100 : y, m - 1, d, h, i, s, ms), utilDate.YEAR, y < 100 ? y - 100 : 0);

        return y == dt.getFullYear() &&
            m == dt.getMonth() + 1 &&
            d == dt.getDate() &&
            h == dt.getHours() &&
            i == dt.getMinutes() &&
            s == dt.getSeconds() &&
            ms == dt.getMilliseconds();
    },

    
    parse : function(input, format, strict) {
        var p = utilDate.parseFunctions;
        if (p[format] == null) {
            utilDate.createParser(format);
        }
        return p[format](input, Ext.isDefined(strict) ? strict : utilDate.useStrict);
    },

    
    parseDate: function(input, format, strict){
        return utilDate.parse(input, format, strict);
    },


    
    getFormatCode : function(character) {
        var f = utilDate.formatCodes[character];

        if (f) {
          f = typeof f == 'function'? f() : f;
          utilDate.formatCodes[character] = f; 
        }

        
        return f || ("'" + Ext.String.escape(character) + "'");
    },

    
    createFormat : function(format) {
        var code = [],
            special = false,
            ch = '',
            i;

        for (i = 0; i < format.length; ++i) {
            ch = format.charAt(i);
            if (!special && ch == "\\") {
                special = true;
            } else if (special) {
                special = false;
                code.push("'" + Ext.String.escape(ch) + "'");
            } else {
                code.push(utilDate.getFormatCode(ch));
            }
        }
        utilDate.formatFunctions[format] = Ext.functionFactory("return " + code.join('+'));
    },

    
    createParser : (function() {
        var code = [
            "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
                "def = Ext.Date.defaults,",
                "results = String(input).match(Ext.Date.parseRegexes[{0}]);", 

            "if(results){",
                "{1}",

                "if(u != null){", 
                    "v = new Date(u * 1000);", 
                "}else{",
                    
                    
                    
                    "dt = Ext.Date.clearTime(new Date);",

                    
                    "y = Ext.Number.from(y, Ext.Number.from(def.y, dt.getFullYear()));",
                    "m = Ext.Number.from(m, Ext.Number.from(def.m - 1, dt.getMonth()));",
                    "d = Ext.Number.from(d, Ext.Number.from(def.d, dt.getDate()));",

                    
                    "h  = Ext.Number.from(h, Ext.Number.from(def.h, dt.getHours()));",
                    "i  = Ext.Number.from(i, Ext.Number.from(def.i, dt.getMinutes()));",
                    "s  = Ext.Number.from(s, Ext.Number.from(def.s, dt.getSeconds()));",
                    "ms = Ext.Number.from(ms, Ext.Number.from(def.ms, dt.getMilliseconds()));",

                    "if(z >= 0 && y >= 0){",
                        
                        

                        
                        
                        "v = Ext.Date.add(new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",

                        
                        "v = !strict? v : (strict === true && (z <= 364 || (Ext.Date.isLeapYear(v) && z <= 365))? Ext.Date.add(v, Ext.Date.DAY, z) : null);",
                    "}else if(strict === true && !Ext.Date.isValid(y, m + 1, d, h, i, s, ms)){", 
                        "v = null;", 
                    "}else{",
                        
                        
                        "v = Ext.Date.add(new Date(y < 100 ? 100 : y, m, d, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
                    "}",
                "}",
            "}",

            "if(v){",
                
                "if(zz != null){",
                    
                    "v = Ext.Date.add(v, Ext.Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
                "}else if(o){",
                    
                    "v = Ext.Date.add(v, Ext.Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
                "}",
            "}",

            "return v;"
        ].join('\n');

        return function(format) {
            var regexNum = utilDate.parseRegexes.length,
                currentGroup = 1,
                calc = [],
                regex = [],
                special = false,
                ch = "",
                i = 0,
                len = format.length,
                atEnd = [],
                obj;

            for (; i < len; ++i) {
                ch = format.charAt(i);
                if (!special && ch == "\\") {
                    special = true;
                } else if (special) {
                    special = false;
                    regex.push(Ext.String.escape(ch));
                } else {
                    obj = utilDate.formatCodeToRegex(ch, currentGroup);
                    currentGroup += obj.g;
                    regex.push(obj.s);
                    if (obj.g && obj.c) {
                        if (obj.calcAtEnd) {
                            atEnd.push(obj.c);
                        } else {
                            calc.push(obj.c);
                        }
                    }
                }
            }
            
            calc = calc.concat(atEnd);

            utilDate.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i');
            utilDate.parseFunctions[format] = Ext.functionFactory("input", "strict", xf(code, regexNum, calc.join('')));
        };
    }()),

    
    parseCodes : {
        
        d: {
            g:1,
            c:"d = parseInt(results[{0}], 10);\n",
            s:"(3[0-1]|[1-2][0-9]|0[1-9])" 
        },
        j: {
            g:1,
            c:"d = parseInt(results[{0}], 10);\n",
            s:"(3[0-1]|[1-2][0-9]|[1-9])" 
        },
        D: function() {
            for (var a = [], i = 0; i < 7; a.push(utilDate.getShortDayName(i)), ++i); 
            return {
                g:0,
                c:null,
                s:"(?:" + a.join("|") +")"
            };
        },
        l: function() {
            return {
                g:0,
                c:null,
                s:"(?:" + utilDate.dayNames.join("|") + ")"
            };
        },
        N: {
            g:0,
            c:null,
            s:"[1-7]" 
        },
        
        S: {
            g:0,
            c:null,
            s:"(?:st|nd|rd|th)"
        },
        
        w: {
            g:0,
            c:null,
            s:"[0-6]" 
        },
        z: {
            g:1,
            c:"z = parseInt(results[{0}], 10);\n",
            s:"(\\d{1,3})" 
        },
        W: {
            g:0,
            c:null,
            s:"(?:\\d{2})" 
        },
        F: function() {
            return {
                g:1,
                c:"m = parseInt(Ext.Date.getMonthNumber(results[{0}]), 10);\n", 
                s:"(" + utilDate.monthNames.join("|") + ")"
            };
        },
        M: function() {
            for (var a = [], i = 0; i < 12; a.push(utilDate.getShortMonthName(i)), ++i); 
            return Ext.applyIf({
                s:"(" + a.join("|") + ")"
            }, utilDate.formatCodeToRegex("F"));
        },
        m: {
            g:1,
            c:"m = parseInt(results[{0}], 10) - 1;\n",
            s:"(1[0-2]|0[1-9])" 
        },
        n: {
            g:1,
            c:"m = parseInt(results[{0}], 10) - 1;\n",
            s:"(1[0-2]|[1-9])" 
        },
        t: {
            g:0,
            c:null,
            s:"(?:\\d{2})" 
        },
        L: {
            g:0,
            c:null,
            s:"(?:1|0)"
        },
        o: function() {
            return utilDate.formatCodeToRegex("Y");
        },
        Y: {
            g:1,
            c:"y = parseInt(results[{0}], 10);\n",
            s:"(\\d{4})" 
        },
        y: {
            g:1,
            c:"var ty = parseInt(results[{0}], 10);\n"
                + "y = ty > Ext.Date.y2kYear ? 1900 + ty : 2000 + ty;\n", 
            s:"(\\d{1,2})"
        },
        
        
        a: {
            g:1,
            c:"if (/(am)/i.test(results[{0}])) {\n"
                + "if (!h || h == 12) { h = 0; }\n"
                + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
            s:"(am|pm|AM|PM)",
            calcAtEnd: true
        },
        
        
        A: {
            g:1,
            c:"if (/(am)/i.test(results[{0}])) {\n"
                + "if (!h || h == 12) { h = 0; }\n"
                + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
            s:"(AM|PM|am|pm)",
            calcAtEnd: true
        },
        
        g: {
            g:1,
            c:"h = parseInt(results[{0}], 10);\n",
            s:"(1[0-2]|[0-9])" 
        },
        G: {
            g:1,
            c:"h = parseInt(results[{0}], 10);\n",
            s:"(2[0-3]|1[0-9]|[0-9])" 
        },
        h: {
            g:1,
            c:"h = parseInt(results[{0}], 10);\n",
            s:"(1[0-2]|0[1-9])" 
        },
        H: {
            g:1,
            c:"h = parseInt(results[{0}], 10);\n",
            s:"(2[0-3]|[0-1][0-9])" 
        },
        i: {
            g:1,
            c:"i = parseInt(results[{0}], 10);\n",
            s:"([0-5][0-9])" 
        },
        s: {
            g:1,
            c:"s = parseInt(results[{0}], 10);\n",
            s:"([0-5][0-9])" 
        },
        u: {
            g:1,
            c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
            s:"(\\d+)" 
        },
        O: {
            g:1,
            c:[
                "o = results[{0}];",
                "var sn = o.substring(0,1),", 
                    "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", 
                    "mn = o.substring(3,5) % 60;", 
                "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" 
            ].join("\n"),
            s: "([+-]\\d{4})" 
        },
        P: {
            g:1,
            c:[
                "o = results[{0}];",
                "var sn = o.substring(0,1),", 
                    "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", 
                    "mn = o.substring(4,6) % 60;", 
                "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" 
            ].join("\n"),
            s: "([+-]\\d{2}:\\d{2})" 
        },
        T: {
            g:0,
            c:null,
            s:"[A-Z]{1,4}" 
        },
        Z: {
            g:1,
            c:"zz = results[{0}] * 1;\n" 
                  + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
            s:"([+-]?\\d{1,5})" 
        },
        c: function() {
            var calc = [],
                arr = [
                    utilDate.formatCodeToRegex("Y", 1), 
                    utilDate.formatCodeToRegex("m", 2), 
                    utilDate.formatCodeToRegex("d", 3), 
                    utilDate.formatCodeToRegex("H", 4), 
                    utilDate.formatCodeToRegex("i", 5), 
                    utilDate.formatCodeToRegex("s", 6), 
                    {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"}, 
                    {c:[ 
                        "if(results[8]) {", 
                            "if(results[8] == 'Z'){",
                                "zz = 0;", 
                            "}else if (results[8].indexOf(':') > -1){",
                                utilDate.formatCodeToRegex("P", 8).c, 
                            "}else{",
                                utilDate.formatCodeToRegex("O", 8).c, 
                            "}",
                        "}"
                    ].join('\n')}
                ],
                i,
                l;

            for (i = 0, l = arr.length; i < l; ++i) {
                calc.push(arr[i].c);
            }

            return {
                g:1,
                c:calc.join(""),
                s:[
                    arr[0].s, 
                    "(?:", "-", arr[1].s, 
                        "(?:", "-", arr[2].s, 
                            "(?:",
                                "(?:T| )?", 
                                arr[3].s, ":", arr[4].s,  
                                "(?::", arr[5].s, ")?", 
                                "(?:(?:\\.|,)(\\d+))?", 
                                "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", 
                            ")?",
                        ")?",
                    ")?"
                ].join("")
            };
        },
        U: {
            g:1,
            c:"u = parseInt(results[{0}], 10);\n",
            s:"(-?\\d+)" 
        }
    },

    
    
    dateFormat: function(date, format) {
        return utilDate.format(date, format);
    },

    
    isEqual: function(date1, date2) {
        
        if (date1 && date2) {
            return (date1.getTime() === date2.getTime());
        }
        
        return !(date1 || date2);
    },

    
    format: function(date, format) {
        var formatFunctions = utilDate.formatFunctions;

        if (!Ext.isDate(date)) {
            return '';
        }

        if (formatFunctions[format] == null) {
            utilDate.createFormat(format);
        }

        return formatFunctions[format].call(date) + '';
    },

    
    getTimezone : function(date) {
        
        
        
        
        
        
        
        
        
        
        
        
        return date.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
    },

    
    getGMTOffset : function(date, colon) {
        var offset = date.getTimezoneOffset();
        return (offset > 0 ? "-" : "+")
            + Ext.String.leftPad(Math.floor(Math.abs(offset) / 60), 2, "0")
            + (colon ? ":" : "")
            + Ext.String.leftPad(Math.abs(offset % 60), 2, "0");
    },

    
    getDayOfYear: function(date) {
        var num = 0,
            d = Ext.Date.clone(date),
            m = date.getMonth(),
            i;

        for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
            num += utilDate.getDaysInMonth(d);
        }
        return num + date.getDate() - 1;
    },

    
    getWeekOfYear : (function() {
        
        var ms1d = 864e5, 
            ms7d = 7 * ms1d; 

        return function(date) { 
            var DC3 = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 3) / ms1d, 
                AWN = Math.floor(DC3 / 7), 
                Wyr = new Date(AWN * ms7d).getUTCFullYear();

            return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
        };
    }()),

    
    isLeapYear : function(date) {
        var year = date.getFullYear();
        return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
    },

    
    getFirstDayOfMonth : function(date) {
        var day = (date.getDay() - (date.getDate() - 1)) % 7;
        return (day < 0) ? (day + 7) : day;
    },

    
    getLastDayOfMonth : function(date) {
        return utilDate.getLastDateOfMonth(date).getDay();
    },


    
    getFirstDateOfMonth : function(date) {
        return new Date(date.getFullYear(), date.getMonth(), 1);
    },

    
    getLastDateOfMonth : function(date) {
        return new Date(date.getFullYear(), date.getMonth(), utilDate.getDaysInMonth(date));
    },

    
    getDaysInMonth: (function() {
        var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

        return function(date) { 
            var m = date.getMonth();

            return m == 1 && utilDate.isLeapYear(date) ? 29 : daysInMonth[m];
        };
    }()),

    
    
    getSuffix : function(date) {
        switch (date.getDate()) {
            case 1:
            case 21:
            case 31:
                return "st";
            case 2:
            case 22:
                return "nd";
            case 3:
            case 23:
                return "rd";
            default:
                return "th";
        }
    },
    

    
    clone : function(date) {
        return new Date(date.getTime());
    },

    
    isDST : function(date) {
        
        
        return new Date(date.getFullYear(), 0, 1).getTimezoneOffset() != date.getTimezoneOffset();
    },

    
    clearTime : function(date, clone) {
        if (clone) {
            return Ext.Date.clearTime(Ext.Date.clone(date));
        }

        
        var d = date.getDate(),
            hr,
            c;

        
        date.setHours(0);
        date.setMinutes(0);
        date.setSeconds(0);
        date.setMilliseconds(0);

        if (date.getDate() != d) { 
            
            

            
            for (hr = 1, c = utilDate.add(date, Ext.Date.HOUR, hr); c.getDate() != d; hr++, c = utilDate.add(date, Ext.Date.HOUR, hr));

            date.setDate(d);
            date.setHours(c.getHours());
        }

        return date;
    },

    
    add : function(date, interval, value) {
        var d = Ext.Date.clone(date),
            Date = Ext.Date,
            day;
        if (!interval || value === 0) {
            return d;
        }

        switch(interval.toLowerCase()) {
            case Ext.Date.MILLI:
                d.setMilliseconds(d.getMilliseconds() + value);
                break;
            case Ext.Date.SECOND:
                d.setSeconds(d.getSeconds() + value);
                break;
            case Ext.Date.MINUTE:
                d.setMinutes(d.getMinutes() + value);
                break;
            case Ext.Date.HOUR:
                d.setHours(d.getHours() + value);
                break;
            case Ext.Date.DAY:
                d.setDate(d.getDate() + value);
                break;
            case Ext.Date.MONTH:
                day = date.getDate();
                if (day > 28) {
                    day = Math.min(day, Ext.Date.getLastDateOfMonth(Ext.Date.add(Ext.Date.getFirstDateOfMonth(date), Ext.Date.MONTH, value)).getDate());
                }
                d.setDate(day);
                d.setMonth(date.getMonth() + value);
                break;
            case Ext.Date.YEAR:
                day = date.getDate();
                if (day > 28) {
                    day = Math.min(day, Ext.Date.getLastDateOfMonth(Ext.Date.add(Ext.Date.getFirstDateOfMonth(date), Ext.Date.YEAR, value)).getDate());
                }
                d.setDate(day);
                d.setFullYear(date.getFullYear() + value);
                break;
        }
        return d;
    },

    
    between : function(date, start, end) {
        var t = date.getTime();
        return start.getTime() <= t && t <= end.getTime();
    },

    
    compat: function() {
        var nativeDate = window.Date,
            p, u,
            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'],
            proto = ['dateFormat', 'format', 'getTimezone', 'getGMTOffset', 'getDayOfYear', 'getWeekOfYear', 'isLeapYear', 'getFirstDayOfMonth', 'getLastDayOfMonth', 'getDaysInMonth', 'getSuffix', 'clone', 'isDST', 'clearTime', 'add', 'between'],
            sLen    = statics.length,
            pLen    = proto.length,
            stat, prot, s;

        
        for (s = 0; s < sLen; s++) {
            stat = statics[s];
            nativeDate[stat] = utilDate[stat];
        }

        
        for (p = 0; p < pLen; p++) {
            prot = proto[p];
            nativeDate.prototype[prot] = function() {
                var args = Array.prototype.slice.call(arguments);
                args.unshift(this);
                return utilDate[prot].apply(utilDate, args);
            };
        }
    }
};

var utilDate = Ext.Date;

}());


(function(flexSetter) {

var noArgs = [],
    Base = function(){};

    
    Ext.apply(Base, {
        $className: 'Ext.Base',

        $isClass: true,

        
        create: function() {
            return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
        },

        
        extend: function(parent) {
            var parentPrototype = parent.prototype,
                basePrototype, prototype, i, ln, name, statics;

            prototype = this.prototype = Ext.Object.chain(parentPrototype);
            prototype.self = this;

            this.superclass = prototype.superclass = parentPrototype;

            if (!parent.$isClass) {
                basePrototype = Ext.Base.prototype;

                for (i in basePrototype) {
                    if (i in prototype) {
                        prototype[i] = basePrototype[i];
                    }
                }
            }

            
            statics = parentPrototype.$inheritableStatics;

            if (statics) {
                for (i = 0,ln = statics.length; i < ln; i++) {
                    name = statics[i];

                    if (!this.hasOwnProperty(name)) {
                        this[name] = parent[name];
                    }
                }
            }

            if (parent.$onExtended) {
                this.$onExtended = parent.$onExtended.slice();
            }

            prototype.config = new prototype.configClass();
            prototype.initConfigList = prototype.initConfigList.slice();
            prototype.initConfigMap = Ext.clone(prototype.initConfigMap);
            prototype.configMap = Ext.Object.chain(prototype.configMap);
        },

        
        $onExtended: [],

        
        triggerExtended: function() {
            var callbacks = this.$onExtended,
                ln = callbacks.length,
                i, callback;

            if (ln > 0) {
                for (i = 0; i < ln; i++) {
                    callback = callbacks[i];
                    callback.fn.apply(callback.scope || this, arguments);
                }
            }
        },

        
        onExtended: function(fn, scope) {
            this.$onExtended.push({
                fn: fn,
                scope: scope
            });

            return this;
        },

        
        addConfig: function(config, fullMerge) {
            var prototype = this.prototype,
                configNameCache = Ext.Class.configNameCache,
                hasConfig = prototype.configMap,
                initConfigList = prototype.initConfigList,
                initConfigMap = prototype.initConfigMap,
                defaultConfig = prototype.config,
                initializedName, name, value;

            for (name in config) {
                if (config.hasOwnProperty(name)) {
                    if (!hasConfig[name]) {
                        hasConfig[name] = true;
                    }

                    value = config[name];

                    initializedName = configNameCache[name].initialized;

                    if (!initConfigMap[name] && value !== null && !prototype[initializedName]) {
                        initConfigMap[name] = true;
                        initConfigList.push(name);
                    }
                }
            }

            if (fullMerge) {
                Ext.merge(defaultConfig, config);
            }
            else {
                Ext.mergeIf(defaultConfig, config);
            }

            prototype.configClass = Ext.Object.classify(defaultConfig);
        },

        
        addStatics: function(members) {
            var member, name;

            for (name in members) {
                if (members.hasOwnProperty(name)) {
                    member = members[name];
                    this[name] = member;
                }
            }

            return this;
        },

        
        addInheritableStatics: function(members) {
            var inheritableStatics,
                hasInheritableStatics,
                prototype = this.prototype,
                name, member;

            inheritableStatics = prototype.$inheritableStatics;
            hasInheritableStatics = prototype.$hasInheritableStatics;

            if (!inheritableStatics) {
                inheritableStatics = prototype.$inheritableStatics = [];
                hasInheritableStatics = prototype.$hasInheritableStatics = {};
            }

            for (name in members) {
                if (members.hasOwnProperty(name)) {
                    member = members[name];
                    this[name] = member;

                    if (!hasInheritableStatics[name]) {
                        hasInheritableStatics[name] = true;
                        inheritableStatics.push(name);
                    }
                }
            }

            return this;
        },

        
        addMembers: function(members) {
            var prototype = this.prototype,
                enumerables = Ext.enumerables,
                names = [],
                i, ln, name, member;

            for (name in members) {
                names.push(name);
            }

            if (enumerables) {
                names.push.apply(names, enumerables);
            }

            for (i = 0,ln = names.length; i < ln; i++) {
                name = names[i];

                if (members.hasOwnProperty(name)) {
                    member = members[name];

                    if (typeof member == 'function' && !member.$isClass && member !== Ext.emptyFn) {
                        member.$owner = this;
                        member.$name = name;
                    }

                    prototype[name] = member;
                }
            }

            return this;
        },

        
        addMember: function(name, member) {
            if (typeof member == 'function' && !member.$isClass && member !== Ext.emptyFn) {
                member.$owner = this;
                member.$name = name;
            }

            this.prototype[name] = member;

            return this;
        },

        
        implement: function() {
            this.addMembers.apply(this, arguments);
        },

        
        borrow: function(fromClass, members) {
            var prototype = this.prototype,
                fromPrototype = fromClass.prototype,
                i, ln, name, fn, toBorrow;

            members = Ext.Array.from(members);

            for (i = 0,ln = members.length; i < ln; i++) {
                name = members[i];

                toBorrow = fromPrototype[name];

                if (typeof toBorrow == 'function') {
                    fn = Ext.Function.clone(toBorrow);


                    fn.$owner = this;
                    fn.$name = name;

                    prototype[name] = fn;
                }
                else {
                    prototype[name] = toBorrow;
                }
            }

            return this;
        },

        
        override: function(members) {
            var me = this,
                enumerables = Ext.enumerables,
                target = me.prototype,
                cloneFunction = Ext.Function.clone,
                name, index, member, statics, names, previous;

            if (arguments.length === 2) {
                name = members;
                members = {};
                members[name] = arguments[1];
                enumerables = null;
            }

            do {
                names = []; 
                statics = null; 

                for (name in members) { 
                    if (name == 'statics') {
                        statics = members[name];
                    } else if (name == 'config') {
                        me.addConfig(members[name], true);
                    } else {
                        names.push(name);
                    }
                }

                if (enumerables) {
                    names.push.apply(names, enumerables);
                }

                for (index = names.length; index--; ) {
                    name = names[index];

                    if (members.hasOwnProperty(name)) {
                        member = members[name];

                        if (typeof member == 'function' && !member.$className && member !== Ext.emptyFn) {
                            if (typeof member.$owner != 'undefined') {
                                member = cloneFunction(member);
                            }


                            member.$owner = me;
                            member.$name = name;

                            previous = target[name];
                            if (previous) {
                                member.$previous = previous;
                            }
                        }

                        target[name] = member;
                    }
                }

                target = me; 
                members = statics; 
            } while (members);

            return this;
        },

        
        callParent: function(args) {
            var method;

            
            return (method = this.callParent.caller) && (method.$previous ||
                  ((method = method.$owner ? method : method.caller) &&
                        method.$owner.superclass.$class[method.$name])).apply(this, args || noArgs);
        },

        
        mixin: function(name, mixinClass) {
            var mixin = mixinClass.prototype,
                prototype = this.prototype,
                key;

            if (typeof mixin.onClassMixedIn != 'undefined') {
                mixin.onClassMixedIn.call(mixinClass, this);
            }

            if (!prototype.hasOwnProperty('mixins')) {
                if ('mixins' in prototype) {
                    prototype.mixins = Ext.Object.chain(prototype.mixins);
                }
                else {
                    prototype.mixins = {};
                }
            }

            for (key in mixin) {
                if (key === 'mixins') {
                    Ext.merge(prototype.mixins, mixin[key]);
                }
                else if (typeof prototype[key] == 'undefined' && key != 'mixinId' && key != 'config') {
                    prototype[key] = mixin[key];
                }
            }

            if ('config' in mixin) {
                this.addConfig(mixin.config, false);
            }

            prototype.mixins[name] = mixin;
        },

        
        getName: function() {
            return Ext.getClassName(this);
        },

        
        createAlias: flexSetter(function(alias, origin) {
            this.override(alias, function() {
                return this[origin].apply(this, arguments);
            });
        }),

        
        addXtype: function(xtype) {
            var prototype = this.prototype,
                xtypesMap = prototype.xtypesMap,
                xtypes = prototype.xtypes,
                xtypesChain = prototype.xtypesChain;

            if (!prototype.hasOwnProperty('xtypesMap')) {
                xtypesMap = prototype.xtypesMap = Ext.merge({}, prototype.xtypesMap || {});
                xtypes = prototype.xtypes = prototype.xtypes ? [].concat(prototype.xtypes) : [];
                xtypesChain = prototype.xtypesChain = prototype.xtypesChain ? [].concat(prototype.xtypesChain) : [];
                prototype.xtype = xtype;
            }

            if (!xtypesMap[xtype]) {
                xtypesMap[xtype] = true;
                xtypes.push(xtype);
                xtypesChain.push(xtype);
                Ext.ClassManager.setAlias(this, 'widget.' + xtype);
            }

            return this;
        }
    });

    Base.implement({
        
        isInstance: true,

        
        $className: 'Ext.Base',

        
        configClass: Ext.emptyFn,

        
        initConfigList: [],

        
        configMap: {},

        
        initConfigMap: {},

        
        statics: function() {
            var method = this.statics.caller,
                self = this.self;

            if (!method) {
                return self;
            }

            return method.$owner;
        },

        
        callParent: function(args) {
            
            
            
            
            var method,
                superMethod = (method = this.callParent.caller) && (method.$previous ||
                        ((method = method.$owner ? method : method.caller) &&
                                method.$owner.superclass[method.$name]));


            return superMethod.apply(this, args || noArgs);
        },

        
        self: Base,

        
        constructor: function() {
            return this;
        },

        
        initConfig: function(config) {
            var instanceConfig = config,
                configNameCache = Ext.Class.configNameCache,
                defaultConfig = new this.configClass(),
                defaultConfigList = this.initConfigList,
                hasConfig = this.configMap,
                nameMap, i, ln, name, initializedName;

            this.initConfig = Ext.emptyFn;

            this.initialConfig = instanceConfig || {};

            this.config = config = (instanceConfig) ? Ext.merge(defaultConfig, config) : defaultConfig;

            if (instanceConfig) {
                defaultConfigList = defaultConfigList.slice();

                for (name in instanceConfig) {
                    if (hasConfig[name]) {
                        if (instanceConfig[name] !== null) {
                            defaultConfigList.push(name);
                            this[configNameCache[name].initialized] = false;
                        }
                    }
                }
            }

            for (i = 0,ln = defaultConfigList.length; i < ln; i++) {
                name = defaultConfigList[i];
                nameMap = configNameCache[name];
                initializedName = nameMap.initialized;

                if (!this[initializedName]) {
                    this[initializedName] = true;
                    this[nameMap.set].call(this, config[name]);
                }
            }

            return this;
        },

        
        hasConfig: function(name) {
            return Boolean(this.configMap[name]);
        },

        
        setConfig: function(config, applyIfNotSet) {
            if (!config) {
                return this;
            }

            var configNameCache = Ext.Class.configNameCache,
                currentConfig = this.config,
                hasConfig = this.configMap,
                initialConfig = this.initialConfig,
                name, value;

            applyIfNotSet = Boolean(applyIfNotSet);

            for (name in config) {
                if (applyIfNotSet && initialConfig.hasOwnProperty(name)) {
                    continue;
                }

                value = config[name];
                currentConfig[name] = value;

                if (hasConfig[name]) {
                    this[configNameCache[name].set](value);
                }
            }

            return this;
        },

        
        getConfig: function(name) {
            var configNameCache = Ext.Class.configNameCache;

            return this[configNameCache[name].get]();
        },

        
        getInitialConfig: function(name) {
            var config = this.config;

            if (!name) {
                return config;
            }
            else {
                return config[name];
            }
        },

        
        onConfigUpdate: function(names, callback, scope) {
            var self = this.self,
                i, ln, name,
                updaterName, updater, newUpdater;

            names = Ext.Array.from(names);

            scope = scope || this;

            for (i = 0,ln = names.length; i < ln; i++) {
                name = names[i];
                updaterName = 'update' + Ext.String.capitalize(name);
                updater = this[updaterName] || Ext.emptyFn;
                newUpdater = function() {
                    updater.apply(this, arguments);
                    scope[callback].apply(scope, arguments);
                };
                newUpdater.$name = updaterName;
                newUpdater.$owner = self;

                this[updaterName] = newUpdater;
            }
        },

        
        destroy: function() {
            this.destroy = Ext.emptyFn;
        }
    });

    
    Base.prototype.callOverridden = Base.prototype.callParent;

    Ext.Base = Base;

}(Ext.Function.flexSetter));


(function() {
    var ExtClass,
        Base = Ext.Base,
        baseStaticMembers = [],
        baseStaticMember, baseStaticMemberLength;

    for (baseStaticMember in Base) {
        if (Base.hasOwnProperty(baseStaticMember)) {
            baseStaticMembers.push(baseStaticMember);
        }
    }

    baseStaticMemberLength = baseStaticMembers.length;

    
    function makeCtor (className) {
        function constructor () {
            
            
            return this.constructor.apply(this, arguments) || null;
        }
        return constructor;
    }

    
    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, {
        
        onBeforeCreated: function(Class, data, hooks) {
            Class.addMembers(data);

            hooks.onCreated.call(Class, Class);
        },

        
        create: function(Class, data) {
            var name, i;

            if (!Class) {
                Class = makeCtor(
                );
            }

            for (i = 0; i < baseStaticMemberLength; i++) {
                name = baseStaticMembers[i];
                Class[name] = Base[name];
            }

            return Class;
        },

        
        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, process;

            delete data.preprocessors;

            for (i = 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 (j = 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,
                preprocessor = hooks.preprocessors.shift();

            if (!preprocessor) {
                hooks.onBeforeCreated.apply(me, arguments);
                return;
            }

            if (preprocessor.call(me, Class, data, hooks, me.doProcess) !== false) {
                me.doProcess(Class, data, hooks);
            }
        },

        
        preprocessors: {},

        
        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;
        },

        
        getPreprocessor: function(name) {
            return this.preprocessors[name];
        },

        
        getPreprocessors: function() {
            return this.preprocessors;
        },

        
        defaultPreprocessors: [],

        
        getDefaultPreprocessors: function() {
            return this.defaultPreprocessors;
        },

        
        setDefaultPreprocessors: function(preprocessors) {
            this.defaultPreprocessors = Ext.Array.from(preprocessors);

            return this;
        },

        
        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;
        },

        configNameCache: {},

        getConfigNameMap: function(name) {
            var cache = this.configNameCache,
                map = cache[name],
                capitalizedName;

            if (!map) {
                capitalizedName = name.charAt(0).toUpperCase() + name.substr(1);

                map = cache[name] = {
                    internal: name,
                    initialized: '_is' + capitalizedName + 'Initialized',
                    apply: 'apply' + capitalizedName,
                    update: 'update' + capitalizedName,
                    'set': 'set' + capitalizedName,
                    'get': 'get' + capitalizedName,
                    doSet : 'doSet' + capitalizedName,
                    changeEvent: name.toLowerCase() + 'change'
                };
            }

            return map;
        }
    });

    
    ExtClass.registerPreprocessor('extend', function(Class, data) {
        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 (i 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);

    
    ExtClass.registerPreprocessor('statics', function(Class, data) {
        Class.addStatics(data.statics);

        delete data.statics;
    });

    
    ExtClass.registerPreprocessor('inheritableStatics', function(Class, data) {
        Class.addInheritableStatics(data.inheritableStatics);

        delete data.inheritableStatics;
    });

    
    ExtClass.registerPreprocessor('config', function(Class, data) {
        var config = data.config,
            prototype = Class.prototype;

        delete data.config;

        Ext.Object.each(config, function(name, value) {
            var nameMap = ExtClass.getConfigNameMap(name),
                internalName = nameMap.internal,
                initializedName = nameMap.initialized,
                applyName = nameMap.apply,
                updateName = nameMap.update,
                setName = nameMap.set,
                getName = nameMap.get,
                hasOwnSetter = (setName in prototype) || data.hasOwnProperty(setName),
                hasOwnApplier = (applyName in prototype) || data.hasOwnProperty(applyName),
                hasOwnUpdater = (updateName in prototype) || data.hasOwnProperty(updateName),
                optimizedGetter, customGetter;

            if (value === null || (!hasOwnSetter && !hasOwnApplier && !hasOwnUpdater)) {
                prototype[internalName] = value;
                prototype[initializedName] = true;
            }
            else {
                prototype[initializedName] = false;
            }

            if (!hasOwnSetter) {
                data[setName] = function(value) {
                    var oldValue = this[internalName],
                        applier = this[applyName],
                        updater = this[updateName];

                    if (!this[initializedName]) {
                        this[initializedName] = true;
                    }

                    if (applier) {
                        value = applier.call(this, value, oldValue);
                    }

                    if (typeof value != 'undefined') {
                        this[internalName] = value;

                        if (updater && value !== oldValue) {
                            updater.call(this, value, oldValue);
                        }
                    }

                    return this;
                };
            }

            if (!(getName in prototype) || data.hasOwnProperty(getName)) {
                customGetter = data[getName] || false;

                if (customGetter) {
                    optimizedGetter = function() {
                        return customGetter.apply(this, arguments);
                    };
                }
                else {
                    optimizedGetter = function() {
                        return this[internalName];
                    };
                }

                data[getName] = function() {
                    var currentGetter;

                    if (!this[initializedName]) {
                        this[initializedName] = true;
                        this[setName](this.config[name]);
                    }

                    currentGetter = this[getName];

                    if ('$previous' in currentGetter) {
                        currentGetter.$previous = optimizedGetter;
                    }
                    else {
                        this[getName] = optimizedGetter;
                    }

                    return optimizedGetter.apply(this, arguments);
                };
            }
        });

        Class.addConfig(config, true);
    });

    
    ExtClass.registerPreprocessor('mixins', function(Class, data, hooks) {
        var mixins = data.mixins,
            name, mixin, i, ln;

        delete data.mixins;

        Ext.Function.interceptBefore(hooks, 'onCreated', function() {
            if (mixins instanceof Array) {
                for (i = 0,ln = mixins.length; i < ln; i++) {
                    mixin = mixins[i];
                    name = mixin.prototype.mixinId || mixin.$className;

                    Class.mixin(name, mixin);
                }
            }
            else {
                for (var mixinName in mixins) {
                    if (mixins.hasOwnProperty(mixinName)) {
                        Class.mixin(mixinName, mixins[mixinName]);
                    }
                }
            }
        });
    });

    
    Ext.extend = function(Class, Parent, members) {
        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'
            ,'statics'
            ,'inheritableStatics'
            ,'mixins'
            ,'config'
        ];

        if (Class) {
            cls = new ExtClass(Class, members);
            
            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;
    };

}());


(function(Class, alias, arraySlice, arrayFrom, global) {

    
    function makeCtor () {
        function constructor () {
            
            
            return this.constructor.apply(this, arguments) || null;
        }
        return constructor;
    }

    var Manager = Ext.ClassManager = {

        
        classes: {},

        
        existCache: {},

        
        namespaceRewrites: [{
            from: 'Ext.',
            to: Ext
        }],

        
        maps: {
            alternateToName: {},
            aliasToName: {},
            nameToAliases: {},
            nameToAlternates: {}
        },

        
        enableNamespaceParseCache: true,

        
        namespaceParseCache: {},

        
        instantiators: [],

        
        isCreated: function(className) {
            var existCache = this.existCache,
                i, ln, part, root, parts;


            if (this.classes[className] || existCache[className]) {
                return true;
            }

            root = global;
            parts = this.parseNamespace(className);

            for (i = 0, ln = parts.length; i < ln; i++) {
                part = parts[i];

                if (typeof part != 'string') {
                    root = part;
                } else {
                    if (!root || !root[part]) {
                        return false;
                    }

                    root = root[part];
                }
            }

            existCache[className] = true;

            this.triggerCreated(className);

            return true;
        },

        
        createdListeners: [],

        
        nameCreatedListeners: {},

        
        triggerCreated: function(className) {
            var listeners = this.createdListeners,
                nameListeners = this.nameCreatedListeners,
                alternateNames = this.maps.nameToAlternates[className],
                names = [className],
                i, ln, j, subLn, listener, name;

            for (i = 0,ln = listeners.length; i < ln; i++) {
                listener = listeners[i];
                listener.fn.call(listener.scope, className);
            }

            if (alternateNames) {
                names.push.apply(names, alternateNames);
            }

            for (i = 0,ln = names.length; i < ln; i++) {
                name = names[i];
                listeners = nameListeners[name];

                if (listeners) {
                    for (j = 0,subLn = listeners.length; j < subLn; j++) {
                        listener = listeners[j];
                        listener.fn.call(listener.scope, name);
                    }
                    delete nameListeners[name];
                }
            }
        },

        
        onCreated: function(fn, scope, className) {
            var listeners = this.createdListeners,
                nameListeners = this.nameCreatedListeners,
                listener = {
                    fn: fn,
                    scope: scope
                };

            if (className) {
                if (this.isCreated(className)) {
                    fn.call(scope, className);
                    return;
                }

                if (!nameListeners[className]) {
                    nameListeners[className] = [];
                }

                nameListeners[className].push(listener);
            }
            else {
                listeners.push(listener);
            }
        },

        
        parseNamespace: function(namespace) {

            var cache = this.namespaceParseCache,
                parts,
                rewrites,
                root,
                name,
                rewrite, from, to, i, ln;

            if (this.enableNamespaceParseCache) {
                if (cache.hasOwnProperty(namespace)) {
                    return cache[namespace];
                }
            }

            parts = [];
            rewrites = this.namespaceRewrites;
            root = global;
            name = namespace;

            for (i = 0, ln = rewrites.length; i < ln; i++) {
                rewrite = rewrites[i];
                from = rewrite.from;
                to = rewrite.to;

                if (name === from || name.substring(0, from.length) === from) {
                    name = name.substring(from.length);

                    if (typeof to != 'string') {
                        root = to;
                    } else {
                        parts = parts.concat(to.split('.'));
                    }

                    break;
                }
            }

            parts.push(root);

            parts = parts.concat(name.split('.'));

            if (this.enableNamespaceParseCache) {
                cache[namespace] = parts;
            }

            return parts;
        },

        
        setNamespace: function(name, value) {
            var root = global,
                parts = this.parseNamespace(name),
                ln = parts.length - 1,
                leaf = parts[ln],
                i, part;

            for (i = 0; i < ln; i++) {
                part = parts[i];

                if (typeof part != 'string') {
                    root = part;
                } else {
                    if (!root[part]) {
                        root[part] = {};
                    }

                    root = root[part];
                }
            }

            root[leaf] = value;

            return root[leaf];
        },

        
        createNamespaces: function() {
            var root = global,
                parts, part, i, j, ln, subLn;

            for (i = 0, ln = arguments.length; i < ln; i++) {
                parts = this.parseNamespace(arguments[i]);

                for (j = 0, subLn = parts.length; j < subLn; j++) {
                    part = parts[j];

                    if (typeof part != 'string') {
                        root = part;
                    } else {
                        if (!root[part]) {
                            root[part] = {};
                        }

                        root = root[part];
                    }
                }
            }

            return root;
        },

        
        set: function(name, value) {
            var me = this,
                maps = me.maps,
                nameToAlternates = maps.nameToAlternates,
                targetName = me.getName(value),
                alternates;

            me.classes[name] = me.setNamespace(name, value);

            if (targetName && targetName !== name) {
                maps.alternateToName[name] = targetName;
                alternates = nameToAlternates[targetName] || (nameToAlternates[targetName] = []);
                alternates.push(name);
            }

            return this;
        },

        
        get: function(name) {
            var classes = this.classes,
                root,
                parts,
                part, i, ln;

            if (classes[name]) {
                return classes[name];
            }

            root = global;
            parts = this.parseNamespace(name);

            for (i = 0, ln = parts.length; i < ln; i++) {
                part = parts[i];

                if (typeof part != 'string') {
                    root = part;
                } else {
                    if (!root || !root[part]) {
                        return null;
                    }

                    root = root[part];
                }
            }

            return root;
        },

        
        setAlias: function(cls, alias) {
            var aliasToNameMap = this.maps.aliasToName,
                nameToAliasesMap = this.maps.nameToAliases,
                className;

            if (typeof cls == 'string') {
                className = cls;
            } else {
                className = this.getName(cls);
            }

            if (alias && aliasToNameMap[alias] !== className) {

                aliasToNameMap[alias] = className;
            }

            if (!nameToAliasesMap[className]) {
                nameToAliasesMap[className] = [];
            }

            if (alias) {
                Ext.Array.include(nameToAliasesMap[className], alias);
            }

            return this;
        },

        
        getByAlias: function(alias) {
            return this.get(this.getNameByAlias(alias));
        },

        
        getNameByAlias: function(alias) {
            return this.maps.aliasToName[alias] || '';
        },

        
        getNameByAlternate: function(alternate) {
            return this.maps.alternateToName[alternate] || '';
        },

        
        getAliasesByName: function(name) {
            return this.maps.nameToAliases[name] || [];
        },

        
        getName: function(object) {
            return object && object.$className || '';
        },

        
        getClass: function(object) {
            return object && object.self || null;
        },

        
        create: function(className, data, createdFn) {

            var ctor = makeCtor();
            if (typeof data == 'function') {
                data = data(ctor);
            }


            data.$className = className;

            return new Class(ctor, data, function() {
                var postprocessorStack = data.postprocessors || Manager.defaultPostprocessors,
                    registeredPostprocessors = Manager.postprocessors,
                    postprocessors = [],
                    postprocessor, i, ln, j, subLn, postprocessorProperties, postprocessorProperty;

                delete data.postprocessors;

                for (i = 0,ln = postprocessorStack.length; i < ln; i++) {
                    postprocessor = postprocessorStack[i];

                    if (typeof postprocessor == 'string') {
                        postprocessor = registeredPostprocessors[postprocessor];
                        postprocessorProperties = postprocessor.properties;

                        if (postprocessorProperties === true) {
                            postprocessors.push(postprocessor.fn);
                        }
                        else if (postprocessorProperties) {
                            for (j = 0,subLn = postprocessorProperties.length; j < subLn; j++) {
                                postprocessorProperty = postprocessorProperties[j];

                                if (data.hasOwnProperty(postprocessorProperty)) {
                                    postprocessors.push(postprocessor.fn);
                                    break;
                                }
                            }
                        }
                    }
                    else {
                        postprocessors.push(postprocessor);
                    }
                }

                data.postprocessors = postprocessors;
                data.createdFn = createdFn;
                Manager.processCreate(className, this, data);
            });
        },
        
        processCreate: function(className, cls, clsData){
            var me = this,
                postprocessor = clsData.postprocessors.shift(),
                createdFn = clsData.createdFn;

            if (!postprocessor) {
                if (className) {
                    me.set(className, cls);
                }

                if (createdFn) {
                    createdFn.call(cls, cls);
                }

                if (className) {
                    me.triggerCreated(className);
                }
                return;
            }

            if (postprocessor.call(me, className, cls, clsData, me.processCreate) !== false) {
                me.processCreate(className, cls, clsData);
            }
        },

        createOverride: function (className, data, createdFn) {
            var me = this,
                overriddenClassName = data.override,
                requires = data.requires,
                uses = data.uses,
                classReady = function () {
                    var cls, temp;

                    if (requires) {
                        temp = requires;
                        requires = null; 

                        
                        
                        
                        Ext.Loader.require(temp, classReady);
                    } else {
                        
                        
                        cls = me.get(overriddenClassName);

                        
                        delete data.override;
                        delete data.requires;
                        delete data.uses;

                        Ext.override(cls, data);

                        
                        
                        
                        me.triggerCreated(className);

                        if (uses) {
                            Ext.Loader.addUsedClasses(uses); 
                        }

                        if (createdFn) {
                            createdFn.call(cls); 
                        }
                    }
                };

            me.existCache[className] = true;

            
            me.onCreated(classReady, me, overriddenClassName);
 
            return me;
        },

        
        instantiateByAlias: function() {
            var alias = arguments[0],
                args = arraySlice.call(arguments),
                className = this.getNameByAlias(alias);

            if (!className) {
                className = this.maps.aliasToName[alias];



                Ext.syncRequire(className);
            }

            args[0] = className;

            return this.instantiate.apply(this, args);
        },

        
        instantiate: function() {
            var name = arguments[0],
                nameType = typeof name,
                args = arraySlice.call(arguments, 1),
                alias = name,
                possibleName, cls;

            if (nameType != 'function') {
                if (nameType != 'string' && args.length === 0) {
                    args = [name];
                    name = name.xclass;
                }


                cls = this.get(name);
            }
            else {
                cls = name;
            }

            
            if (!cls) {
                possibleName = this.getNameByAlias(name);

                if (possibleName) {
                    name = possibleName;

                    cls = this.get(name);
                }
            }

            
            if (!cls) {
                possibleName = this.getNameByAlternate(name);

                if (possibleName) {
                    name = possibleName;

                    cls = this.get(name);
                }
            }

            
            if (!cls) {

                Ext.syncRequire(name);

                cls = this.get(name);
            }


            return this.getInstantiator(args.length)(cls, args);
        },

        
        dynInstantiate: function(name, args) {
            args = arrayFrom(args, true);
            args.unshift(name);

            return this.instantiate.apply(this, args);
        },

        
        getInstantiator: function(length) {
            var instantiators = this.instantiators,
                instantiator,
                i,
                args;

            instantiator = instantiators[length];

            if (!instantiator) {
                i = length;
                args = [];

                for (i = 0; i < length; i++) {
                    args.push('a[' + i + ']');
                }

                instantiator = instantiators[length] = new Function('c', 'a', 'return new c(' + args.join(',') + ')');
            }

            return instantiator;
        },

        
        postprocessors: {},

        
        defaultPostprocessors: [],

        
        registerPostprocessor: function(name, fn, properties, position, relativeTo) {
            if (!position) {
                position = 'last';
            }

            if (!properties) {
                properties = [name];
            }

            this.postprocessors[name] = {
                name: name,
                properties: properties || false,
                fn: fn
            };

            this.setDefaultPostprocessorPosition(name, position, relativeTo);

            return this;
        },

        
        setDefaultPostprocessors: function(postprocessors) {
            this.defaultPostprocessors = arrayFrom(postprocessors);

            return this;
        },

        
        setDefaultPostprocessorPosition: function(name, offset, relativeName) {
            var defaultPostprocessors = this.defaultPostprocessors,
                index;

            if (typeof offset == 'string') {
                if (offset === 'first') {
                    defaultPostprocessors.unshift(name);

                    return this;
                }
                else if (offset === 'last') {
                    defaultPostprocessors.push(name);

                    return this;
                }

                offset = (offset === 'after') ? 1 : -1;
            }

            index = Ext.Array.indexOf(defaultPostprocessors, relativeName);

            if (index !== -1) {
                Ext.Array.splice(defaultPostprocessors, Math.max(0, index + offset), 0, name);
            }

            return this;
        },

        
        getNamesByExpression: function(expression) {
            var nameToAliasesMap = this.maps.nameToAliases,
                names = [],
                name, alias, aliases, possibleName, regex, i, ln;


            if (expression.indexOf('*') !== -1) {
                expression = expression.replace(/\*/g, '(.*?)');
                regex = new RegExp('^' + expression + '$');

                for (name in nameToAliasesMap) {
                    if (nameToAliasesMap.hasOwnProperty(name)) {
                        aliases = nameToAliasesMap[name];

                        if (name.search(regex) !== -1) {
                            names.push(name);
                        }
                        else {
                            for (i = 0, ln = aliases.length; i < ln; i++) {
                                alias = aliases[i];

                                if (alias.search(regex) !== -1) {
                                    names.push(name);
                                    break;
                                }
                            }
                        }
                    }
                }

            } else {
                possibleName = this.getNameByAlias(expression);

                if (possibleName) {
                    names.push(possibleName);
                } else {
                    possibleName = this.getNameByAlternate(expression);

                    if (possibleName) {
                        names.push(possibleName);
                    } else {
                        names.push(expression);
                    }
                }
            }

            return names;
        }
    };

    
    Manager.registerPostprocessor('alias', function(name, cls, data) {
        var aliases = data.alias,
            i, ln;

        for (i = 0,ln = aliases.length; i < ln; i++) {
            alias = aliases[i];

            this.setAlias(cls, alias);
        }

    }, ['xtype', 'alias']);

    
    Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
        fn.call(this, name, new cls(), data);
        return false;
    });

    
    Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
        var alternates = data.alternateClassName,
            i, ln, alternate;

        if (!(alternates instanceof Array)) {
            alternates = [alternates];
        }

        for (i = 0, ln = alternates.length; i < ln; i++) {
            alternate = alternates[i];


            this.set(alternate, cls);
        }
    });

    Ext.apply(Ext, {
        
        create: alias(Manager, 'instantiate'),

        
        widget: function(name, config) {
            
            
            
            
            
            
            
            var xtype = name,
                alias, className, T, load;

            if (typeof xtype != 'string') { 
                
                config = name; 
                xtype = config.xtype;
            } else {
                config = config || {};
            }
            
            if (config.isComponent) {
                return config;
            }

            alias = 'widget.' + xtype;
            className = Manager.getNameByAlias(alias);

            
            if (!className) {
                load = true;
            }
            
            T = Manager.get(className);
            if (load || !T) {
                return Manager.instantiateByAlias(alias, config);
            }
            return new T(config);
        },

        
        createByAlias: alias(Manager, 'instantiateByAlias'),

        
        define: function (className, data, createdFn) {
            if (data.override) {
                return Manager.createOverride.apply(Manager, arguments);
            }

            return Manager.create.apply(Manager, arguments);
        },

        
        getClassName: alias(Manager, 'getName'),

        
        getDisplayName: function(object) {
            if (object) {
                if (object.displayName) {
                    return object.displayName;
                }

                if (object.$name && object.$class) {
                    return Ext.getClassName(object.$class) + '#' + object.$name;
                }

                if (object.$className) {
                    return object.$className;
                }
            }

            return 'Anonymous';
        },

        
        getClass: alias(Manager, 'getClass'),

        
        namespace: alias(Manager, 'createNamespaces')
    });

    
    Ext.createWidget = Ext.widget;

    
    Ext.ns = Ext.namespace;

    Class.registerPreprocessor('className', function(cls, data) {
        if (data.$className) {
            cls.$className = data.$className;
        }
    }, true, 'first');

    Class.registerPreprocessor('alias', function(cls, data) {
        var prototype = cls.prototype,
            xtypes = arrayFrom(data.xtype),
            aliases = arrayFrom(data.alias),
            widgetPrefix = 'widget.',
            widgetPrefixLength = widgetPrefix.length,
            xtypesChain = Array.prototype.slice.call(prototype.xtypesChain || []),
            xtypesMap = Ext.merge({}, prototype.xtypesMap || {}),
            i, ln, alias, xtype;

        for (i = 0,ln = aliases.length; i < ln; i++) {
            alias = aliases[i];


            if (alias.substring(0, widgetPrefixLength) === widgetPrefix) {
                xtype = alias.substring(widgetPrefixLength);
                Ext.Array.include(xtypes, xtype);
            }
        }

        cls.xtype = data.xtype = xtypes[0];
        data.xtypes = xtypes;

        for (i = 0,ln = xtypes.length; i < ln; i++) {
            xtype = xtypes[i];

            if (!xtypesMap[xtype]) {
                xtypesMap[xtype] = true;
                xtypesChain.push(xtype);
            }
        }

        data.xtypesChain = xtypesChain;
        data.xtypesMap = xtypesMap;

        Ext.Function.interceptAfter(data, 'onClassCreated', function() {
            var mixins = prototype.mixins,
                key, mixin;

            for (key in mixins) {
                if (mixins.hasOwnProperty(key)) {
                    mixin = mixins[key];

                    xtypes = mixin.xtypes;

                    if (xtypes) {
                        for (i = 0,ln = xtypes.length; i < ln; i++) {
                            xtype = xtypes[i];

                            if (!xtypesMap[xtype]) {
                                xtypesMap[xtype] = true;
                                xtypesChain.push(xtype);
                            }
                        }
                    }
                }
            }
        });

        for (i = 0,ln = xtypes.length; i < ln; i++) {
            xtype = xtypes[i];


            Ext.Array.include(aliases, widgetPrefix + xtype);
        }

        data.alias = aliases;

    }, ['xtype', 'alias']);

}(Ext.Class, Ext.Function.alias, Array.prototype.slice, Ext.Array.from, Ext.global));



Ext.Loader = new function() {
    var Loader = this,
        Manager = Ext.ClassManager,
        Class = Ext.Class,
        flexSetter = Ext.Function.flexSetter,
        alias = Ext.Function.alias,
        pass = Ext.Function.pass,
        defer = Ext.Function.defer,
        arrayErase = Ext.Array.erase,
        dependencyProperties = ['extend', 'mixins', 'requires'],
        isInHistory = {},
        history = [],
        slashDotSlashRe = /\/\.\//g,
        dotRe = /\./g;

    Ext.apply(Loader, {

        
        isInHistory: isInHistory,

        
        history: history,

        
        config: {
            
            enabled: false,

            
            scriptChainDelay : false,

            
            disableCaching: true,

            
            disableCachingParam: '_dc',

            
            garbageCollect : false,

            
            paths: {
                'Ext': '.'
            },

            
            preserveScripts : true,

            
            scriptCharset : undefined
        },

        
        setConfig: function(name, value) {
            if (Ext.isObject(name) && arguments.length === 1) {
                Ext.merge(Loader.config, name);
            }
            else {
                Loader.config[name] = (Ext.isObject(value)) ? Ext.merge(Loader.config[name], value) : value;
            }

            return Loader;
        },

        
        getConfig: function(name) {
            if (name) {
                return Loader.config[name];
            }

            return Loader.config;
        },

        
        setPath: flexSetter(function(name, path) {
            Loader.config.paths[name] = path;

            return Loader;
        }),

        
        getPath: function(className) {
            var path = '',
                paths = Loader.config.paths,
                prefix = Loader.getPrefix(className);

            if (prefix.length > 0) {
                if (prefix === className) {
                    return paths[prefix];
                }

                path = paths[prefix];
                className = className.substring(prefix.length + 1);
            }

            if (path.length > 0) {
                path += '/';
            }

            return path.replace(slashDotSlashRe, '/') + className.replace(dotRe, "/") + '.js';
        },

        
        getPrefix: function(className) {
            var paths = Loader.config.paths,
                prefix, deepestPrefix = '';

            if (paths.hasOwnProperty(className)) {
                return className;
            }

            for (prefix in paths) {
                if (paths.hasOwnProperty(prefix) && prefix + '.' === className.substring(0, prefix.length + 1)) {
                    if (prefix.length > deepestPrefix.length) {
                        deepestPrefix = prefix;
                    }
                }
            }

            return deepestPrefix;
        },

        
        isAClassNameWithAKnownPrefix: function(className) {
            var prefix = Loader.getPrefix(className);

            
            return prefix !== '' && prefix !== className;
        },

        
        require: function(expressions, fn, scope, excludes) {
            if (fn) {
                fn.call(scope);
            }
        },

        
        syncRequire: function() {},

        
        exclude: function(excludes) {
            return {
                require: function(expressions, fn, scope) {
                    return Loader.require(expressions, fn, scope, excludes);
                },

                syncRequire: function(expressions, fn, scope) {
                    return Loader.syncRequire(expressions, fn, scope, excludes);
                }
            };
        },

        
        onReady: function(fn, scope, withDomReady, options) {
            var oldFn;

            if (withDomReady !== false && Ext.onDocumentReady) {
                oldFn = fn;

                fn = function() {
                    Ext.onDocumentReady(oldFn, scope, options);
                };
            }

            fn.call(scope);
        }
    });

    var queue = [],
        isClassFileLoaded = {},
        isFileLoaded = {},
        classNameToFilePathMap = {},
        scriptElements = {},
        readyListeners = [],
        usedClasses = [],
        requiresMap = {};

    Ext.apply(Loader, {
        
        documentHead: typeof document != 'undefined' && (document.head || document.getElementsByTagName('head')[0]),

        
        isLoading: false,

        
        queue: queue,

        
        isClassFileLoaded: isClassFileLoaded,

        
        isFileLoaded: isFileLoaded,

        
        readyListeners: readyListeners,

        
        optionalRequires: usedClasses,

        
        requiresMap: requiresMap,

        
        numPendingFiles: 0,

        
        numLoadedFiles: 0,

        
        hasFileLoadError: false,

        
        classNameToFilePathMap: classNameToFilePathMap,

        
        scriptsLoading: 0,

        
        syncModeEnabled: false,

        scriptElements: scriptElements,

        
        refreshQueue: function() {
            var ln = queue.length,
                i, item, j, requires;

            

            if (!ln && !Loader.scriptsLoading) {
                return Loader.triggerReady();
            }

            for (i = 0; i < ln; i++) {
                item = queue[i];

                if (item) {
                    requires = item.requires;

                    
                    
                    if (requires.length > Loader.numLoadedFiles) {
                        continue;
                    }

                    
                    for (j = 0; j < requires.length; ) {
                        if (Manager.isCreated(requires[j])) {
                            
                            arrayErase(requires, j, 1);
                        }
                        else {
                            j++;
                        }
                    }

                    
                    if (item.requires.length === 0) {
                        arrayErase(queue, i, 1);
                        item.callback.call(item.scope);
                        Loader.refreshQueue();
                        break;
                    }
                }
            }

            return Loader;
        },

        
        injectScriptElement: function(url, onLoad, onError, scope, charset) {
            var script = document.createElement('script'),
                dispatched = false,
                config = Loader.config,
                onLoadFn = function() {

                    if(!dispatched) {
                        dispatched = true;
                        script.onload = script.onreadystatechange = script.onerror = null;
                        if (typeof config.scriptChainDelay == 'number') {
                            
                            defer(onLoad, config.scriptChainDelay, scope);
                        } else {
                            onLoad.call(scope);
                        }
                        Loader.cleanupScriptElement(script, config.preserveScripts === false, config.garbageCollect);
                    }

                },
                onErrorFn = function(arg) {
                    defer(onError, 1, scope);   
                    Loader.cleanupScriptElement(script, config.preserveScripts === false, config.garbageCollect);
                };

            script.type = 'text/javascript';
            script.onerror = onErrorFn;
            charset = charset || config.scriptCharset;
            if (charset) {
                script.charset = charset;
            }

            
            if ('addEventListener' in script ) {
                script.onload = onLoadFn;
            } else if ('readyState' in script) {   
                script.onreadystatechange = function() {
                    if ( this.readyState == 'loaded' || this.readyState == 'complete' ) {
                        onLoadFn();
                    }
                };
            } else {
                 script.onload = onLoadFn;
            }

            script.src = url;
            (Loader.documentHead || document.getElementsByTagName('head')[0]).appendChild(script);

            return script;
        },

        
        removeScriptElement: function(url) {
            if (scriptElements[url]) {
                Loader.cleanupScriptElement(scriptElements[url], true, !!Loader.getConfig('garbageCollect'));
                delete scriptElements[url];
            }

            return Loader;
        },

        
        cleanupScriptElement: function(script, remove, collect) {
            var prop;
            script.onload = script.onreadystatechange = script.onerror = null;
            if (remove) {
                Ext.removeNode(script);       
                if (collect) {
                    for (prop in script) {
                        try {
                            script[prop] = null;
                            delete script[prop];      
                        } catch (cleanEx) {
                            
                        }
                    }
                }
            }

            return Loader;
        },

        
        loadScript: function (options) {
            var config = Loader.getConfig(),
                isString = typeof options == 'string',
                url = isString ? options : options.url,
                onError = !isString && options.onError,
                onLoad = !isString && options.onLoad,
                scope = !isString && options.scope,
                onScriptError = function() {
                    Loader.numPendingFiles--;
                    Loader.scriptsLoading--;

                    if (onError) {
                        onError.call(scope, "Failed loading '" + url + "', please verify that the file exists");
                    }

                    if (Loader.numPendingFiles + Loader.scriptsLoading === 0) {
                        Loader.refreshQueue();
                    }
                },
                onScriptLoad = function () {
                    Loader.numPendingFiles--;
                    Loader.scriptsLoading--;

                    if (onLoad) {
                        onLoad.call(scope);
                    }

                    if (Loader.numPendingFiles + Loader.scriptsLoading === 0) {
                        Loader.refreshQueue();
                    }
                },
                src;

            Loader.isLoading = true;
            Loader.numPendingFiles++;
            Loader.scriptsLoading++;

            src = config.disableCaching ?
                (url + '?' + config.disableCachingParam + '=' + Ext.Date.now()) : url;

            scriptElements[url] = Loader.injectScriptElement(src, onScriptLoad, onScriptError);
        },

        
        loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
            if (isFileLoaded[url]) {
                return Loader;
            }

            var config = Loader.getConfig(),
                noCacheUrl = url + (config.disableCaching ? ('?' + config.disableCachingParam + '=' + Ext.Date.now()) : ''),
                isCrossOriginRestricted = false,
                xhr, status, onScriptError,
                debugSourceURL = "";

            scope = scope || Loader;

            Loader.isLoading = true;

            if (!synchronous) {
                onScriptError = function() {
                };

                scriptElements[url] = Loader.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
            } else {
                if (typeof XMLHttpRequest != 'undefined') {
                    xhr = new XMLHttpRequest();
                } else {
                    xhr = new ActiveXObject('Microsoft.XMLHTTP');
                }

                try {
                    xhr.open('GET', noCacheUrl, false);
                    xhr.send(null);
                } catch (e) {
                    isCrossOriginRestricted = true;
                }

                status = (xhr.status === 1223) ? 204 :
                    (xhr.status === 0 && (self.location || {}).protocol == 'file:') ? 200 : xhr.status;

                isCrossOriginRestricted = isCrossOriginRestricted || (status === 0);

                if (isCrossOriginRestricted
                ) {
                }
                else if ((status >= 200 && status < 300) || (status === 304)
                ) {
                    
                    
                    if (!Ext.isIE) {
                        debugSourceURL = "\n//@ sourceURL=" + url;
                    }

                    Ext.globalEval(xhr.responseText + debugSourceURL);

                    onLoad.call(scope);
                }
                else {
                }

                
                xhr = null;
            }
        },

        
        syncRequire: function() {
            var syncModeEnabled = Loader.syncModeEnabled;

            if (!syncModeEnabled) {
                Loader.syncModeEnabled = true;
            }

            Loader.require.apply(Loader, arguments);

            if (!syncModeEnabled) {
                Loader.syncModeEnabled = false;
            }

            Loader.refreshQueue();
        },

        
        require: function(expressions, fn, scope, excludes) {
            var excluded = {},
                included = {},
                excludedClassNames = [],
                possibleClassNames = [],
                classNames = [],
                references = [],
                callback,
                syncModeEnabled,
                filePath, expression, exclude, className,
                possibleClassName, i, j, ln, subLn;

            if (excludes) {
                
                excludes = (typeof excludes === 'string') ? [ excludes ] : excludes;

                for (i = 0,ln = excludes.length; i < ln; i++) {
                    exclude = excludes[i];

                    if (typeof exclude == 'string' && exclude.length > 0) {
                        excludedClassNames = Manager.getNamesByExpression(exclude);

                        for (j = 0,subLn = excludedClassNames.length; j < subLn; j++) {
                            excluded[excludedClassNames[j]] = true;
                        }
                    }
                }
            }

            
            expressions = (typeof expressions === 'string') ? [ expressions ] : (expressions ? expressions : []);

            if (fn) {
                if (fn.length > 0) {
                    callback = function() {
                        var classes = [],
                            i, ln;

                        for (i = 0,ln = references.length; i < ln; i++) {
                            classes.push(Manager.get(references[i]));
                        }

                        return fn.apply(this, classes);
                    };
                }
                else {
                    callback = fn;
                }
            }
            else {
                callback = Ext.emptyFn;
            }

            scope = scope || Ext.global;

            for (i = 0,ln = expressions.length; i < ln; i++) {
                expression = expressions[i];

                if (typeof expression == 'string' && expression.length > 0) {
                    possibleClassNames = Manager.getNamesByExpression(expression);
                    subLn = possibleClassNames.length;

                    for (j = 0; j < subLn; j++) {
                        possibleClassName = possibleClassNames[j];

                        if (excluded[possibleClassName] !== true) {
                            references.push(possibleClassName);

                            if (!Manager.isCreated(possibleClassName) && !included[possibleClassName]) {
                                included[possibleClassName] = true;
                                classNames.push(possibleClassName);
                            }
                        }
                    }
                }
            }

            
            
            if (classNames.length > 0) {
                if (!Loader.config.enabled) {
                    throw new Error("Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +
                             "Missing required class" + ((classNames.length > 1) ? "es" : "") + ": " + classNames.join(', '));
                }
            }
            else {
                callback.call(scope);
                return Loader;
            }

            syncModeEnabled = Loader.syncModeEnabled;

            if (!syncModeEnabled) {
                queue.push({
                    requires: classNames.slice(), 
                                                  
                    callback: callback,
                    scope: scope
                });
            }

            ln = classNames.length;

            for (i = 0; i < ln; i++) {
                className = classNames[i];

                filePath = Loader.getPath(className);

                
                
                
                if (syncModeEnabled && isClassFileLoaded.hasOwnProperty(className)) {
                    Loader.numPendingFiles--;
                    Loader.removeScriptElement(filePath);
                    delete isClassFileLoaded[className];
                }

                if (!isClassFileLoaded.hasOwnProperty(className)) {
                    isClassFileLoaded[className] = false;

                    classNameToFilePathMap[className] = filePath;

                    Loader.numPendingFiles++;
                    Loader.loadScriptFile(
                        filePath,
                        pass(Loader.onFileLoaded, [className, filePath], Loader),
                        pass(Loader.onFileLoadError, [className, filePath], Loader),
                        Loader,
                        syncModeEnabled
                    );
                }
            }

            if (syncModeEnabled) {
                callback.call(scope);

                if (ln === 1) {
                    return Manager.get(className);
                }
            }

            return Loader;
        },

        
        onFileLoaded: function(className, filePath) {
            Loader.numLoadedFiles++;

            isClassFileLoaded[className] = true;
            isFileLoaded[filePath] = true;

            Loader.numPendingFiles--;

            if (Loader.numPendingFiles === 0) {
                Loader.refreshQueue();
            }

        },

        
        onFileLoadError: function(className, filePath, errorMessage, isSynchronous) {
            Loader.numPendingFiles--;
            Loader.hasFileLoadError = true;

        },

        
        addUsedClasses: function (classes) {
            var cls, i, ln;

            if (classes) {
                classes = (typeof classes == 'string') ? [classes] : classes;
                for (i = 0, ln = classes.length; i < ln; i++) {
                    cls = classes[i];
                    if (typeof cls == 'string' && !Ext.Array.contains(usedClasses, cls)) {
                        usedClasses.push(cls);
                    }
                }
            }

            return Loader;
        },

        
        triggerReady: function() {
            var listener,
                i, refClasses = usedClasses;

            if (Loader.isLoading) {
                Loader.isLoading = false;

                if (refClasses.length !== 0) {
                    
                    refClasses = refClasses.slice();
                    usedClasses.length = 0;
                    
                    
                    Loader.require(refClasses, Loader.triggerReady, Loader);
                    return Loader;
                }
            }

            
            
            
            while (readyListeners.length && !Loader.isLoading) {
                
                
                listener = readyListeners.shift();
                listener.fn.call(listener.scope);
            }

            return Loader;
        },

        
        onReady: function(fn, scope, withDomReady, options) {
            var oldFn;

            if (withDomReady !== false && Ext.onDocumentReady) {
                oldFn = fn;

                fn = function() {
                    Ext.onDocumentReady(oldFn, scope, options);
                };
            }

            if (!Loader.isLoading) {
                fn.call(scope);
            }
            else {
                readyListeners.push({
                    fn: fn,
                    scope: scope
                });
            }
        },

        
        historyPush: function(className) {
            if (className && isClassFileLoaded.hasOwnProperty(className) && !isInHistory[className]) {
                isInHistory[className] = true;
                history.push(className);
            }
            return Loader;
        }
    });

    
    Ext.disableCacheBuster = function (disable, path) {
        var date = new Date();
        date.setTime(date.getTime() + (disable ? 10*365 : -1) * 24*60*60*1000);
        date = date.toGMTString();
        document.cookie = 'ext-cache=1; expires=' + date + '; path='+(path || '/');
    };


    
    Ext.require = alias(Loader, 'require');

    
    Ext.syncRequire = alias(Loader, 'syncRequire');

    
    Ext.exclude = alias(Loader, 'exclude');

    
    Ext.onReady = function(fn, scope, options) {
        Loader.onReady(fn, scope, true, options);
    };

    
    Class.registerPreprocessor('loader', function(cls, data, hooks, continueFn) {
        var me = this,
            dependencies = [],
            dependency,
            className = Manager.getName(cls),
            i, j, ln, subLn, value, propertyName, propertyValue,
            requiredMap, requiredDep;

        

        for (i = 0,ln = dependencyProperties.length; i < ln; i++) {
            propertyName = dependencyProperties[i];

            if (data.hasOwnProperty(propertyName)) {
                propertyValue = data[propertyName];

                if (typeof propertyValue == 'string') {
                    dependencies.push(propertyValue);
                }
                else if (propertyValue instanceof Array) {
                    for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
                        value = propertyValue[j];

                        if (typeof value == 'string') {
                            dependencies.push(value);
                        }
                    }
                }
                else if (typeof propertyValue != 'function') {
                    for (j in propertyValue) {
                        if (propertyValue.hasOwnProperty(j)) {
                            value = propertyValue[j];

                            if (typeof value == 'string') {
                                dependencies.push(value);
                            }
                        }
                    }
                }
            }
        }

        if (dependencies.length === 0) {
            return;
        }


        Loader.require(dependencies, function() {
            for (i = 0,ln = dependencyProperties.length; i < ln; i++) {
                propertyName = dependencyProperties[i];

                if (data.hasOwnProperty(propertyName)) {
                    propertyValue = data[propertyName];

                    if (typeof propertyValue == 'string') {
                        data[propertyName] = Manager.get(propertyValue);
                    }
                    else if (propertyValue instanceof Array) {
                        for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
                            value = propertyValue[j];

                            if (typeof value == 'string') {
                                data[propertyName][j] = Manager.get(value);
                            }
                        }
                    }
                    else if (typeof propertyValue != 'function') {
                        for (var k in propertyValue) {
                            if (propertyValue.hasOwnProperty(k)) {
                                value = propertyValue[k];

                                if (typeof value == 'string') {
                                    data[propertyName][k] = Manager.get(value);
                                }
                            }
                        }
                    }
                }
            }

            continueFn.call(me, cls, data, hooks);
        });

        return false;
    }, true, 'after', 'className');

    
    Manager.registerPostprocessor('uses', function(name, cls, data) {
        var uses = data.uses;
        if (uses) {
            Loader.addUsedClasses(uses);
        }
    });

    Manager.onCreated(Loader.historyPush);
};


Ext.Error = Ext.extend(Error, {
    statics: {
        
        ignore: false,

        
        

        
        raise: function(err){
            err = err || {};
            if (Ext.isString(err)) {
                err = { msg: err };
            }

            var method = this.raise.caller,
                msg;

            if (method) {
                if (method.$name) {
                    err.sourceMethod = method.$name;
                }
                if (method.$owner) {
                    err.sourceClass = method.$owner.$className;
                }
            }

            if (Ext.Error.handle(err) !== true) {
                msg = Ext.Error.prototype.toString.call(err);

                Ext.log({
                    msg: msg,
                    level: 'error',
                    dump: err,
                    stack: true
                });

                throw new Ext.Error(err);
            }
        },

        
        handle: function(){
            return Ext.Error.ignore;
        }
    },

    
    name: 'Ext.Error',

    
    constructor: function(config){
        if (Ext.isString(config)) {
            config = { msg: config };
        }

        var me = this;

        Ext.apply(me, config);

        me.message = me.message || me.msg; 
        
    },

    
    toString: function(){
        var me = this,
            className = me.sourceClass ? me.sourceClass : '',
            methodName = me.sourceMethod ? '.' + me.sourceMethod + '(): ' : '',
            msg = me.msg || '(No description provided)';

        return className + methodName + msg;
    }
});


Ext.deprecated = function (suggestion) {
    return Ext.emptyFn;
};





Ext.JSON = (new(function() {
    var me = this,
    encodingFunction,
    decodingFunction,
    useNative = null,
    useHasOwn = !! {}.hasOwnProperty,
    isNative = function() {
        if (useNative === null) {
            useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
        }
        return useNative;
    },
    pad = function(n) {
        return n < 10 ? "0" + n : n;
    },
    doDecode = function(json) {
        return eval("(" + json + ')');
    },
    doEncode = function(o, newline) {
        
        if (o === null || o === undefined) {
            return "null";
        } else if (Ext.isDate(o)) {
            return Ext.JSON.encodeDate(o);
        } else if (Ext.isString(o)) {
            return Ext.JSON.encodeString(o);
        } else if (typeof o == "number") {
            
            return isFinite(o) ? String(o) : "null";
        } else if (Ext.isBoolean(o)) {
            return String(o);
        }
        
        
        else if (o.toJSON) {
            return o.toJSON();
        } else if (Ext.isArray(o)) {
            return encodeArray(o, newline);
        } else if (Ext.isObject(o)) {
            return encodeObject(o, newline);
        } else if (typeof o === "function") {
            return "null";
        }
        return 'undefined';
    },
    m = {
        "\b": '\\b',
        "\t": '\\t',
        "\n": '\\n',
        "\f": '\\f',
        "\r": '\\r',
        '"': '\\"',
        "\\": '\\\\',
        '\x0b': '\\u000b' 
    },
    charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
    encodeString = function(s) {
        return '"' + s.replace(charToReplace, function(a) {
            var c = m[a];
            return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"';
    },


    encodeArray = function(o, newline) {

        var a = ["[", ""], 
            len = o.length,
            i;
        for (i = 0; i < len; i += 1) {
            a.push(Ext.JSON.encodeValue(o[i]), ',');
        }
        
        a[a.length - 1] = ']';
        return a.join("");
    },

    encodeObject = function(o, newline) {

        var a = ["{", ""], 
            i;
        for (i in o) {
            if (!useHasOwn || o.hasOwnProperty(i)) {
                a.push(Ext.JSON.encodeValue(i), ":", Ext.JSON.encodeValue(o[i]), ',');
            }
        }
        
        a[a.length - 1] = '}';
        return a.join("");
    };
    
    
    me.encodeString = encodeString;

    
    me.encodeValue = doEncode;

    
    me.encodeDate = function(o) {
        return '"' + o.getFullYear() + "-"
        + pad(o.getMonth() + 1) + "-"
        + pad(o.getDate()) + "T"
        + pad(o.getHours()) + ":"
        + pad(o.getMinutes()) + ":"
        + pad(o.getSeconds()) + '"';
    };

    
    me.encode = function(o) {
        if (!encodingFunction) {
            
            encodingFunction = isNative() ? JSON.stringify : me.encodeValue;
        }
        return encodingFunction(o);
    };

    
    me.decode = function(json, safe) {
        if (!decodingFunction) {
            
            decodingFunction = isNative() ? JSON.parse : doDecode;
        }
        try {
            return decodingFunction(json);
        } catch (e) {
            if (safe === true) {
                return null;
            }
            Ext.Error.raise({
                sourceClass: "Ext.JSON",
                sourceMethod: "decode",
                msg: "You're trying to decode an invalid JSON String: " + json
            });
        }
    };
})());

Ext.encode = Ext.JSON.encode;

Ext.decode = Ext.JSON.decode;

Ext.apply(Ext, {
    userAgent: navigator.userAgent.toLowerCase(),
    cache: {},
    idSeed: 1000,
    windowId: 'ext-window',
    documentId: 'ext-document',

    
    isReady: false,

    
    enableGarbageCollector: true,

    
    enableListenerCollection: true,

    addCacheEntry: function(id, el, dom) {
        dom = dom || el.dom;


        var key = id || (el && el.id) || dom.id,
            entry = Ext.cache[key] || (Ext.cache[key] = {
                data: {},
                events: {},

                dom: dom,

                
                skipGarbageCollection: !!(dom.getElementById || dom.navigator)
            });

        if (el) {
            el.$cache = entry;
            
            
            entry.el = el;
        }

        return entry;
    },
    
    updateCacheEntry: function(cacheItem, dom){
        cacheItem.dom = dom;
        if (cacheItem.el) {
            cacheItem.el.dom = dom;
        }
        return cacheItem;
    },

    
    id: function(el, prefix) {
        var me = this,
            sandboxPrefix = '';
        el = Ext.getDom(el, true) || {};
        if (el === document) {
            el.id = me.documentId;
        }
        else if (el === window) {
            el.id = me.windowId;
        }
        if (!el.id) {
            if (me.isSandboxed) {
                sandboxPrefix = Ext.sandboxName.toLowerCase() + '-';
            }
            el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
        }
        return el.id;
    },

    escapeId: (function(){
        var validIdRe = /^[a-zA-Z_][a-zA-Z0-9_\-]*$/i,
            escapeRx = /([\W]{1})/g,
            leadingNumRx = /^(\d)/g,
            escapeFn = function(match, capture){
                return "\\" + capture;
            },
            numEscapeFn = function(match, capture){
                return '\\00' + capture.charCodeAt(0).toString(16) + ' ';
            };

        return function(id) {
            return validIdRe.test(id)
                ? id
                
                
                : id.replace(escapeRx, escapeFn)
                    .replace(leadingNumRx, numEscapeFn);
        };
    }()),

    
    getBody: (function() {
        var body;
        return function() {
            return body || (body = Ext.get(document.body));
        };
    }()),

    
    getHead: (function() {
        var head;
        return function() {
            return head || (head = Ext.get(document.getElementsByTagName("head")[0]));
        };
    }()),

    
    getDoc: (function() {
        var doc;
        return function() {
            return doc || (doc = Ext.get(document));
        };
    }()),

    
    getCmp: function(id) {
        return Ext.ComponentManager.get(id);
    },

    
    getOrientation: function() {
        return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
    },

    
    destroy: function() {
        var ln = arguments.length,
        i, arg;

        for (i = 0; i < ln; i++) {
            arg = arguments[i];
            if (arg) {
                if (Ext.isArray(arg)) {
                    this.destroy.apply(this, arg);
                }
                else if (Ext.isFunction(arg.destroy)) {
                    arg.destroy();
                }
                else if (arg.dom) {
                    arg.remove();
                }
            }
        }
    },

    
    callback: function(callback, scope, args, delay){
        if(Ext.isFunction(callback)){
            args = args || [];
            scope = scope || window;
            if (delay) {
                Ext.defer(callback, delay, scope, args);
            } else {
                callback.apply(scope, args);
            }
        }
    },

    
    htmlEncode : function(value) {
        return Ext.String.htmlEncode(value);
    },

    
    htmlDecode : function(value) {
         return Ext.String.htmlDecode(value);
    },

    
    urlAppend : function(url, s) {
        return Ext.String.urlAppend(url, s);
    }
});


Ext.ns = Ext.namespace;


window.undefined = window.undefined;


(function(){

    var check = function(regex){
            return regex.test(Ext.userAgent);
        },
        isStrict = document.compatMode == "CSS1Compat",
        version = function (is, regex) {
            var m;
            return (is && (m = regex.exec(Ext.userAgent))) ? parseFloat(m[1]) : 0;
        },
        docMode = document.documentMode,
        isOpera = check(/opera/),
        isOpera10_5 = isOpera && check(/version\/10\.5/),
        isChrome = check(/\bchrome\b/),
        isWebKit = check(/webkit/),
        isSafari = !isChrome && check(/safari/),
        isSafari2 = isSafari && check(/applewebkit\/4/), 
        isSafari3 = isSafari && check(/version\/3/),
        isSafari4 = isSafari && check(/version\/4/),
        isSafari5_0 = isSafari && check(/version\/5\.0/),
        isSafari5 = isSafari && check(/version\/5/),
        isIE = !isOpera && check(/msie/),
        isIE7 = isIE && ((check(/msie 7/) && docMode != 8 && docMode != 9) || docMode == 7),
        isIE8 = isIE && ((check(/msie 8/) && docMode != 7 && docMode != 9) || docMode == 8),
        isIE9 = isIE && ((check(/msie 9/) && docMode != 7 && docMode != 8) || docMode == 9),
        isIE6 = isIE && check(/msie 6/),
        isGecko = !isWebKit && check(/gecko/),
        isGecko3 = isGecko && check(/rv:1\.9/),
        isGecko4 = isGecko && check(/rv:2\.0/),
        isGecko5 = isGecko && check(/rv:5\./),
        isGecko10 = isGecko && check(/rv:10\./),
        isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
        isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
        isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
        isWindows = check(/windows|win32/),
        isMac = check(/macintosh|mac os x/),
        isLinux = check(/linux/),
        scrollbarSize = null,
        chromeVersion = version(true, /\bchrome\/(\d+\.\d+)/),
        firefoxVersion = version(true, /\bfirefox\/(\d+\.\d+)/),
        ieVersion = version(isIE, /msie (\d+\.\d+)/),
        operaVersion = version(isOpera, /version\/(\d+\.\d+)/),
        safariVersion = version(isSafari, /version\/(\d+\.\d+)/),
        webKitVersion = version(isWebKit, /webkit\/(\d+\.\d+)/),
        isSecure = /^https/i.test(window.location.protocol),
        nullLog;

    
    try {
        document.execCommand("BackgroundImageCache", false, true);
    } catch(e) {}



    nullLog = function () {};
    nullLog.info = nullLog.warn = nullLog.error = Ext.emptyFn;

    Ext.setVersion('extjs', '4.1.1');
    Ext.apply(Ext, {
        
        SSL_SECURE_URL : isSecure && isIE ? 'javascript:\'\'' : 'about:blank',

        

        
        scopeResetCSS : Ext.buildSettings.scopeResetCSS,
        
        
        resetCls: Ext.buildSettings.baseCSSPrefix + 'reset',

        
        enableNestedListenerRemoval : false,

        
        USE_NATIVE_JSON : false,

        
        getDom : function(el, strict) {
            if (!el || !document) {
                return null;
            }
            if (el.dom) {
                return el.dom;
            } else {
                if (typeof el == 'string') {
                    var e = Ext.getElementById(el);
                    
                    
                    if (e && isIE && strict) {
                        if (el == e.getAttribute('id')) {
                            return e;
                        } else {
                            return null;
                        }
                    }
                    return e;
                } else {
                    return el;
                }
            }
        },

        
        removeNode : isIE6 || isIE7 || isIE8
            ? (function() {
                var d;
                return function(n){
                    if(n && n.tagName.toUpperCase() != 'BODY'){
                        (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);

                        var cache = Ext.cache,
                            id = n.id;

                        if (cache[id]) {
                            delete cache[id].dom;
                            delete cache[id];
                        }

                        if (isIE8 && n.parentNode) {
                            n.parentNode.removeChild(n);
                        }
                        d = d || document.createElement('div');
                        d.appendChild(n);
                        d.innerHTML = '';
                    }
                };
            }())
            : function(n) {
                if (n && n.parentNode && n.tagName.toUpperCase() != 'BODY') {
                    (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);

                    var cache = Ext.cache,
                        id = n.id;

                    if (cache[id]) {
                        delete cache[id].dom;
                        delete cache[id];
                    }

                    n.parentNode.removeChild(n);
                }
            },

        isStrict: isStrict,

        isIEQuirks: isIE && !isStrict,

        
        isOpera : isOpera,

        
        isOpera10_5 : isOpera10_5,

        
        isWebKit : isWebKit,

        
        isChrome : isChrome,

        
        isSafari : isSafari,

        
        isSafari3 : isSafari3,

        
        isSafari4 : isSafari4,

        
        isSafari5 : isSafari5,

        
        isSafari5_0 : isSafari5_0,


        
        isSafari2 : isSafari2,

        
        isIE : isIE,

        
        isIE6 : isIE6,

        
        isIE7 : isIE7,

        
        isIE8 : isIE8,

        
        isIE9 : isIE9,

        
        isGecko : isGecko,

        
        isGecko3 : isGecko3,

        
        isGecko4 : isGecko4,

        
        isGecko5 : isGecko5,

        
        isGecko10 : isGecko10,

        
        isFF3_0 : isFF3_0,

        
        isFF3_5 : isFF3_5,

        
        isFF3_6 : isFF3_6,

        
        isFF4 : 4 <= firefoxVersion && firefoxVersion < 5,

        
        isFF5 : 5 <= firefoxVersion && firefoxVersion < 6,

        
        isFF10 : 10 <= firefoxVersion && firefoxVersion < 11,

        
        isLinux : isLinux,

        
        isWindows : isWindows,

        
        isMac : isMac,

        
        chromeVersion: chromeVersion,

        
        firefoxVersion: firefoxVersion,

        
        ieVersion: ieVersion,

        
        operaVersion: operaVersion,

        
        safariVersion: safariVersion,

        
        webKitVersion: webKitVersion,

        
        isSecure: isSecure,
        
        
        BLANK_IMAGE_URL : (isIE6 || isIE7) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',

        
        value : function(v, defaultValue, allowBlank){
            return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
        },

        
        escapeRe : function(s) {
            return s.replace(/([-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
        },

        
        addBehaviors : function(o){
            if(!Ext.isReady){
                Ext.onReady(function(){
                    Ext.addBehaviors(o);
                });
            } else {
                var cache = {}, 
                    parts,
                    b,
                    s;
                for (b in o) {
                    if ((parts = b.split('@'))[1]) { 
                        s = parts[0];
                        if(!cache[s]){
                            cache[s] = Ext.select(s);
                        }
                        cache[s].on(parts[1], o[b]);
                    }
                }
                cache = null;
            }
        },

        
        getScrollbarSize: function (force) {
            if (!Ext.isReady) {
                return {};
            }

            if (force || !scrollbarSize) {
                var db = document.body,
                    div = document.createElement('div');

                div.style.width = div.style.height = '100px';
                div.style.overflow = 'scroll';
                div.style.position = 'absolute';

                db.appendChild(div); 

                
                scrollbarSize = {
                    width: div.offsetWidth - div.clientWidth,
                    height: div.offsetHeight - div.clientHeight
                };

                db.removeChild(div);
            }

            return scrollbarSize;
        },

        
        getScrollBarWidth: function(force){
            var size = Ext.getScrollbarSize(force);
            return size.width + 2; 
        },

        
        copyTo : function(dest, source, names, usePrototypeKeys){
            if(typeof names == 'string'){
                names = names.split(/[,;\s]/);
            }

            var n,
                nLen = names.length,
                name;

            for(n = 0; n < nLen; n++) {
                name = names[n];

                if(usePrototypeKeys || source.hasOwnProperty(name)){
                    dest[name] = source[name];
                }
            }

            return dest;
        },

        
        destroyMembers : function(o){
            for (var i = 1, a = arguments, len = a.length; i < len; i++) {
                Ext.destroy(o[a[i]]);
                delete o[a[i]];
            }
        },

        
        log :
            nullLog,

        
        partition : function(arr, truth){
            var ret = [[],[]],
                a, v,
                aLen = arr.length;

            for (a = 0; a < aLen; a++) {
                v = arr[a];
                ret[ (truth && truth(v, a, arr)) || (!truth && v) ? 0 : 1].push(v);
            }

            return ret;
        },

        
        invoke : function(arr, methodName){
            var ret  = [],
                args = Array.prototype.slice.call(arguments, 2),
                a, v,
                aLen = arr.length;

            for (a = 0; a < aLen; a++) {
                v = arr[a];

                if (v && typeof v[methodName] == 'function') {
                    ret.push(v[methodName].apply(v, args));
                } else {
                    ret.push(undefined);
                }
            }

            return ret;
        },

        
        zip : function(){
            var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
                arrs = parts[0],
                fn = parts[1][0],
                len = Ext.max(Ext.pluck(arrs, "length")),
                ret = [],
                i,
                j,
                aLen;

            for (i = 0; i < len; i++) {
                ret[i] = [];
                if(fn){
                    ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
                }else{
                    for (j = 0, aLen = arrs.length; j < aLen; j++){
                        ret[i].push( arrs[j][i] );
                    }
                }
            }
            return ret;
        },

        
        toSentence: function(items, connector) {
            var length = items.length,
                head,
                tail;

            if (length <= 1) {
                return items[0];
            } else {
                head = items.slice(0, length - 1);
                tail = items[length - 1];

                return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
            }
        },

        
        useShims: isIE6
    });
}());


Ext.application = function(config) {
    Ext.require('Ext.app.Application');

    Ext.onReady(function() {
        new Ext.app.Application(config);
    });
};


(function() {
    Ext.ns('Ext.util');

    Ext.util.Format = {};
    var UtilFormat     = Ext.util.Format,
        stripTagsRE    = /<\/?[^>]+>/gi,
        stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
        nl2brRe        = /\r?\n/g,

        
        formatCleanRe  = /[^\d\.]/g,

        
        
        I18NFormatCleanRe;

    Ext.apply(UtilFormat, {
        
        
        thousandSeparator: ',',
        

        
        
        decimalSeparator: '.',
        

        
        
        currencyPrecision: 2,
        

         
        
        currencySign: '$',
        

        
        
        currencyAtEnd: false,
        

        
        undef : function(value) {
            return value !== undefined ? value : "";
        },

        
        defaultValue : function(value, defaultValue) {
            return value !== undefined && value !== '' ? value : defaultValue;
        },

        
        substr : 'ab'.substr(-1) != 'b'
        ? function (value, start, length) {
            var str = String(value);
            return (start < 0)
                ? str.substr(Math.max(str.length + start, 0), length)
                : str.substr(start, length);
        }
        : function(value, start, length) {
            return String(value).substr(start, length);
        },

        
        lowercase : function(value) {
            return String(value).toLowerCase();
        },

        
        uppercase : function(value) {
            return String(value).toUpperCase();
        },

        
        usMoney : function(v) {
            return UtilFormat.currency(v, '$', 2);
        },

        
        currency: function(v, currencySign, decimals, end) {
            var negativeSign = '',
                format = ",0",
                i = 0;
            v = v - 0;
            if (v < 0) {
                v = -v;
                negativeSign = '-';
            }
            decimals = Ext.isDefined(decimals) ? decimals : UtilFormat.currencyPrecision;
            format += format + (decimals > 0 ? '.' : '');
            for (; i < decimals; i++) {
                format += '0';
            }
            v = UtilFormat.number(v, format);
            if ((end || UtilFormat.currencyAtEnd) === true) {
                return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
            } else {
                return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
            }
        },

        
        date: function(v, format) {
            if (!v) {
                return "";
            }
            if (!Ext.isDate(v)) {
                v = new Date(Date.parse(v));
            }
            return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
        },

        
        dateRenderer : function(format) {
            return function(v) {
                return UtilFormat.date(v, format);
            };
        },

        
        stripTags : function(v) {
            return !v ? v : String(v).replace(stripTagsRE, "");
        },

        
        stripScripts : function(v) {
            return !v ? v : String(v).replace(stripScriptsRe, "");
        },

        
        fileSize : function(size) {
            if (size < 1024) {
                return size + " bytes";
            } else if (size < 1048576) {
                return (Math.round(((size*10) / 1024))/10) + " KB";
            } else {
                return (Math.round(((size*10) / 1048576))/10) + " MB";
            }
        },

        
        math : (function(){
            var fns = {};

            return function(v, a){
                if (!fns[a]) {
                    fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
                }
                return fns[a](v);
            };
        }()),

        
        round : function(value, precision) {
            var result = Number(value);
            if (typeof precision == 'number') {
                precision = Math.pow(10, precision);
                result = Math.round(value * precision) / precision;
            }
            return result;
        },

        
        number : function(v, formatString) {
            if (!formatString) {
                return v;
            }
            v = Ext.Number.from(v, NaN);
            if (isNaN(v)) {
                return '';
            }
            var comma = UtilFormat.thousandSeparator,
                dec   = UtilFormat.decimalSeparator,
                i18n  = false,
                neg   = v < 0,
                hasComma,
                psplit,
                fnum,
                cnum,
                parr,
                j,
                m,
                n,
                i;

            v = Math.abs(v);

            
            
            
            
            if (formatString.substr(formatString.length - 2) == '/i') {
                if (!I18NFormatCleanRe) {
                    I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
                }
                formatString = formatString.substr(0, formatString.length - 2);
                i18n   = true;
                hasComma = formatString.indexOf(comma) != -1;
                psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
            } else {
                hasComma = formatString.indexOf(',') != -1;
                psplit = formatString.replace(formatCleanRe, '').split('.');
            }

            if (psplit.length > 2) {
            } else if (psplit.length > 1) {
                v = Ext.Number.toFixed(v, psplit[1].length);
            } else {
                v = Ext.Number.toFixed(v, 0);
            }

            fnum = v.toString();

            psplit = fnum.split('.');

            if (hasComma) {
                cnum = psplit[0];
                parr = [];
                j = cnum.length;
                m = Math.floor(j / 3);
                n = cnum.length % 3 || 3;

                for (i = 0; i < j; i += n) {
                    if (i !== 0) {
                        n = 3;
                    }

                    parr[parr.length] = cnum.substr(i, n);
                    m -= 1;
                }
                fnum = parr.join(comma);
                if (psplit[1]) {
                    fnum += dec + psplit[1];
                }
            } else {
                if (psplit[1]) {
                    fnum = psplit[0] + dec + psplit[1];
                }
            }

            if (neg) {
                
                neg = fnum.replace(/[^1-9]/g, '') !== '';
            }

            return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
        },

        
        numberRenderer : function(format) {
            return function(v) {
                return UtilFormat.number(v, format);
            };
        },

        
        plural : function(v, s, p) {
            return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
        },

        
        nl2br : function(v) {
            return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
        },

        
        capitalize: Ext.String.capitalize,

        
        ellipsis: Ext.String.ellipsis,

        
        format: Ext.String.format,

        
        htmlDecode: Ext.String.htmlDecode,

        
        htmlEncode: Ext.String.htmlEncode,

        
        leftPad: Ext.String.leftPad,

        
        trim : Ext.String.trim,

        
        parseBox : function(box) {
          box = Ext.isEmpty(box) ? '' : box;
            if (Ext.isNumber(box)) {
                box = box.toString();
            }
            var parts  = box.split(' '),
                ln = parts.length;

            if (ln == 1) {
                parts[1] = parts[2] = parts[3] = parts[0];
            }
            else if (ln == 2) {
                parts[2] = parts[0];
                parts[3] = parts[1];
            }
            else if (ln == 3) {
                parts[3] = parts[1];
            }

            return {
                top   :parseInt(parts[0], 10) || 0,
                right :parseInt(parts[1], 10) || 0,
                bottom:parseInt(parts[2], 10) || 0,
                left  :parseInt(parts[3], 10) || 0
            };
        },

        
        escapeRegex : function(s) {
            return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
        }
    });
}());


Ext.define('Ext.util.TaskRunner', {
    
    interval: 10,

    
    timerId: null,

    constructor: function (interval) {
        var me = this;

        if (typeof interval == 'number') {
            me.interval = interval;
        } else if (interval) {
            Ext.apply(me, interval);
        }

        me.tasks = [];
        me.timerFn = Ext.Function.bind(me.onTick, me);
    },

    
    newTask: function (config) {
        var task = new Ext.util.TaskRunner.Task(config);
        task.manager = this;
        return task;
    },

    
    start: function(task) {
        var me = this,
            now = new Date().getTime();

        if (!task.pending) {
            me.tasks.push(task);
            task.pending = true; 
        }

        task.stopped = false; 
        task.taskStartTime = now;
        task.taskRunTime = task.fireOnStart !== false ? 0 : task.taskStartTime;
        task.taskRunCount = 0;

        if (!me.firing) {
            if (task.fireOnStart !== false) {
                me.startTimer(0, now);
            } else {
                me.startTimer(task.interval, now);
            }
        }

        return task;
    },

    
    stop: function(task) {
        
        
        
        if (!task.stopped) {
            task.stopped = true;

            if (task.onStop) {
                task.onStop.call(task.scope || task, task);
            }
        }

        return task;
    },

    
    stopAll: function() {
        
        Ext.each(this.tasks, this.stop, this);
    },

    

    firing: false,

    nextExpires: 1e99,

    
    onTick: function () {
        var me = this,
            tasks = me.tasks,
            now = new Date().getTime(),
            nextExpires = 1e99,
            len = tasks.length,
            expires, newTasks, i, task, rt, remove;

        me.timerId = null;
        me.firing = true; 

        
        
        
        
        for (i = 0; i < len || i < (len = tasks.length); ++i) {
            task = tasks[i];

            if (!(remove = task.stopped)) {
                expires = task.taskRunTime + task.interval;

                if (expires <= now) {
                    rt = 1; 
                    try {
                        rt = task.run.apply(task.scope || task, task.args || [++task.taskRunCount]);
                    } catch (taskError) {
                        try {
                            if (task.onError) {
                                rt = task.onError.call(task.scope || task, task, taskError);
                            }
                        } catch (ignore) { }
                    }
                    task.taskRunTime = now;
                    if (rt === false || task.taskRunCount === task.repeat) {
                        me.stop(task);
                        remove = true;
                    } else {
                        remove = task.stopped; 
                        expires = now + task.interval;
                    }
                }

                if (!remove && task.duration && task.duration <= (now - task.taskStartTime)) {
                    me.stop(task);
                    remove = true;
                }
            }

            if (remove) {
                task.pending = false; 

                
                
                
                
                
                if (!newTasks) {
                    newTasks = tasks.slice(0, i);
                    
                    
                    
                }
            } else {
                if (newTasks) {
                    newTasks.push(task); 
                }

                if (nextExpires > expires) {
                    nextExpires = expires; 
                }
            }
        }

        if (newTasks) {
            
            
            me.tasks = newTasks;
        }

        me.firing = false; 

        if (me.tasks.length) {
            
            
            
            me.startTimer(nextExpires - now, new Date().getTime());
        }
    },

    
    startTimer: function (timeout, now) {
        var me = this,
            expires = now + timeout,
            timerId = me.timerId;

        
        
        if (timerId && me.nextExpires - expires > me.interval) {
            clearTimeout(timerId);
            timerId = null;
        }

        if (!timerId) {
            if (timeout < me.interval) {
                timeout = me.interval;
            }

            me.timerId = setTimeout(me.timerFn, timeout);
            me.nextExpires = expires;
        }
    }
},
function () {
    var me = this,
        proto = me.prototype;

    
    proto.destroy = proto.stopAll;

    
    Ext.util.TaskManager = Ext.TaskManager = new me();

    
    me.Task = new Ext.Class({
        isTask: true,

        
        stopped: true, 

        
        fireOnStart: false,

        constructor: function (config) {
            Ext.apply(this, config);
        },

        
        restart: function (interval) {
            if (interval !== undefined) {
                this.interval = interval;
            }

            this.manager.start(this);
        },

        
        start: function (interval) {
            if (this.stopped) {
                this.restart(interval);
            }
        },

        
        stop: function () {
            this.manager.stop(this);
        }
    });

    proto = me.Task.prototype;

    
    proto.destroy = proto.stop;
});


Ext.define('Ext.perf.Accumulator', (function () {
    var currentFrame = null,
        khrome = Ext.global['chrome'],
        formatTpl,
        
        
        getTimestamp = function () {

            getTimestamp = function () {
                return new Date().getTime();
            };
            
            var interval, toolbox;

            
            if (Ext.isChrome && khrome && khrome.Interval) {
                interval = new khrome.Interval();
                interval.start();
                getTimestamp = function () {
                    return interval.microseconds() / 1000;
                };
            } else if (window.ActiveXObject) {
                try {
                    
                    toolbox = new ActiveXObject('SenchaToolbox.Toolbox');
                    Ext.senchaToolbox = toolbox; 
                    getTimestamp = function () {
                        return toolbox.milliseconds;
                    };
                } catch (e) {
                    
                }
            } else if (Date.now) {
                getTimestamp = Date.now;
            }

            Ext.perf.getTimestamp = Ext.perf.Accumulator.getTimestamp = getTimestamp;
            return getTimestamp();
        };

    function adjustSet (set, time) {
        set.sum += time;
        set.min = Math.min(set.min, time);
        set.max = Math.max(set.max, time);
    }

    function leaveFrame (time) {
        var totalTime = time ? time : (getTimestamp() - this.time), 
            me = this, 
            accum = me.accum;

        ++accum.count;
        if (! --accum.depth) {
            adjustSet(accum.total, totalTime);
        }
        adjustSet(accum.pure, totalTime - me.childTime);

        currentFrame = me.parent;
        if (currentFrame) {
            ++currentFrame.accum.childCount;
            currentFrame.childTime += totalTime;
        }
    }

    function makeSet () {
        return {
            min: Number.MAX_VALUE,
            max: 0,
            sum: 0
        };
    }

    function makeTap (me, fn) {
        return function () {
            var frame = me.enter(),
                ret = fn.apply(this, arguments);

            frame.leave();
            return ret;
        };
    }

    function round (x) {
        return Math.round(x * 100) / 100;
    }

    function setToJSON (count, childCount, calibration, set) {
        var data = {
            avg: 0,
            min: set.min,
            max: set.max,
            sum: 0
        };

        if (count) {
            calibration = calibration || 0;
            data.sum = set.sum - childCount * calibration;
            data.avg = data.sum / count;
            
            
        }

        return data;
    }

    return {
        constructor: function (name) {
            var me = this;

            me.count = me.childCount = me.depth = me.maxDepth = 0;
            me.pure = makeSet();
            me.total = makeSet();
            me.name = name;
        },

        statics: {
            getTimestamp: getTimestamp
        },

        format: function (calibration) {
            if (!formatTpl) {
                formatTpl = new Ext.XTemplate([
                        '{name} - {count} call(s)',
                        '<tpl if="count">',
                            '<tpl if="childCount">',
                                ' ({childCount} children)',
                            '</tpl>',
                            '<tpl if="depth - 1">',
                                ' ({depth} deep)',
                            '</tpl>',
                            '<tpl for="times">',
                                ', {type}: {[this.time(values.sum)]} msec (',
                                     
                                     'avg={[this.time(values.sum / parent.count)]}',
                                     
                                     ')',
                            '</tpl>',
                        '</tpl>'
                    ].join(''), {
                        time: function (t) {
                            return Math.round(t * 100) / 100;
                        }
                    });
            }

            var data = this.getData(calibration);
            data.name = this.name;
            data.pure.type = 'Pure';
            data.total.type = 'Total';
            data.times = [data.pure, data.total];
            return formatTpl.apply(data);
        },

        getData: function (calibration) {
            var me = this;

            return {
                count: me.count,
                childCount: me.childCount,
                depth: me.maxDepth,
                pure: setToJSON(me.count, me.childCount, calibration, me.pure),
                total: setToJSON(me.count, me.childCount, calibration, me.total)
            };
        },

        enter: function () {
            var me = this,
                frame = {
                    accum: me,
                    leave: leaveFrame,
                    childTime: 0,
                    parent: currentFrame
                };

            ++me.depth;
            if (me.maxDepth < me.depth) {
                me.maxDepth = me.depth;
            }

            currentFrame = frame;
            frame.time = getTimestamp(); 
            return frame;
        },

        monitor: function (fn, scope, args) {
            var frame = this.enter();
            if (args) {
                fn.apply(scope, args);
            } else {
                fn.call(scope);
            }
            frame.leave();
        },

        report: function () {
            Ext.log(this.format());
        },

        tap: function (className, methodName) {
            var me = this,
                methods = typeof methodName == 'string' ? [methodName] : methodName,
                klass, statik, i, parts, length, name, src,
                tapFunc;

            tapFunc = function(){
                if (typeof className == 'string') {
                    klass = Ext.global;
                    parts = className.split('.');
                    for (i = 0, length = parts.length; i < length; ++i) {
                        klass = klass[parts[i]];
                    }
                } else {
                    klass = className;
                }

                for (i = 0, length = methods.length; i < length; ++i) {
                    name = methods[i];
                    statik = name.charAt(0) == '!';

                    if (statik) {
                        name = name.substring(1);
                    } else {
                        statik = !(name in klass.prototype);
                    }

                    src = statik ? klass : klass.prototype;
                    src[name] = makeTap(me, src[name]);
                }
            };

            Ext.ClassManager.onCreated(tapFunc, me, className);

            return me;
        }
    };
}()),

function () {
    Ext.perf.getTimestamp = this.getTimestamp;
});


Ext.define('Ext.perf.Monitor', {
    singleton: true,
    alternateClassName: 'Ext.Perf',

    requires: [
        'Ext.perf.Accumulator'
    ],

    constructor: function () {
        this.accumulators = [];
        this.accumulatorsByName = {};
    },

    calibrate: function () {
        var accum = new Ext.perf.Accumulator('$'),
            total = accum.total,
            getTimestamp = Ext.perf.Accumulator.getTimestamp,
            count = 0,
            frame,
            endTime,
            startTime;

        startTime = getTimestamp();

        do {
            frame = accum.enter();
            frame.leave();
            ++count;
        } while (total.sum < 100);

        endTime = getTimestamp();

        return (endTime - startTime) / count;
    },

    get: function (name) {
        var me = this,
            accum = me.accumulatorsByName[name];

        if (!accum) {
            me.accumulatorsByName[name] = accum = new Ext.perf.Accumulator(name);
            me.accumulators.push(accum);
        }

        return accum;
    },

    enter: function (name) {
        return this.get(name).enter();
    },

    monitor: function (name, fn, scope) {
        this.get(name).monitor(fn, scope);
    },

    report: function () {
        var me = this,
            accumulators = me.accumulators,
            calibration = me.calibrate();

        accumulators.sort(function (a, b) {
            return (a.name < b.name) ? -1 : ((b.name < a.name) ? 1 : 0);
        });

        me.updateGC();

        Ext.log('Calibration: ' + Math.round(calibration * 100) / 100 + ' msec/sample');
        Ext.each(accumulators, function (accum) {
            Ext.log(accum.format(calibration));
        });
    },

    getData: function (all) {
        var ret = {},
            accumulators = this.accumulators;

        Ext.each(accumulators, function (accum) {
            if (all || accum.count) {
                ret[accum.name] = accum.getData();
            }
        });

        return ret;
    },

    reset: function(){
        Ext.each(this.accumulators, function(accum){
            var me = accum;
            me.count = me.childCount = me.depth = me.maxDepth = 0;
            me.pure = {
                min: Number.MAX_VALUE,
                max: 0,
                sum: 0
            };
            me.total = {
                min: Number.MAX_VALUE,
                max: 0,
                sum: 0
            };
        });
    },

    updateGC: function () {
        var accumGC = this.accumulatorsByName.GC,
            toolbox = Ext.senchaToolbox,
            bucket;

        if (accumGC) {
            accumGC.count = toolbox.garbageCollectionCounter || 0;

            if (accumGC.count) {
                bucket = accumGC.pure;
                accumGC.total.sum = bucket.sum = toolbox.garbageCollectionMilliseconds;
                bucket.min = bucket.max = bucket.sum / accumGC.count;
                bucket = accumGC.total;
                bucket.min = bucket.max = bucket.sum / accumGC.count;
            }
        }
    },

    watchGC: function () {
        Ext.perf.getTimestamp(); 

        var toolbox = Ext.senchaToolbox;

        if (toolbox) {
            this.get("GC");
            toolbox.watchGarbageCollector(false); 
        }
    },

    setup: function (config) {
        if (!config) {
            config = {
                
                






                render: {
                    'Ext.AbstractComponent': 'render'
                },

































                layout: {
                    'Ext.layout.Context': 'run'
                }
            };
        }

        this.currentConfig = config;

        var key, prop,
            accum, className, methods;
        for (key in config) {
            if (config.hasOwnProperty(key)) {
                prop = config[key];
                accum = Ext.Perf.get(key);

                for (className in prop) {
                    if (prop.hasOwnProperty(className)) {
                        methods = prop[className];
                        accum.tap(className, methods);
                    }
                }
            }
        }

        this.watchGC();
    }
});


Ext.is = {
    init : function(navigator) {
        var platforms = this.platforms,
            ln = platforms.length,
            i, platform;

        navigator = navigator || window.navigator;

        for (i = 0; i < ln; i++) {
            platform = platforms[i];
            this[platform.identity] = platform.regex.test(navigator[platform.property]);
        }

        
        this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
        
        this.Tablet = this.iPad;
        
        this.Phone = !this.Desktop && !this.Tablet;
        
        this.iOS = this.iPhone || this.iPad || this.iPod;
        
        
        this.Standalone = !!window.navigator.standalone;
    },
    
    
    platforms: [{
        property: 'platform',
        regex: /iPhone/i,
        identity: 'iPhone'
    },
    
    
    {
        property: 'platform',
        regex: /iPod/i,
        identity: 'iPod'
    },
    
    
    {
        property: 'userAgent',
        regex: /iPad/i,
        identity: 'iPad'
    },
    
    
    {
        property: 'userAgent',
        regex: /Blackberry/i,
        identity: 'Blackberry'
    },
    
    
    {
        property: 'userAgent',
        regex: /Android/i,
        identity: 'Android'
    },
    
    
    {
        property: 'platform',
        regex: /Mac/i,
        identity: 'Mac'
    },
    
    
    {
        property: 'platform',
        regex: /Win/i,
        identity: 'Windows'
    },
    
    
    {
        property: 'platform',
        regex: /Linux/i,
        identity: 'Linux'
    }]
};

Ext.is.init();


(function(){

    
    
    
    var getStyle = function(element, styleName){
        var view = element.ownerDocument.defaultView,
            style = (view ? view.getComputedStyle(element, null) : element.currentStyle) || element.style;
        return style[styleName];
    };

Ext.supports = {
    
    init : function() {
        var me = this,
            doc = document,
            tests = me.tests,
            n = tests.length,
            div = n && Ext.isReady && doc.createElement('div'),
            test, notRun = [];

        if (div) {
            div.innerHTML = [
                '<div style="height:30px;width:50px;">',
                    '<div style="height:20px;width:20px;"></div>',
                '</div>',
                '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
                    '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
                '</div>',
                '<div style="position: absolute; left: 10%; top: 10%;"></div>',
                '<div style="float:left; background-color:transparent;"></div>'
            ].join('');

            doc.body.appendChild(div);
        }

        while (n--) {
            test = tests[n];
            if (div || test.early) {
                me[test.identity] = test.fn.call(me, doc, div);
            } else {
                notRun.push(test);
            }
        }

        if (div) {
            doc.body.removeChild(div);
        }

        me.tests = notRun;
    },

    
    PointerEvents: 'pointerEvents' in document.documentElement.style,

    
    CSS3BoxShadow: 'boxShadow' in document.documentElement.style || 'WebkitBoxShadow' in document.documentElement.style || 'MozBoxShadow' in document.documentElement.style,

    
    ClassList: !!document.documentElement.classList,

    
    OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),

    
    DeviceMotion: ('ondevicemotion' in window),

    
    
    
    Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),

    
    TimeoutActualLateness: (function(){
        setTimeout(function(){
            Ext.supports.TimeoutActualLateness = arguments.length !== 0;
        }, 0);
    }()),

    tests: [
        
        {
            identity: 'Transitions',
            fn: function(doc, div) {
                var prefix = [
                        'webkit',
                        'Moz',
                        'o',
                        'ms',
                        'khtml'
                    ],
                    TE = 'TransitionEnd',
                    transitionEndName = [
                        prefix[0] + TE,
                        'transitionend', 
                        prefix[2] + TE,
                        prefix[3] + TE,
                        prefix[4] + TE
                    ],
                    ln = prefix.length,
                    i = 0,
                    out = false;

                for (; i < ln; i++) {
                    if (getStyle(div, prefix[i] + "TransitionProperty")) {
                        Ext.supports.CSS3Prefix = prefix[i];
                        Ext.supports.CSS3TransitionEnd = transitionEndName[i];
                        out = true;
                        break;
                    }
                }
                return out;
            }
        },

        
        {
            identity: 'RightMargin',
            fn: function(doc, div) {
                var view = doc.defaultView;
                return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
            }
        },

        
        {
            identity: 'DisplayChangeInputSelectionBug',
            early: true,
            fn: function() {
                var webKitVersion = Ext.webKitVersion;
                
                return 0 < webKitVersion && webKitVersion < 533;
            }
        },

        
        {
            identity: 'DisplayChangeTextAreaSelectionBug',
            early: true,
            fn: function() {
                var webKitVersion = Ext.webKitVersion;

                
                return 0 < webKitVersion && webKitVersion < 534.24;
            }
        },

        
        {
            identity: 'TransparentColor',
            fn: function(doc, div, view) {
                view = doc.defaultView;
                return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
            }
        },

        
        {
            identity: 'ComputedStyle',
            fn: function(doc, div, view) {
                view = doc.defaultView;
                return view && view.getComputedStyle;
            }
        },

        
        {
            identity: 'Svg',
            fn: function(doc) {
                return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
            }
        },

        
        {
            identity: 'Canvas',
            fn: function(doc) {
                return !!doc.createElement('canvas').getContext;
            }
        },

        
        {
            identity: 'Vml',
            fn: function(doc) {
                var d = doc.createElement("div");
                d.innerHTML = "<!--[if vml]><br/><br/><![endif]-->";
                return (d.childNodes.length == 2);
            }
        },

        
        {
            identity: 'Float',
            fn: function(doc, div) {
                return !!div.lastChild.style.cssFloat;
            }
        },

        
        {
            identity: 'AudioTag',
            fn: function(doc) {
                return !!doc.createElement('audio').canPlayType;
            }
        },

        
        {
            identity: 'History',
            fn: function() {
                var history = window.history;
                return !!(history && history.pushState);
            }
        },

        
        {
            identity: 'CSS3DTransform',
            fn: function() {
                return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
            }
        },

		
        {
            identity: 'CSS3LinearGradient',
            fn: function(doc, div) {
                var property = 'background-image:',
                    webkit   = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
                    w3c      = 'linear-gradient(left top, black, white)',
                    moz      = '-moz-' + w3c,
                    opera    = '-o-' + w3c,
                    options  = [property + webkit, property + w3c, property + moz, property + opera];

                div.style.cssText = options.join(';');

                return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
            }
        },

        
        {
            identity: 'CSS3BorderRadius',
            fn: function(doc, div) {
                var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
                    pass = false,
                    i;
                for (i = 0; i < domPrefixes.length; i++) {
                    if (document.body.style[domPrefixes[i]] !== undefined) {
                        return true;
                    }
                }
                return pass;
            }
        },

        
        {
            identity: 'GeoLocation',
            fn: function() {
                return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
            }
        },
        
        {
            identity: 'MouseEnterLeave',
            fn: function(doc, div){
                return ('onmouseenter' in div && 'onmouseleave' in div);
            }
        },
        
        {
            identity: 'MouseWheel',
            fn: function(doc, div) {
                return ('onmousewheel' in div);
            }
        },
        
        {
            identity: 'Opacity',
            fn: function(doc, div){
                
                if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
                    return false;
                }
                div.firstChild.style.cssText = 'opacity:0.73';
                return div.firstChild.style.opacity == '0.73';
            }
        },
        
        {
            identity: 'Placeholder',
            fn: function(doc) {
                return 'placeholder' in doc.createElement('input');
            }
        },

        
        {
            identity: 'Direct2DBug',
            fn: function() {
                return Ext.isString(document.body.style.msTransformOrigin);
            }
        },
        
        {
            identity: 'BoundingClientRect',
            fn: function(doc, div) {
                return Ext.isFunction(div.getBoundingClientRect);
            }
        },
        {
            identity: 'IncludePaddingInWidthCalculation',
            fn: function(doc, div){
                return div.childNodes[1].firstChild.offsetWidth == 210;
            }
        },
        {
            identity: 'IncludePaddingInHeightCalculation',
            fn: function(doc, div){
                return div.childNodes[1].firstChild.offsetHeight == 210;
            }
        },

        
        {
            identity: 'ArraySort',
            fn: function() {
                var a = [1,2,3,4,5].sort(function(){ return 0; });
                return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
            }
        },
        
        {
            identity: 'Range',
            fn: function() {
                return !!document.createRange;
            }
        },
        
        {
            identity: 'CreateContextualFragment',
            fn: function() {
                var range = Ext.supports.Range ? document.createRange() : false;

                return range && !!range.createContextualFragment;
            }
        },

        
        {
            identity: 'WindowOnError',
            fn: function () {
                
                return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; 
            }
        },

        
        {
            identity: 'TextAreaMaxLength',
            fn: function(){
                var el = document.createElement('textarea');
                return ('maxlength' in el);
            }
        },
        
        
        {
            identity: 'GetPositionPercentage',
            fn: function(doc, div){
               return getStyle(div.childNodes[2], 'left') == '10%';
            }
        }
    ]
};
}());

Ext.supports.init(); 



Ext.util.DelayedTask = function(fn, scope, args) {
    var me = this,
        id,
        call = function() {
            clearInterval(id);
            id = null;
            fn.apply(scope, args || []);
        };

    
    this.delay = function(delay, newFn, newScope, newArgs) {
        me.cancel();
        fn = newFn || fn;
        scope = newScope || scope;
        args = newArgs || args;
        id = setInterval(call, delay);
    };

    
    this.cancel = function(){
        if (id) {
            clearInterval(id);
            id = null;
        }
    };
};
Ext.require('Ext.util.DelayedTask', function() {

    
    Ext.util.Event = Ext.extend(Object, (function() {
        var noOptions = {};

        function createTargeted(handler, listener, o, scope){
            return function(){
                if (o.target === arguments[0]){
                    handler.apply(scope, arguments);
                }
            };
        }

        function createBuffered(handler, listener, o, scope) {
            listener.task = new Ext.util.DelayedTask();
            return function() {
                listener.task.delay(o.buffer, handler, scope, Ext.Array.toArray(arguments));
            };
        }

        function createDelayed(handler, listener, o, scope) {
            return function() {
                var task = new Ext.util.DelayedTask();
                if (!listener.tasks) {
                    listener.tasks = [];
                }
                listener.tasks.push(task);
                task.delay(o.delay || 10, handler, scope, Ext.Array.toArray(arguments));
            };
        }

        function createSingle(handler, listener, o, scope) {
            return function() {
                var event = listener.ev;

                if (event.removeListener(listener.fn, scope) && event.observable) {
                    
                    
                    event.observable.hasListeners[event.name]--;
                }

                return handler.apply(scope, arguments);
            };
        }

        return {
            
            isEvent: true,

            constructor: function(observable, name) {
                this.name = name;
                this.observable = observable;
                this.listeners = [];
            },

            addListener: function(fn, scope, options) {
                var me = this,
                    listener;
                    scope = scope || me.observable;


                if (!me.isListening(fn, scope)) {
                    listener = me.createListener(fn, scope, options);
                    if (me.firing) {
                        
                        me.listeners = me.listeners.slice(0);
                    }
                    me.listeners.push(listener);
                }
            },

            createListener: function(fn, scope, options) {
                options = options || noOptions;
                scope = scope || this.observable;

                var listener = {
                        fn: fn,
                        scope: scope,
                        o: options,
                        ev: this
                    },
                    handler = fn;

                
                
                if (options.single) {
                    handler = createSingle(handler, listener, options, scope);
                }
                if (options.target) {
                    handler = createTargeted(handler, listener, options, scope);
                }
                if (options.delay) {
                    handler = createDelayed(handler, listener, options, scope);
                }
                if (options.buffer) {
                    handler = createBuffered(handler, listener, options, scope);
                }

                listener.fireFn = handler;
                return listener;
            },

            findListener: function(fn, scope) {
                var listeners = this.listeners,
                i = listeners.length,
                listener,
                s;

                while (i--) {
                    listener = listeners[i];
                    if (listener) {
                        s = listener.scope;

                        
                        
                        
                        if (listener.fn == fn && (s == (scope || this.observable))) {
                            return i;
                        }
                    }
                }

                return - 1;
            },

            isListening: function(fn, scope) {
                return this.findListener(fn, scope) !== -1;
            },

            removeListener: function(fn, scope) {
                var me = this,
                    index,
                    listener,
                    k;
                index = me.findListener(fn, scope);
                if (index != -1) {
                    listener = me.listeners[index];

                    if (me.firing) {
                        me.listeners = me.listeners.slice(0);
                    }

                    
                    if (listener.task) {
                        listener.task.cancel();
                        delete listener.task;
                    }

                    
                    k = listener.tasks && listener.tasks.length;
                    if (k) {
                        while (k--) {
                            listener.tasks[k].cancel();
                        }
                        delete listener.tasks;
                    }

                    
                    Ext.Array.erase(me.listeners, index, 1);
                    return true;
                }

                return false;
            },

            
            clearListeners: function() {
                var listeners = this.listeners,
                    i = listeners.length;

                while (i--) {
                    this.removeListener(listeners[i].fn, listeners[i].scope);
                }
            },

            fire: function() {
                var me = this,
                    listeners = me.listeners,
                    count = listeners.length,
                    i,
                    args,
                    listener;

                if (count > 0) {
                    me.firing = true;
                    for (i = 0; i < count; i++) {
                        listener = listeners[i];
                        args = arguments.length ? Array.prototype.slice.call(arguments, 0) : [];
                        if (listener.o) {
                            args.push(listener.o);
                        }
                        if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
                            return (me.firing = false);
                        }
                    }
                }
                me.firing = false;
                return true;
            }
        };
    }()));
});


Ext.EventManager = new function() {
    var EventManager = this,
        doc = document,
        win = window,
        initExtCss = function() {
            
            var bd = doc.body || doc.getElementsByTagName('body')[0],
                baseCSSPrefix = Ext.baseCSSPrefix,
                cls = [baseCSSPrefix + 'body'],
                htmlCls = [],
                supportsLG = Ext.supports.CSS3LinearGradient,
                supportsBR = Ext.supports.CSS3BorderRadius,
                resetCls = [],
                html,
                resetElementSpec;

            if (!bd) {
                return false;
            }

            html = bd.parentNode;

            function add (c) {
                cls.push(baseCSSPrefix + c);
            }

            
            if (Ext.isIE) {
                add('ie');

                
                
                
                
                
                
                
                
                
                
                
                if (Ext.isIE6) {
                    add('ie6');
                } else { 
                    add('ie7p');

                    if (Ext.isIE7) {
                        add('ie7');
                    } else {
                        add('ie8p');

                        if (Ext.isIE8) {
                            add('ie8');
                        } else {
                            add('ie9p');

                            if (Ext.isIE9) {
                                add('ie9');
                            }
                        }
                    }
                }

                if (Ext.isIE6 || Ext.isIE7) {
                    add('ie7m');
                }
                if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
                    add('ie8m');
                }
                if (Ext.isIE7 || Ext.isIE8) {
                    add('ie78');
                }
            }
            if (Ext.isGecko) {
                add('gecko');
                if (Ext.isGecko3) {
                    add('gecko3');
                }
                if (Ext.isGecko4) {
                    add('gecko4');
                }
                if (Ext.isGecko5) {
                    add('gecko5');
                }
            }
            if (Ext.isOpera) {
                add('opera');
            }
            if (Ext.isWebKit) {
                add('webkit');
            }
            if (Ext.isSafari) {
                add('safari');
                if (Ext.isSafari2) {
                    add('safari2');
                }
                if (Ext.isSafari3) {
                    add('safari3');
                }
                if (Ext.isSafari4) {
                    add('safari4');
                }
                if (Ext.isSafari5) {
                    add('safari5');
                }
                if (Ext.isSafari5_0) {
                    add('safari5_0')
                }
            }
            if (Ext.isChrome) {
                add('chrome');
            }
            if (Ext.isMac) {
                add('mac');
            }
            if (Ext.isLinux) {
                add('linux');
            }
            if (!supportsBR) {
                add('nbr');
            }
            if (!supportsLG) {
                add('nlg');
            }

            
            
            
            if (Ext.scopeResetCSS) {

                
                resetElementSpec = Ext.resetElementSpec = {
                    cls: baseCSSPrefix + 'reset'
                };
                
                if (!supportsLG) {
                    resetCls.push(baseCSSPrefix + 'nlg');
                }
                
                if (!supportsBR) {
                    resetCls.push(baseCSSPrefix + 'nbr');
                }
                
                if (resetCls.length) {                    
                    resetElementSpec.cn = {
                        cls: resetCls.join(' ')
                    };
                }
                
                Ext.resetElement = Ext.getBody().createChild(resetElementSpec);
                if (resetCls.length) {
                    Ext.resetElement = Ext.get(Ext.resetElement.dom.firstChild);
                }
            }
            
            else {
                Ext.resetElement = Ext.getBody();
                add('reset');
            }

            
            if (html) {
                if (Ext.isStrict && (Ext.isIE6 || Ext.isIE7)) {
                    Ext.isBorderBox = false;
                }
                else {
                    Ext.isBorderBox = true;
                }

                if(Ext.isBorderBox) {
                    htmlCls.push(baseCSSPrefix + 'border-box');
                }
                if (Ext.isStrict) {
                    htmlCls.push(baseCSSPrefix + 'strict');
                } else {
                    htmlCls.push(baseCSSPrefix + 'quirks');
                }
                Ext.fly(html, '_internal').addCls(htmlCls);
            }

            Ext.fly(bd, '_internal').addCls(cls);
            return true;
        };

    Ext.apply(EventManager, {
        
        hasBoundOnReady: false,

        
        hasFiredReady: false,

        
        deferReadyEvent : 1,

        
        onReadyChain : [],

        
        readyEvent:
            (function () {
                var event = new Ext.util.Event();
                event.fire = function () {
                    Ext._beforeReadyTime = Ext._beforeReadyTime || new Date().getTime();
                    event.self.prototype.fire.apply(event, arguments);
                    Ext._afterReadytime = new Date().getTime();
                };
                return event;
            }()),

        
        idleEvent: new Ext.util.Event(),

        
        isReadyPaused: function(){
            return (/[?&]ext-pauseReadyFire\b/i.test(location.search) && !Ext._continueFireReady);
        },

        
        bindReadyEvent: function() {
            if (EventManager.hasBoundOnReady) {
                return;
            }

            
            if ( doc.readyState == 'complete'  ) {  
                EventManager.onReadyEvent({
                    type: doc.readyState || 'body'
                });
            } else {
                document.addEventListener('DOMContentLoaded', EventManager.onReadyEvent, false);
                window.addEventListener('load', EventManager.onReadyEvent, false);
                EventManager.hasBoundOnReady = true;
            }
        },

        onReadyEvent : function(e) {
            if (e && e.type) {
                EventManager.onReadyChain.push(e.type);
            }

            if (EventManager.hasBoundOnReady) {
                document.removeEventListener('DOMContentLoaded', EventManager.onReadyEvent, false);
                window.removeEventListener('load', EventManager.onReadyEvent, false);
            }

            if (!Ext.isReady) {
                EventManager.fireDocReady();
            }
        },

        
        fireDocReady: function() {
            if (!Ext.isReady) {
                Ext._readyTime = new Date().getTime();
                Ext.isReady = true;

                Ext.supports.init();
                EventManager.onWindowUnload();
                EventManager.readyEvent.onReadyChain = EventManager.onReadyChain;    

                if (Ext.isNumber(EventManager.deferReadyEvent)) {
                    Ext.Function.defer(EventManager.fireReadyEvent, EventManager.deferReadyEvent);
                    EventManager.hasDocReadyTimer = true;
                } else {
                    EventManager.fireReadyEvent();
                }
            }
        },

        
        fireReadyEvent: function(){
            var readyEvent = EventManager.readyEvent;

            
            
            EventManager.hasDocReadyTimer = false;
            EventManager.isFiring = true;

            
            
            
            while (readyEvent.listeners.length && !EventManager.isReadyPaused()) {
                readyEvent.fire();
            }
            EventManager.isFiring = false;
            EventManager.hasFiredReady = true;
        },

        
        onDocumentReady: function(fn, scope, options) {
            options = options || {};
            
            options.single = true;
            EventManager.readyEvent.addListener(fn, scope, options);

            
            
            if (!(EventManager.isFiring || EventManager.hasDocReadyTimer)) {
                if (Ext.isReady) {
                    EventManager.fireReadyEvent();
                } else {
                    EventManager.bindReadyEvent();
                }
            }
        },

        

        
        stoppedMouseDownEvent: new Ext.util.Event(),

        
        propRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|freezeEvent)$/,

        
        getId : function(element) {
            var id;

            element = Ext.getDom(element);

            if (element === doc || element === win) {
                id = element === doc ? Ext.documentId : Ext.windowId;
            }
            else {
                id = Ext.id(element);
            }

            if (!Ext.cache[id]) {
                Ext.addCacheEntry(id, null, element);
            }

            return id;
        },

        
        prepareListenerConfig: function(element, config, isRemove) {
            var propRe = EventManager.propRe,
                key, value, args;

            
            for (key in config) {
                if (config.hasOwnProperty(key)) {
                    
                    if (!propRe.test(key)) {
                        value = config[key];
                        
                        
                        if (typeof value == 'function') {
                            
                            args = [element, key, value, config.scope, config];
                        } else {
                            
                            args = [element, key, value.fn, value.scope, value];
                        }

                        if (isRemove) {
                            EventManager.removeListener.apply(EventManager, args);
                        } else {
                            EventManager.addListener.apply(EventManager, args);
                        }
                    }
                }
            }
        },

        mouseEnterLeaveRe: /mouseenter|mouseleave/,

        
        normalizeEvent: function(eventName, fn) {
            if (EventManager.mouseEnterLeaveRe.test(eventName) && !Ext.supports.MouseEnterLeave) {
                if (fn) {
                    fn = Ext.Function.createInterceptor(fn, EventManager.contains);
                }
                eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
            } else if (eventName == 'mousewheel' && !Ext.supports.MouseWheel && !Ext.isOpera) {
                eventName = 'DOMMouseScroll';
            }
            return {
                eventName: eventName,
                fn: fn
            };
        },

        
        contains: function(event) {
            var parent = event.browserEvent.currentTarget,
                child = EventManager.getRelatedTarget(event);

            if (parent && parent.firstChild) {
                while (child) {
                    if (child === parent) {
                        return false;
                    }
                    child = child.parentNode;
                    if (child && (child.nodeType != 1)) {
                        child = null;
                    }
                }
            }
            return true;
        },

        
        addListener: function(element, eventName, fn, scope, options) {
            
            if (typeof eventName !== 'string') {
                EventManager.prepareListenerConfig(element, eventName);
                return;
            }

            var dom = element.dom || Ext.getDom(element),
                bind, wrap;


            
            options = options || {};

            bind = EventManager.normalizeEvent(eventName, fn);
            wrap = EventManager.createListenerWrap(dom, eventName, bind.fn, scope, options);

            if (dom.attachEvent) {
                dom.attachEvent('on' + bind.eventName, wrap);
            } else {
                dom.addEventListener(bind.eventName, wrap, options.capture || false);
            }

            if (dom == doc && eventName == 'mousedown') {
                EventManager.stoppedMouseDownEvent.addListener(wrap);
            }

            
            EventManager.getEventListenerCache(element.dom ? element : dom, eventName).push({
                fn: fn,
                wrap: wrap,
                scope: scope
            });
        },

        
        removeListener : function(element, eventName, fn, scope) {
            
            if (typeof eventName !== 'string') {
                EventManager.prepareListenerConfig(element, eventName, true);
                return;
            }

            var dom = Ext.getDom(element),
                el = element.dom ? element : Ext.get(dom),
                cache = EventManager.getEventListenerCache(el, eventName),
                bindName = EventManager.normalizeEvent(eventName).eventName,
                i = cache.length, j,
                listener, wrap, tasks;


            while (i--) {
                listener = cache[i];

                if (listener && (!fn || listener.fn == fn) && (!scope || listener.scope === scope)) {
                    wrap = listener.wrap;

                    
                    if (wrap.task) {
                        clearTimeout(wrap.task);
                        delete wrap.task;
                    }

                    
                    j = wrap.tasks && wrap.tasks.length;
                    if (j) {
                        while (j--) {
                            clearTimeout(wrap.tasks[j]);
                        }
                        delete wrap.tasks;
                    }

                    if (dom.detachEvent) {
                        dom.detachEvent('on' + bindName, wrap);
                    } else {
                        dom.removeEventListener(bindName, wrap, false);
                    }

                    if (wrap && dom == doc && eventName == 'mousedown') {
                        EventManager.stoppedMouseDownEvent.removeListener(wrap);
                    }

                    
                    Ext.Array.erase(cache, i, 1);
                }
            }
        },

        
        removeAll : function(element) {
            var el = element.dom ? element : Ext.get(element),
                cache, events, eventName;

            if (!el) {
                return;
            }
            cache = (el.$cache || el.getCache());
            events = cache.events;

            for (eventName in events) {
                if (events.hasOwnProperty(eventName)) {
                    EventManager.removeListener(el, eventName);
                }
            }
            cache.events = {};
        },

        
        purgeElement : function(element, eventName) {
            var dom = Ext.getDom(element),
                i = 0, len;

            if (eventName) {
                EventManager.removeListener(element, eventName);
            }
            else {
                EventManager.removeAll(element);
            }

            if (dom && dom.childNodes) {
                for (len = element.childNodes.length; i < len; i++) {
                    EventManager.purgeElement(element.childNodes[i], eventName);
                }
            }
        },

        
        createListenerWrap : function(dom, ename, fn, scope, options) {
            options = options || {};

            var f, gen, escapeRx = /\\/g, wrap = function(e, args) {
                
                if (!gen) {
                    f = ['if(!' + Ext.name + ') {return;}'];

                    if(options.buffer || options.delay || options.freezeEvent) {
                        f.push('e = new X.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
                    } else {
                        f.push('e = X.EventObject.setEvent(e);');
                    }

                    if (options.delegate) {
                        
                        
                        f.push('var result, t = e.getTarget("' + (options.delegate + '').replace(escapeRx, '\\\\') + '", this);');
                        f.push('if(!t) {return;}');
                    } else {
                        f.push('var t = e.target, result;');
                    }

                    if (options.target) {
                        f.push('if(e.target !== options.target) {return;}');
                    }

                    if(options.stopEvent) {
                        f.push('e.stopEvent();');
                    } else {
                        if(options.preventDefault) {
                            f.push('e.preventDefault();');
                        }
                        if(options.stopPropagation) {
                            f.push('e.stopPropagation();');
                        }
                    }

                    if(options.normalized === false) {
                        f.push('e = e.browserEvent;');
                    }

                    if(options.buffer) {
                        f.push('(wrap.task && clearTimeout(wrap.task));');
                        f.push('wrap.task = setTimeout(function() {');
                    }

                    if(options.delay) {
                        f.push('wrap.tasks = wrap.tasks || [];');
                        f.push('wrap.tasks.push(setTimeout(function() {');
                    }

                    
                    f.push('result = fn.call(scope || dom, e, t, options);');

                    if(options.single) {
                        f.push('evtMgr.removeListener(dom, ename, fn, scope);');
                    }

                    
                    
                    if (ename !== 'mousemove') {
                        f.push('if (evtMgr.idleEvent.listeners.length) {');
                        f.push('evtMgr.idleEvent.fire();');
                        f.push('}');
                    }

                    if(options.delay) {
                        f.push('}, ' + options.delay + '));');
                    }

                    if(options.buffer) {
                        f.push('}, ' + options.buffer + ');');
                    }
                    f.push('return result;')

                    gen = Ext.cacheableFunctionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', 'X', 'evtMgr', f.join('\n'));
                }

                return gen.call(dom, e, options, fn, scope, ename, dom, wrap, args, Ext, EventManager);
            };
            return wrap;
        },

        
        getEventListenerCache : function(element, eventName) {
            var elementCache, eventCache;
            if (!element) {
                return [];
            }

            if (element.$cache) {
                elementCache = element.$cache;
            } else {
                
                elementCache = Ext.cache[EventManager.getId(element)];
            }
            eventCache = elementCache.events || (elementCache.events = {});

            return eventCache[eventName] || (eventCache[eventName] = []);
        },

        
        mouseLeaveRe: /(mouseout|mouseleave)/,
        mouseEnterRe: /(mouseover|mouseenter)/,

        
        stopEvent: function(event) {
            EventManager.stopPropagation(event);
            EventManager.preventDefault(event);
        },

        
        stopPropagation: function(event) {
            event = event.browserEvent || event;
            if (event.stopPropagation) {
                event.stopPropagation();
            } else {
                event.cancelBubble = true;
            }
        },

        
        preventDefault: function(event) {
            event = event.browserEvent || event;
            if (event.preventDefault) {
                event.preventDefault();
            } else {
                event.returnValue = false;
                
                try {
                  
                  if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
                      event.keyCode = -1;
                  }
                } catch (e) {
                    
                }
            }
        },

        
        getRelatedTarget: function(event) {
            event = event.browserEvent || event;
            var target = event.relatedTarget;
            if (!target) {
                if (EventManager.mouseLeaveRe.test(event.type)) {
                    target = event.toElement;
                } else if (EventManager.mouseEnterRe.test(event.type)) {
                    target = event.fromElement;
                }
            }
            return EventManager.resolveTextNode(target);
        },

        
        getPageX: function(event) {
            return EventManager.getPageXY(event)[0];
        },

        
        getPageY: function(event) {
            return EventManager.getPageXY(event)[1];
        },

        
        getPageXY: function(event) {
            event = event.browserEvent || event;
            var x = event.pageX,
                y = event.pageY,
                docEl = doc.documentElement,
                body = doc.body;

            
            if (!x && x !== 0) {
                x = event.clientX + (docEl && docEl.scrollLeft || body && body.scrollLeft || 0) - (docEl && docEl.clientLeft || body && body.clientLeft || 0);
                y = event.clientY + (docEl && docEl.scrollTop  || body && body.scrollTop  || 0) - (docEl && docEl.clientTop  || body && body.clientTop  || 0);
            }
            return [x, y];
        },

        
        getTarget: function(event) {
            event = event.browserEvent || event;
            return EventManager.resolveTextNode(event.target || event.srcElement);
        },

        
        
        
        
        resolveTextNode: Ext.isGecko ?
            function(node) {
                if (!node) {
                    return;
                }
                
                var s = HTMLElement.prototype.toString.call(node);
                if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') {
                    return;
                }
                    return node.nodeType == 3 ? node.parentNode: node;
                }: function(node) {
                    return node && node.nodeType == 3 ? node.parentNode: node;
                },

        

        
        curWidth: 0,
        curHeight: 0,

        
        onWindowResize: function(fn, scope, options) {
            var resize = EventManager.resizeEvent;

            if (!resize) {
                EventManager.resizeEvent = resize = new Ext.util.Event();
                EventManager.on(win, 'resize', EventManager.fireResize, null, {buffer: 100});
            }
            resize.addListener(fn, scope, options);
        },

        
        fireResize: function() {
            var w = Ext.Element.getViewWidth(),
                h = Ext.Element.getViewHeight();

             
             if (EventManager.curHeight != h || EventManager.curWidth != w) {
                 EventManager.curHeight = h;
                 EventManager.curWidth = w;
                 EventManager.resizeEvent.fire(w, h);
             }
        },

        
        removeResizeListener: function(fn, scope) {
            var resize = EventManager.resizeEvent;
            if (resize) {
                resize.removeListener(fn, scope);
            }
        },

        
        onWindowUnload: function(fn, scope, options) {
            var unload = EventManager.unloadEvent;

            if (!unload) {
                EventManager.unloadEvent = unload = new Ext.util.Event();
                EventManager.addListener(win, 'unload', EventManager.fireUnload);
            }
            if (fn) {
                unload.addListener(fn, scope, options);
            }
        },

        
        fireUnload: function() {
            
            try {
                
                doc = win = undefined;

                var gridviews, i, ln,
                    el, cache;

                EventManager.unloadEvent.fire();
                
                if (Ext.isGecko3) {
                    gridviews = Ext.ComponentQuery.query('gridview');
                    i = 0;
                    ln = gridviews.length;
                    for (; i < ln; i++) {
                        gridviews[i].scrollToTop();
                    }
                }
                
                cache = Ext.cache;

                for (el in cache) {
                    if (cache.hasOwnProperty(el)) {
                        EventManager.removeAll(el);
                    }
                }
            } catch(e) {
            }
        },

        
        removeUnloadListener: function(fn, scope) {
            var unload = EventManager.unloadEvent;
            if (unload) {
                unload.removeListener(fn, scope);
            }
        },

        
        useKeyDown: Ext.isWebKit ?
                       parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) >= 525 :
                       !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera),

        
        getKeyEvent: function() {
            return EventManager.useKeyDown ? 'keydown' : 'keypress';
        }
    });

    
    if(!('addEventListener' in document) && document.attachEvent) {
        Ext.apply( EventManager, {
            

            
            pollScroll : function() {
                var scrollable = true;

                try {
                    document.documentElement.doScroll('left');
                } catch(e) {
                    scrollable = false;
                }

                
                if (scrollable && document.body) {
                    EventManager.onReadyEvent({
                        type:'doScroll'
                    });
                } else {
                    
                    EventManager.scrollTimeout = setTimeout(EventManager.pollScroll, 20);
                }

                return scrollable;
            },

            
            scrollTimeout: null,

            
            readyStatesRe  : /complete/i,

            
            checkReadyState: function() {
                var state = document.readyState;

                if (EventManager.readyStatesRe.test(state)) {
                    EventManager.onReadyEvent({
                        type: state
                    });
                }
            },

            bindReadyEvent: function() {
                var topContext = true;

                if (EventManager.hasBoundOnReady) {
                    return;
                }

                
                try {
                    topContext = window.frameElement === undefined;
                } catch(e) {
                    
                    
                    topContext = false;
                }

                if (!topContext || !doc.documentElement.doScroll) {
                    EventManager.pollScroll = Ext.emptyFn;   
                }

                
                if (EventManager.pollScroll() === true) {
                    return;
                }

                
                if (doc.readyState == 'complete' )  {
                    EventManager.onReadyEvent({type: 'already ' + (doc.readyState || 'body') });
                } else {
                    doc.attachEvent('onreadystatechange', EventManager.checkReadyState);
                    window.attachEvent('onload', EventManager.onReadyEvent);
                    EventManager.hasBoundOnReady = true;
                }
            },

            onReadyEvent : function(e) {
                if (e && e.type) {
                    EventManager.onReadyChain.push(e.type);
                }

                if (EventManager.hasBoundOnReady) {
                    document.detachEvent('onreadystatechange', EventManager.checkReadyState);
                    window.detachEvent('onload', EventManager.onReadyEvent);
                }

                if (Ext.isNumber(EventManager.scrollTimeout)) {
                    clearTimeout(EventManager.scrollTimeout);
                    delete EventManager.scrollTimeout;
                }

                if (!Ext.isReady) {
                    EventManager.fireDocReady();
                }
            },

            
            onReadyChain : []
        });
    }


    
    Ext.onReady = function(fn, scope, options) {
        Ext.Loader.onReady(fn, scope, true, options);
    };

    
    Ext.onDocumentReady = EventManager.onDocumentReady;

    
    EventManager.on = EventManager.addListener;

    
    EventManager.un = EventManager.removeListener;

    Ext.onReady(initExtCss);
};


Ext.define('Ext.EventObjectImpl', {
    uses: ['Ext.util.Point'],

    
    BACKSPACE: 8,
    
    TAB: 9,
    
    NUM_CENTER: 12,
    
    ENTER: 13,
    
    RETURN: 13,
    
    SHIFT: 16,
    
    CTRL: 17,
    
    ALT: 18,
    
    PAUSE: 19,
    
    CAPS_LOCK: 20,
    
    ESC: 27,
    
    SPACE: 32,
    
    PAGE_UP: 33,
    
    PAGE_DOWN: 34,
    
    END: 35,
    
    HOME: 36,
    
    LEFT: 37,
    
    UP: 38,
    
    RIGHT: 39,
    
    DOWN: 40,
    
    PRINT_SCREEN: 44,
    
    INSERT: 45,
    
    DELETE: 46,
    
    ZERO: 48,
    
    ONE: 49,
    
    TWO: 50,
    
    THREE: 51,
    
    FOUR: 52,
    
    FIVE: 53,
    
    SIX: 54,
    
    SEVEN: 55,
    
    EIGHT: 56,
    
    NINE: 57,
    
    A: 65,
    
    B: 66,
    
    C: 67,
    
    D: 68,
    
    E: 69,
    
    F: 70,
    
    G: 71,
    
    H: 72,
    
    I: 73,
    
    J: 74,
    
    K: 75,
    
    L: 76,
    
    M: 77,
    
    N: 78,
    
    O: 79,
    
    P: 80,
    
    Q: 81,
    
    R: 82,
    
    S: 83,
    
    T: 84,
    
    U: 85,
    
    V: 86,
    
    W: 87,
    
    X: 88,
    
    Y: 89,
    
    Z: 90,
    
    CONTEXT_MENU: 93,
    
    NUM_ZERO: 96,
    
    NUM_ONE: 97,
    
    NUM_TWO: 98,
    
    NUM_THREE: 99,
    
    NUM_FOUR: 100,
    
    NUM_FIVE: 101,
    
    NUM_SIX: 102,
    
    NUM_SEVEN: 103,
    
    NUM_EIGHT: 104,
    
    NUM_NINE: 105,
    
    NUM_MULTIPLY: 106,
    
    NUM_PLUS: 107,
    
    NUM_MINUS: 109,
    
    NUM_PERIOD: 110,
    
    NUM_DIVISION: 111,
    
    F1: 112,
    
    F2: 113,
    
    F3: 114,
    
    F4: 115,
    
    F5: 116,
    
    F6: 117,
    
    F7: 118,
    
    F8: 119,
    
    F9: 120,
    
    F10: 121,
    
    F11: 122,
    
    F12: 123,
    
    WHEEL_SCALE: (function () {
        var scale;

        if (Ext.isGecko) {
            
            scale = 3;
        } else if (Ext.isMac) {
            
            
            

            if (Ext.isSafari && Ext.webKitVersion >= 532.0) {
                
                
                
                
                
                
                scale = 120;
            } else {
                
                
                scale = 12;
            }

            
            
            
            
            scale *= 3;
        } else {
            
            scale = 120;
        }

        return scale;
    }()),

    
    clickRe: /(dbl)?click/,
    
    safariKeys: {
        3: 13, 
        63234: 37, 
        63235: 39, 
        63232: 38, 
        63233: 40, 
        63276: 33, 
        63277: 34, 
        63272: 46, 
        63273: 36, 
        63275: 35 
    },
    
    btnMap: Ext.isIE ? {
        1: 0,
        4: 1,
        2: 2
    } : {
        0: 0,
        1: 1,
        2: 2
    },
    
    
    
    

    constructor: function(event, freezeEvent){
        if (event) {
            this.setEvent(event.browserEvent || event, freezeEvent);
        }
    },

    setEvent: function(event, freezeEvent){
        var me = this, button, options;

        if (event == me || (event && event.browserEvent)) { 
            return event;
        }
        me.browserEvent = event;
        if (event) {
            
            button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
            if (me.clickRe.test(event.type) && button == -1) {
                button = 0;
            }
            options = {
                type: event.type,
                button: button,
                shiftKey: event.shiftKey,
                
                ctrlKey: event.ctrlKey || event.metaKey || false,
                altKey: event.altKey,
                
                keyCode: event.keyCode,
                charCode: event.charCode,
                
                target: Ext.EventManager.getTarget(event),
                relatedTarget: Ext.EventManager.getRelatedTarget(event),
                currentTarget: event.currentTarget,
                xy: (freezeEvent ? me.getXY() : null)
            };
        } else {
            options = {
                button: -1,
                shiftKey: false,
                ctrlKey: false,
                altKey: false,
                keyCode: 0,
                charCode: 0,
                target: null,
                xy: [0, 0]
            };
        }
        Ext.apply(me, options);
        return me;
    },

    
    stopEvent: function(){
        this.stopPropagation();
        this.preventDefault();
    },

    
    preventDefault: function(){
        if (this.browserEvent) {
            Ext.EventManager.preventDefault(this.browserEvent);
        }
    },

    
    stopPropagation: function(){
        var browserEvent = this.browserEvent;

        if (browserEvent) {
            if (browserEvent.type == 'mousedown') {
                Ext.EventManager.stoppedMouseDownEvent.fire(this);
            }
            Ext.EventManager.stopPropagation(browserEvent);
        }
    },

    
    getCharCode: function(){
        return this.charCode || this.keyCode;
    },

    
    getKey: function(){
        return this.normalizeKey(this.keyCode || this.charCode);
    },

    
    normalizeKey: function(key){
        
        return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
    },

    
    getPageX: function(){
        return this.getX();
    },

    
    getPageY: function(){
        return this.getY();
    },

    
    getX: function() {
        return this.getXY()[0];
    },

    
    getY: function() {
        return this.getXY()[1];
    },

    
    getXY: function() {
        if (!this.xy) {
            
            this.xy = Ext.EventManager.getPageXY(this.browserEvent);
        }
        return this.xy;
    },

    
    getTarget : function(selector, maxDepth, returnEl){
        if (selector) {
            return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
        }
        return returnEl ? Ext.get(this.target) : this.target;
    },

    
    getRelatedTarget : function(selector, maxDepth, returnEl){
        if (selector) {
            return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
        }
        return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
    },

    
    correctWheelDelta : function (delta) {
        var scale = this.WHEEL_SCALE,
            ret = Math.round(delta / scale);

        if (!ret && delta) {
            ret = (delta < 0) ? -1 : 1; 
        }

        return ret;
    },

    
    getWheelDeltas : function () {
        var me = this,
            event = me.browserEvent,
            dx = 0, dy = 0; 

        if (Ext.isDefined(event.wheelDeltaX)) { 
            dx = event.wheelDeltaX;
            dy = event.wheelDeltaY;
        } else if (event.wheelDelta) { 
            dy = event.wheelDelta;
        } else if (event.detail) { 
            dy = -event.detail; 

            
            
            if (dy > 100) {
                dy = 3;
            } else if (dy < -100) {
                dy = -3;
            }

            
            
            if (Ext.isDefined(event.axis) && event.axis === event.HORIZONTAL_AXIS) {
                dx = dy;
                dy = 0;
            }
        }

        return {
            x: me.correctWheelDelta(dx),
            y: me.correctWheelDelta(dy)
        };
    },

    
    getWheelDelta : function(){
        var deltas = this.getWheelDeltas();

        return deltas.y;
    },

    
    within : function(el, related, allowEl){
        if(el){
            var t = related ? this.getRelatedTarget() : this.getTarget(),
                result;

            if (t) {
                result = Ext.fly(el).contains(t);
                if (!result && allowEl) {
                    result = t == Ext.getDom(el);
                }
                return result;
            }
        }
        return false;
    },

    
    isNavKeyPress : function(){
        var me = this,
            k = this.normalizeKey(me.keyCode);

       return (k >= 33 && k <= 40) ||  
       k == me.RETURN ||
       k == me.TAB ||
       k == me.ESC;
    },

    
    isSpecialKey : function(){
        var k = this.normalizeKey(this.keyCode);
        return (this.type == 'keypress' && this.ctrlKey) ||
        this.isNavKeyPress() ||
        (k == this.BACKSPACE) || 
        (k >= 16 && k <= 20) || 
        (k >= 44 && k <= 46);   
    },

    
    getPoint : function(){
        var xy = this.getXY();
        return new Ext.util.Point(xy[0], xy[1]);
    },

   
    hasModifier : function(){
        return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
    },

    
    injectEvent: (function () {
        var API,
            dispatchers = {}, 
            crazyIEButtons;

        

        
        

        if (!Ext.isIE && document.createEvent) { 
            API = {
                createHtmlEvent: function (doc, type, bubbles, cancelable) {
                    var event = doc.createEvent('HTMLEvents');

                    event.initEvent(type, bubbles, cancelable);
                    return event;
                },

                createMouseEvent: function (doc, type, bubbles, cancelable, detail,
                                            clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
                                            button, relatedTarget) {
                    var event = doc.createEvent('MouseEvents'),
                        view = doc.defaultView || window;

                    if (event.initMouseEvent) {
                        event.initMouseEvent(type, bubbles, cancelable, view, detail,
                                    clientX, clientY, clientX, clientY, ctrlKey, altKey,
                                    shiftKey, metaKey, button, relatedTarget);
                    } else { 
                        event = doc.createEvent('UIEvents');
                        event.initEvent(type, bubbles, cancelable);
                        event.view = view;
                        event.detail = detail;
                        event.screenX = clientX;
                        event.screenY = clientY;
                        event.clientX = clientX;
                        event.clientY = clientY;
                        event.ctrlKey = ctrlKey;
                        event.altKey = altKey;
                        event.metaKey = metaKey;
                        event.shiftKey = shiftKey;
                        event.button = button;
                        event.relatedTarget = relatedTarget;
                    }

                    return event;
                },

                createUIEvent: function (doc, type, bubbles, cancelable, detail) {
                    var event = doc.createEvent('UIEvents'),
                        view = doc.defaultView || window;

                    event.initUIEvent(type, bubbles, cancelable, view, detail);
                    return event;
                },

                fireEvent: function (target, type, event) {
                    target.dispatchEvent(event);
                },

                fixTarget: function (target) {
                    
                    if (target == window && !target.dispatchEvent) {
                        return document;
                    }

                    return target;
                }
            };
        } else if (document.createEventObject) { 
            crazyIEButtons = { 0: 1, 1: 4, 2: 2 };

            API = {
                createHtmlEvent: function (doc, type, bubbles, cancelable) {
                    var event = doc.createEventObject();
                    event.bubbles = bubbles;
                    event.cancelable = cancelable;
                    return event;
                },

                createMouseEvent: function (doc, type, bubbles, cancelable, detail,
                                            clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
                                            button, relatedTarget) {
                    var event = doc.createEventObject();
                    event.bubbles = bubbles;
                    event.cancelable = cancelable;
                    event.detail = detail;
                    event.screenX = clientX;
                    event.screenY = clientY;
                    event.clientX = clientX;
                    event.clientY = clientY;
                    event.ctrlKey = ctrlKey;
                    event.altKey = altKey;
                    event.shiftKey = shiftKey;
                    event.metaKey = metaKey;
                    event.button = crazyIEButtons[button] || button;
                    event.relatedTarget = relatedTarget; 
                    return event;
                },

                createUIEvent: function (doc, type, bubbles, cancelable, detail) {
                    var event = doc.createEventObject();
                    event.bubbles = bubbles;
                    event.cancelable = cancelable;
                    return event;
                },

                fireEvent: function (target, type, event) {
                    target.fireEvent('on' + type, event);
                },

                fixTarget: function (target) {
                    if (target == document) {
                        
                        
                        return document.documentElement;
                    }

                    return target;
                }
            };
        }

        
        

        Ext.Object.each({
                load:   [false, false],
                unload: [false, false],
                select: [true, false],
                change: [true, false],
                submit: [true, true],
                reset:  [true, false],
                resize: [true, false],
                scroll: [true, false]
            },
            function (name, value) {
                var bubbles = value[0], cancelable = value[1];
                dispatchers[name] = function (targetEl, srcEvent) {
                    var e = API.createHtmlEvent(name, bubbles, cancelable);
                    API.fireEvent(targetEl, name, e);
                };
            });

        
        

        function createMouseEventDispatcher (type, detail) {
            var cancelable = (type != 'mousemove');
            return function (targetEl, srcEvent) {
                var xy = srcEvent.getXY(),
                    e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
                                detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
                                srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
                                srcEvent.relatedTarget);
                API.fireEvent(targetEl, type, e);
            };
        }

        Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
            function (eventName) {
                dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
            });

        
        

        Ext.Object.each({
                focusin:  [true, false],
                focusout: [true, false],
                activate: [true, true],
                focus:    [false, false],
                blur:     [false, false]
            },
            function (name, value) {
                var bubbles = value[0], cancelable = value[1];
                dispatchers[name] = function (targetEl, srcEvent) {
                    var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
                    API.fireEvent(targetEl, name, e);
                };
            });

        
        if (!API) {
            

            dispatchers = {}; 

            API = {
                fixTarget: function (t) {
                    return t;
                }
            };
        }

        function cannotInject (target, srcEvent) {
        }

        return function (target) {
            var me = this,
                dispatcher = dispatchers[me.type] || cannotInject,
                t = target ? (target.dom || target) : me.getTarget();

            t = API.fixTarget(t);
            dispatcher(t, me);
        };
    }()) 

}, function() {

Ext.EventObject = new Ext.EventObjectImpl();

});



Ext.define('Ext.dom.AbstractQuery', {
    
    select: function(q, root) {
        var results = [],
            nodes,
            i,
            j,
            qlen,
            nlen;

        root = root || document;

        if (typeof root == 'string') {
            root = document.getElementById(root);
        }

        q = q.split(",");

        for (i = 0,qlen = q.length; i < qlen; i++) {
            if (typeof q[i] == 'string') {
                
                
                if (typeof q[i][0] == '@') {
                    nodes = root.getAttributeNode(q[i].substring(1));
                    results.push(nodes);
                } else {
                    nodes = root.querySelectorAll(q[i]);

                    for (j = 0,nlen = nodes.length; j < nlen; j++) {
                        results.push(nodes[j]);
                    }
                }
            }
        }

        return results;
    },

    
    selectNode: function(q, root) {
        return this.select(q, root)[0];
    },

    
    is: function(el, q) {
        if (typeof el == "string") {
            el = document.getElementById(el);
        }
        return this.select(q).indexOf(el) !== -1;
    }

});


Ext.define('Ext.dom.AbstractHelper', {
    emptyTags : /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
    confRe : /(?:tag|children|cn|html|tpl|tplData)$/i,
    endRe : /end/i,

    
    attributeTransform: { cls : 'class', htmlFor : 'for' },

    closeTags: {},

    decamelizeName : (function () {
        var camelCaseRe = /([a-z])([A-Z])/g,
            cache = {};

        function decamel (match, p1, p2) {
            return p1 + '-' + p2.toLowerCase();
        }

        return function (s) {
            return cache[s] || (cache[s] = s.replace(camelCaseRe, decamel));
        };
    }()),

    generateMarkup: function(spec, buffer) {
        var me = this,
            attr, val, tag, i, closeTags;

        if (typeof spec == "string") {
            buffer.push(spec);
        } else if (Ext.isArray(spec)) {
            for (i = 0; i < spec.length; i++) {
                if (spec[i]) {
                    me.generateMarkup(spec[i], buffer);
                }
            }
        } else {
            tag = spec.tag || 'div';
            buffer.push('<', tag);

            for (attr in spec) {
                if (spec.hasOwnProperty(attr)) {
                    val = spec[attr];
                    if (!me.confRe.test(attr)) {
                        if (typeof val == "object") {
                            buffer.push(' ', attr, '="');
                            me.generateStyles(val, buffer).push('"');
                        } else {
                            buffer.push(' ', me.attributeTransform[attr] || attr, '="', val, '"');
                        }
                    }
                }
            }

            
            if (me.emptyTags.test(tag)) {
                buffer.push('/>');
            } else {
                buffer.push('>');

                
                if ((val = spec.tpl)) {
                    val.applyOut(spec.tplData, buffer);
                }
                if ((val = spec.html)) {
                    buffer.push(val);
                }
                if ((val = spec.cn || spec.children)) {
                    me.generateMarkup(val, buffer);
                }

                
                closeTags = me.closeTags;
                buffer.push(closeTags[tag] || (closeTags[tag] = '</' + tag + '>'));
            }
        }

        return buffer;
    },

    
    generateStyles: function (styles, buffer) {
        var a = buffer || [],
            name;

        for (name in styles) {
            if (styles.hasOwnProperty(name)) {
                a.push(this.decamelizeName(name), ':', styles[name], ';');
            }
        }

        return buffer || a.join('');
    },

    
    markup: function(spec) {
        if (typeof spec == "string") {
            return spec;
        }

        var buf = this.generateMarkup(spec, []);
        return buf.join('');
    },

    
    applyStyles: function(el, styles) {
        if (styles) {
            var i = 0,
                len,
                style;

            el = Ext.fly(el);
            if (typeof styles == 'function') {
                styles = styles.call();
            }
            if (typeof styles == 'string'){
                styles = Ext.util.Format.trim(styles).split(/\s*(?::|;)\s*/);
                for(len = styles.length; i < len;){
                    el.setStyle(styles[i++], styles[i++]);
                }
            } else if (Ext.isObject(styles)) {
                el.setStyle(styles);
            }
        }
    },

    
    insertHtml: function(where, el, html) {
        var hash = {},
            hashVal,
            setStart,
            range,
            frag,
            rangeEl,
            rs;

        where = where.toLowerCase();

        
        hash['beforebegin'] = ['BeforeBegin', 'previousSibling'];
        hash['afterend'] = ['AfterEnd', 'nextSibling'];

        range = el.ownerDocument.createRange();
        setStart = 'setStart' + (this.endRe.test(where) ? 'After' : 'Before');
        if (hash[where]) {
            range[setStart](el);
            frag = range.createContextualFragment(html);
            el.parentNode.insertBefore(frag, where == 'beforebegin' ? el : el.nextSibling);
            return el[(where == 'beforebegin' ? 'previous' : 'next') + 'Sibling'];
        }
        else {
            rangeEl = (where == 'afterbegin' ? 'first' : 'last') + 'Child';
            if (el.firstChild) {
                range[setStart](el[rangeEl]);
                frag = range.createContextualFragment(html);
                if (where == 'afterbegin') {
                    el.insertBefore(frag, el.firstChild);
                }
                else {
                    el.appendChild(frag);
                }
            }
            else {
                el.innerHTML = html;
            }
            return el[rangeEl];
        }

        throw 'Illegal insertion point -> "' + where + '"';
    },

    
    insertBefore: function(el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'beforebegin');
    },

    
    insertAfter: function(el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'afterend', 'nextSibling');
    },

    
    insertFirst: function(el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'afterbegin', 'firstChild');
    },

    
    append: function(el, o, returnElement) {
        return this.doInsert(el, o, returnElement, 'beforeend', '', true);
    },

    
    overwrite: function(el, o, returnElement) {
        el = Ext.getDom(el);
        el.innerHTML = this.markup(o);
        return returnElement ? Ext.get(el.firstChild) : el.firstChild;
    },

    doInsert: function(el, o, returnElement, pos, sibling, append) {
        var newNode = this.insertHtml(pos, Ext.getDom(el), this.markup(o));
        return returnElement ? Ext.get(newNode, true) : newNode;
    }

});


(function() {

var document = window.document,
    trimRe = /^\s+|\s+$/g,
    whitespaceRe = /\s/;

if (!Ext.cache){
    Ext.cache = {};
}

Ext.define('Ext.dom.AbstractElement', {

    inheritableStatics: {

        
        get: function(el) {
            var me = this,
                El = Ext.dom.Element,
                cacheItem,
                extEl,
                dom,
                id;

            if (!el) {
                return null;
            }

            if (typeof el == "string") { 
                if (el == Ext.windowId) {
                    return El.get(window);
                } else if (el == Ext.documentId) {
                    return El.get(document);
                }
                
                cacheItem = Ext.cache[el];
                
                
                
                
                if (cacheItem && cacheItem.skipGarbageCollection) {
                    extEl = cacheItem.el;
                    return extEl;
                }
                
                if (!(dom = document.getElementById(el))) {
                    return null;
                }

                if (cacheItem && cacheItem.el) {
                    extEl = Ext.updateCacheEntry(cacheItem, dom).el;
                } else {
                    
                    extEl = new El(dom, !!cacheItem);
                }
                return extEl;
            } else if (el.tagName) { 
                if (!(id = el.id)) {
                    id = Ext.id(el);
                }
                cacheItem = Ext.cache[id];
                if (cacheItem && cacheItem.el) {
                    extEl = Ext.updateCacheEntry(cacheItem, el).el;
                } else {
                    
                    extEl = new El(el, !!cacheItem);
                }
                return extEl;
            } else if (el instanceof me) {
                if (el != me.docEl && el != me.winEl) {
                    id = el.id;
                    
                    
                    cacheItem = Ext.cache[id];
                    if (cacheItem) {
                        Ext.updateCacheEntry(cacheItem, document.getElementById(id) || el.dom);
                    }
                }
                return el;
            } else if (el.isComposite) {
                return el;
            } else if (Ext.isArray(el)) {
                return me.select(el);
            } else if (el === document) {
                
                if (!me.docEl) {
                    me.docEl = Ext.Object.chain(El.prototype);
                    me.docEl.dom = document;
                    me.docEl.id = Ext.id(document);
                    me.addToCache(me.docEl);
                }
                return me.docEl;
            } else if (el === window) {
                if (!me.winEl) {
                    me.winEl = Ext.Object.chain(El.prototype);
                    me.winEl.dom = window;
                    me.winEl.id = Ext.id(window);
                    me.addToCache(me.winEl);
                }
                return me.winEl;
            }
            return null;
        },

        addToCache: function(el, id) {
            if (el) {
                Ext.addCacheEntry(id, el);
            }
            return el;
        },

        addMethods: function() {
            this.override.apply(this, arguments);
        },

        
        mergeClsList: function() {
            var clsList, clsHash = {},
                i, length, j, listLength, clsName, result = [],
                changed = false;

            for (i = 0, length = arguments.length; i < length; i++) {
                clsList = arguments[i];
                if (Ext.isString(clsList)) {
                    clsList = clsList.replace(trimRe, '').split(whitespaceRe);
                }
                if (clsList) {
                    for (j = 0, listLength = clsList.length; j < listLength; j++) {
                        clsName = clsList[j];
                        if (!clsHash[clsName]) {
                            if (i) {
                                changed = true;
                            }
                            clsHash[clsName] = true;
                        }
                    }
                }
            }

            for (clsName in clsHash) {
                result.push(clsName);
            }
            result.changed = changed;
            return result;
        },

        
        removeCls: function(existingClsList, removeClsList) {
            var clsHash = {},
                i, length, clsName, result = [],
                changed = false;

            if (existingClsList) {
                if (Ext.isString(existingClsList)) {
                    existingClsList = existingClsList.replace(trimRe, '').split(whitespaceRe);
                }
                for (i = 0, length = existingClsList.length; i < length; i++) {
                    clsHash[existingClsList[i]] = true;
                }
            }
            if (removeClsList) {
                if (Ext.isString(removeClsList)) {
                    removeClsList = removeClsList.split(whitespaceRe);
                }
                for (i = 0, length = removeClsList.length; i < length; i++) {
                    clsName = removeClsList[i];
                    if (clsHash[clsName]) {
                        changed = true;
                        delete clsHash[clsName];
                    }
                }
            }
            for (clsName in clsHash) {
                result.push(clsName);
            }
            result.changed = changed;
            return result;
        },

        
        VISIBILITY: 1,

        
        DISPLAY: 2,

        
        OFFSETS: 3,

        
        ASCLASS: 4
    },

    constructor: function(element, forceNew) {
        var me = this,
            dom = typeof element == 'string'
                ? document.getElementById(element)
                : element,
            id;

        if (!dom) {
            return null;
        }

        id = dom.id;
        if (!forceNew && id && Ext.cache[id]) {
            
            return Ext.cache[id].el;
        }

        
        me.dom = dom;

        
        me.id = id || Ext.id(dom);

        me.self.addToCache(me);
    },

    
    set: function(o, useSet) {
         var el = this.dom,
             attr,
             value;

         for (attr in o) {
             if (o.hasOwnProperty(attr)) {
                 value = o[attr];
                 if (attr == 'style') {
                     this.applyStyles(value);
                 }
                 else if (attr == 'cls') {
                     el.className = value;
                 }
                 else if (useSet !== false) {
                     if (value === undefined) {
                         el.removeAttribute(attr);
                     } else {
                        el.setAttribute(attr, value);
                     }
                 }
                 else {
                     el[attr] = value;
                 }
             }
         }
         return this;
     },

    
    defaultUnit: "px",

    
    is: function(simpleSelector) {
        return Ext.DomQuery.is(this.dom, simpleSelector);
    },

    
    getValue: function(asNumber) {
        var val = this.dom.value;
        return asNumber ? parseInt(val, 10) : val;
    },

    
    remove: function() {
        var me = this,
        dom = me.dom;

        if (dom) {
            Ext.removeNode(dom);
            delete me.dom;
        }
    },

    
    contains: function(el) {
        if (!el) {
            return false;
        }

        var me = this,
            dom = el.dom || el;

        
        return (dom === me.dom) || Ext.dom.AbstractElement.isAncestor(me.dom, dom);
    },

    
    getAttribute: function(name, ns) {
        var dom = this.dom;
        return dom.getAttributeNS(ns, name) || dom.getAttribute(ns + ":" + name) || dom.getAttribute(name) || dom[name];
    },

    
    update: function(html) {
        if (this.dom) {
            this.dom.innerHTML = html;
        }
        return this;
    },


    
    setHTML: function(html) {
        if(this.dom) {
            this.dom.innerHTML = html;
        }
        return this;
    },

    
    getHTML: function() {
        return this.dom ? this.dom.innerHTML : '';
    },

    
    hide: function() {
        this.setVisible(false);
        return this;
    },

    
    show: function() {
        this.setVisible(true);
        return this;
    },

    
    setVisible: function(visible, animate) {
        var me = this,
            statics = me.self,
            mode = me.getVisibilityMode(),
            prefix = Ext.baseCSSPrefix;

        switch (mode) {
            case statics.VISIBILITY:
                me.removeCls([prefix + 'hidden-display', prefix + 'hidden-offsets']);
                me[visible ? 'removeCls' : 'addCls'](prefix + 'hidden-visibility');
            break;

            case statics.DISPLAY:
                me.removeCls([prefix + 'hidden-visibility', prefix + 'hidden-offsets']);
                me[visible ? 'removeCls' : 'addCls'](prefix + 'hidden-display');
            break;

            case statics.OFFSETS:
                me.removeCls([prefix + 'hidden-visibility', prefix + 'hidden-display']);
                me[visible ? 'removeCls' : 'addCls'](prefix + 'hidden-offsets');
            break;
        }

        return me;
    },

    getVisibilityMode: function() {
        
        
        
        var data = (this.$cache || this.getCache()).data,
            visMode = data.visibilityMode;

        if (visMode === undefined) {
            data.visibilityMode = visMode = this.self.DISPLAY;
        }
        
        return visMode;
    },

    
    setVisibilityMode: function(mode) {
        (this.$cache || this.getCache()).data.visibilityMode = mode;
        return this;
    },
    
    getCache: function() {
        var me = this,
            id = me.dom.id || Ext.id(me.dom);

        
        
        
        me.$cache = Ext.cache[id] || Ext.addCacheEntry(id, null, me.dom);
            
        return me.$cache;
    }
    
}, function() {
    var AbstractElement = this;

    
    Ext.getDetachedBody = function () {
        var detachedEl = AbstractElement.detachedBodyEl;

        if (!detachedEl) {
            detachedEl = document.createElement('div');
            AbstractElement.detachedBodyEl = detachedEl = new AbstractElement.Fly(detachedEl);
            detachedEl.isDetachedBody = true;
        }

        return detachedEl;
    };

    
    Ext.getElementById = function (id) {
        var el = document.getElementById(id),
            detachedBodyEl;

        if (!el && (detachedBodyEl = AbstractElement.detachedBodyEl)) {
            el = detachedBodyEl.dom.querySelector('#' + Ext.escapeId(id));
        }

        return el;
    };

    
    Ext.get = function(el) {
        return Ext.dom.Element.get(el);
    };

    this.addStatics({
        
        Fly: new Ext.Class({
            extend: AbstractElement,

            
            isFly: true,

            constructor: function(dom) {
                this.dom = dom;
            },

            
            attach: function (dom) {

                
                this.dom = dom;
                
                
                this.$cache = dom.id ? Ext.cache[dom.id] : null;
                return this;
            }
        }),

        _flyweights: {},

        
        fly: function(dom, named) {
            var fly = null,
                _flyweights = AbstractElement._flyweights;

            named = named || '_global';

            dom = Ext.getDom(dom);

            if (dom) {
                fly = _flyweights[named] || (_flyweights[named] = new AbstractElement.Fly());

                
                
                fly.dom = dom;
                
                
                fly.$cache = dom.id ? Ext.cache[dom.id] : null;
            }
            return fly;
        }
    });

    
    Ext.fly = function() {
        return AbstractElement.fly.apply(AbstractElement, arguments);
    };

    (function (proto) {
        
        proto.destroy = proto.remove;

        
        if (document.querySelector) {
            proto.getById = function (id, asDom) {
                
                
                var dom = document.getElementById(id) ||
                    this.dom.querySelector('#'+Ext.escapeId(id));
                return asDom ? dom : (dom ? Ext.get(dom) : null);
            };
        } else {
            proto.getById = function (id, asDom) {
                var dom = document.getElementById(id);
                return asDom ? dom : (dom ? Ext.get(dom) : null);
            };
        }
    }(this.prototype));
});

}());


Ext.dom.AbstractElement.addInheritableStatics({
    unitRe: /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
    camelRe: /(-[a-z])/gi,
    cssRe: /([a-z0-9\-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
    opacityRe: /alpha\(opacity=(.*)\)/i,
    propertyCache: {},
    defaultUnit : "px",
    borders: {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'},
    paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'},
    margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'},
    
    addUnits: function(size, units) {
        
        if (typeof size == 'number') {
            return size + (units || this.defaultUnit || 'px');
        }

        
        if (size === "" || size == "auto" || size === undefined || size === null) {
            return size || '';
        }

        
        if (!this.unitRe.test(size)) {
            return size || '';
        }

        return size;
    },

    
    isAncestor: function(p, c) {
        var ret = false;

        p = Ext.getDom(p);
        c = Ext.getDom(c);
        if (p && c) {
            if (p.contains) {
                return p.contains(c);
            } else if (p.compareDocumentPosition) {
                return !!(p.compareDocumentPosition(c) & 16);
            } else {
                while ((c = c.parentNode)) {
                    ret = c == p || ret;
                }
            }
        }
        return ret;
    },

    
    parseBox: function(box) {
        if (typeof box != 'string') {
            box = box.toString();
        }
        var parts  = box.split(' '),
            ln = parts.length;

        if (ln == 1) {
            parts[1] = parts[2] = parts[3] = parts[0];
        }
        else if (ln == 2) {
            parts[2] = parts[0];
            parts[3] = parts[1];
        }
        else if (ln == 3) {
            parts[3] = parts[1];
        }

        return {
            top   :parseFloat(parts[0]) || 0,
            right :parseFloat(parts[1]) || 0,
            bottom:parseFloat(parts[2]) || 0,
            left  :parseFloat(parts[3]) || 0
        };
    },

    
    unitizeBox: function(box, units) {
        var a = this.addUnits,
            b = this.parseBox(box);

        return a(b.top, units) + ' ' +
               a(b.right, units) + ' ' +
               a(b.bottom, units) + ' ' +
               a(b.left, units);

    },

    
    camelReplaceFn: function(m, a) {
        return a.charAt(1).toUpperCase();
    },

    
    normalize: function(prop) {
        
        if (prop == 'float') {
            prop = Ext.supports.Float ? 'cssFloat' : 'styleFloat';
        }
        return this.propertyCache[prop] || (this.propertyCache[prop] = prop.replace(this.camelRe, this.camelReplaceFn));
    },

    
    getDocumentHeight: function() {
        return Math.max(!Ext.isStrict ? document.body.scrollHeight : document.documentElement.scrollHeight, this.getViewportHeight());
    },

    
    getDocumentWidth: function() {
        return Math.max(!Ext.isStrict ? document.body.scrollWidth : document.documentElement.scrollWidth, this.getViewportWidth());
    },

    
    getViewportHeight: function(){
        return window.innerHeight;
    },

    
    getViewportWidth: function() {
        return window.innerWidth;
    },

    
    getViewSize: function() {
        return {
            width: window.innerWidth,
            height: window.innerHeight
        };
    },

    
    getOrientation: function() {
        if (Ext.supports.OrientationChange) {
            return (window.orientation == 0) ? 'portrait' : 'landscape';
        }

        return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
    },

    
    fromPoint: function(x, y) {
        return Ext.get(document.elementFromPoint(x, y));
    },

    
    parseStyles: function(styles){
        var out = {},
            cssRe = this.cssRe,
            matches;

        if (styles) {
            
            
            
            
            cssRe.lastIndex = 0;
            while ((matches = cssRe.exec(styles))) {
                out[matches[1]] = matches[2];
            }
        }
        return out;
    }
});


(function(){
    var doc = document,
        AbstractElement = Ext.dom.AbstractElement,
        activeElement = null,
        isCSS1 = doc.compatMode == "CSS1Compat",
        flyInstance,
        fly = function (el) {
            if (!flyInstance) {
                flyInstance = new AbstractElement.Fly();
            }
            flyInstance.attach(el);
            return flyInstance;
        };

    
    
    
    if (!('activeElement' in doc) && doc.addEventListener) {
        doc.addEventListener('focus',
            function (ev) {
                if (ev && ev.target) {
                    activeElement = (ev.target == doc) ? null : ev.target;
                }
            }, true);
    }

    
    function makeSelectionRestoreFn (activeEl, start, end) {
        return function () {
            activeEl.selectionStart = start;
            activeEl.selectionEnd = end;
        };
    }

    AbstractElement.addInheritableStatics({
        
        getActiveElement: function () {
            return doc.activeElement || activeElement;
        },

        
        getRightMarginFixCleaner: function (target) {
            var supports = Ext.supports,
                hasInputBug = supports.DisplayChangeInputSelectionBug,
                hasTextAreaBug = supports.DisplayChangeTextAreaSelectionBug,
                activeEl,
                tag,
                start,
                end;

            if (hasInputBug || hasTextAreaBug) {
                activeEl = doc.activeElement || activeElement; 
                tag = activeEl && activeEl.tagName;

                if ((hasTextAreaBug && tag == 'TEXTAREA') ||
                    (hasInputBug && tag == 'INPUT' && activeEl.type == 'text')) {
                    if (Ext.dom.Element.isAncestor(target, activeEl)) {
                        start = activeEl.selectionStart;
                        end = activeEl.selectionEnd;

                        if (Ext.isNumber(start) && Ext.isNumber(end)) { 
                            
                            
                            
                            
                            return makeSelectionRestoreFn(activeEl, start, end);
                        }
                    }
                }
            }

            return Ext.emptyFn; 
        },

        getViewWidth: function(full) {
            return full ? Ext.dom.Element.getDocumentWidth() : Ext.dom.Element.getViewportWidth();
        },

        getViewHeight: function(full) {
            return full ? Ext.dom.Element.getDocumentHeight() : Ext.dom.Element.getViewportHeight();
        },

        getDocumentHeight: function() {
            return Math.max(!isCSS1 ? doc.body.scrollHeight : doc.documentElement.scrollHeight, Ext.dom.Element.getViewportHeight());
        },

        getDocumentWidth: function() {
            return Math.max(!isCSS1 ? doc.body.scrollWidth : doc.documentElement.scrollWidth, Ext.dom.Element.getViewportWidth());
        },

        getViewportHeight: function(){
            return Ext.isIE ?
                   (Ext.isStrict ? doc.documentElement.clientHeight : doc.body.clientHeight) :
                   self.innerHeight;
        },

        getViewportWidth: function() {
            return (!Ext.isStrict && !Ext.isOpera) ? doc.body.clientWidth :
                   Ext.isIE ? doc.documentElement.clientWidth : self.innerWidth;
        },

        getY: function(el) {
            return Ext.dom.Element.getXY(el)[1];
        },

        getX: function(el) {
            return Ext.dom.Element.getXY(el)[0];
        },

        getXY: function(el) {
            var bd = doc.body,
                docEl = doc.documentElement,
                leftBorder = 0,
                topBorder = 0,
                ret = [0,0],
                round = Math.round,
                box,
                scroll;

            el = Ext.getDom(el);

            if(el != doc && el != bd){
                
                
                if (Ext.isIE) {
                    try {
                        box = el.getBoundingClientRect();
                        
                        topBorder = docEl.clientTop || bd.clientTop;
                        leftBorder = docEl.clientLeft || bd.clientLeft;
                    } catch (ex) {
                        box = { left: 0, top: 0 };
                    }
                } else {
                    box = el.getBoundingClientRect();
                }

                scroll = fly(document).getScroll();
                ret = [round(box.left + scroll.left - leftBorder), round(box.top + scroll.top - topBorder)];
            }
            return ret;
        },

        setXY: function(el, xy) {
            (el = Ext.fly(el, '_setXY')).position();

            var pts = el.translatePoints(xy),
                style = el.dom.style,
                pos;

            for (pos in pts) {
                if (!isNaN(pts[pos])) {
                    style[pos] = pts[pos] + "px";
                }
            }
        },

        setX: function(el, x) {
            Ext.dom.Element.setXY(el, [x, false]);
        },

        setY: function(el, y) {
            Ext.dom.Element.setXY(el, [false, y]);
        },

        
        serializeForm: function(form) {
            var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,
                hasSubmit = false,
                encoder   = encodeURIComponent,
                data      = '',
                eLen      = fElements.length,
                element, name, type, options, hasValue, e,
                o, oLen, opt;

            for (e = 0; e < eLen; e++) {
                element = fElements[e];
                name    = element.name;
                type    = element.type;
                options = element.options;

                if (!element.disabled && name) {
                    if (/select-(one|multiple)/i.test(type)) {
                        oLen = options.length;
                        for (o = 0; o < oLen; o++) {
                            opt = options[o];
                            if (opt.selected) {
                                hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttributeNode('value').specified;
                                data += Ext.String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text));
                            }
                        }
                    } else if (!(/file|undefined|reset|button/i.test(type))) {
                        if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) {
                            data += encoder(name) + '=' + encoder(element.value) + '&';
                            hasSubmit = /submit/i.test(type);
                        }
                    }
                }
            }
            return data.substr(0, data.length - 1);
        }
    });
}());


Ext.dom.AbstractElement.override({

    
    getAnchorXY: function(anchor, local, size) {
        
        
        anchor = (anchor || "tl").toLowerCase();
        size = size || {};

        var me = this,
            vp = me.dom == document.body || me.dom == document,
            width = size.width || vp ? window.innerWidth: me.getWidth(),
            height = size.height || vp ? window.innerHeight: me.getHeight(),
            xy,
            rnd = Math.round,
            myXY = me.getXY(),
            extraX = vp ? 0: !local ? myXY[0] : 0,
            extraY = vp ? 0: !local ? myXY[1] : 0,
            hash = {
                c: [rnd(width * 0.5), rnd(height * 0.5)],
                t: [rnd(width * 0.5), 0],
                l: [0, rnd(height * 0.5)],
                r: [width, rnd(height * 0.5)],
                b: [rnd(width * 0.5), height],
                tl: [0, 0],
                bl: [0, height],
                br: [width, height],
                tr: [width, 0]
            };

        xy = hash[anchor];
        return [xy[0] + extraX, xy[1] + extraY];
    },

    alignToRe: /^([a-z]+)-([a-z]+)(\?)?$/,

    
    getAlignToXY: function(el, position, offsets, local) {
        local = !!local;
        el = Ext.get(el);

        offsets = offsets || [0, 0];

        if (!position || position == '?') {
            position = 'tl-bl?';
        }
        else if (! (/-/).test(position) && position !== "") {
            position = 'tl-' + position;
        }
        position = position.toLowerCase();

        var me = this,
            matches = position.match(this.alignToRe),
            dw = window.innerWidth,
            dh = window.innerHeight,
            p1 = "",
            p2 = "",
            a1,
            a2,
            x,
            y,
            swapX,
            swapY,
            p1x,
            p1y,
            p2x,
            p2y,
            width,
            height,
            region,
            constrain;

        if (!matches) {
            throw "Element.alignTo with an invalid alignment " + position;
        }

        p1 = matches[1];
        p2 = matches[2];
        constrain = !!matches[3];

        
        
        a1 = me.getAnchorXY(p1, true);
        a2 = el.getAnchorXY(p2, local);

        x = a2[0] - a1[0] + offsets[0];
        y = a2[1] - a1[1] + offsets[1];

        if (constrain) {
            width = me.getWidth();
            height = me.getHeight();

            region = el.getPageBox();

            
            
            
            p1y = p1.charAt(0);
            p1x = p1.charAt(p1.length - 1);
            p2y = p2.charAt(0);
            p2x = p2.charAt(p2.length - 1);

            swapY = ((p1y == "t" && p2y == "b") || (p1y == "b" && p2y == "t"));
            swapX = ((p1x == "r" && p2x == "l") || (p1x == "l" && p2x == "r"));

            if (x + width > dw) {
                x = swapX ? region.left - width: dw - width;
            }
            if (x < 0) {
                x = swapX ? region.right: 0;
            }
            if (y + height > dh) {
                y = swapY ? region.top - height: dh - height;
            }
            if (y < 0) {
                y = swapY ? region.bottom: 0;
            }
        }

        return [x, y];
    },

    
    getAnchor: function(){
        var data = (this.$cache || this.getCache()).data,
            anchor;
            
        if (!this.dom) {
            return;
        }
        anchor = data._anchor;

        if(!anchor){
            anchor = data._anchor = {};
        }
        return anchor;
    },

    
    adjustForConstraints: function(xy, parent) {
        var vector = this.getConstrainVector(parent, xy);
        if (vector) {
            xy[0] += vector[0];
            xy[1] += vector[1];
        }
        return xy;
    }

});


Ext.dom.AbstractElement.addMethods({
    
    appendChild: function(el) {
        return Ext.get(el).appendTo(this);
    },

    
    appendTo: function(el) {
        Ext.getDom(el).appendChild(this.dom);
        return this;
    },

    
    insertBefore: function(el) {
        el = Ext.getDom(el);
        el.parentNode.insertBefore(this.dom, el);
        return this;
    },

    
    insertAfter: function(el) {
        el = Ext.getDom(el);
        el.parentNode.insertBefore(this.dom, el.nextSibling);
        return this;
    },

    
    insertFirst: function(el, returnDom) {
        el = el || {};
        if (el.nodeType || el.dom || typeof el == 'string') { 
            el = Ext.getDom(el);
            this.dom.insertBefore(el, this.dom.firstChild);
            return !returnDom ? Ext.get(el) : el;
        }
        else { 
            return this.createChild(el, this.dom.firstChild, returnDom);
        }
    },

    
    insertSibling: function(el, where, returnDom){
        var me      = this,
            isAfter = (where || 'before').toLowerCase() == 'after',
            rt, insertEl, eLen, e;

        if (Ext.isArray(el)) {
            insertEl = me;
            eLen = el.length;
            
            for (e = 0; e < eLen; e++) {
                rt = Ext.fly(insertEl, '_internal').insertSibling(el[e], where, returnDom);

                if (isAfter) {
                    insertEl = rt;
                }
            }

            return rt;
        }

        el = el || {};

        if(el.nodeType || el.dom){
            rt = me.dom.parentNode.insertBefore(Ext.getDom(el), isAfter ? me.dom.nextSibling : me.dom);
            if (!returnDom) {
                rt = Ext.get(rt);
            }
        }else{
            if (isAfter && !me.dom.nextSibling) {
                rt = Ext.core.DomHelper.append(me.dom.parentNode, el, !returnDom);
            } else {
                rt = Ext.core.DomHelper[isAfter ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
            }
        }
        return rt;
    },

    
    replace: function(el) {
        el = Ext.get(el);
        this.insertBefore(el);
        el.remove();
        return this;
    },

    
    replaceWith: function(el){
        var me = this;

        if(el.nodeType || el.dom || typeof el == 'string'){
            el = Ext.get(el);
            me.dom.parentNode.insertBefore(el, me.dom);
        }else{
            el = Ext.core.DomHelper.insertBefore(me.dom, el);
        }

        delete Ext.cache[me.id];
        Ext.removeNode(me.dom);
        me.id = Ext.id(me.dom = el);
        Ext.dom.AbstractElement.addToCache(me.isFlyweight ? new Ext.dom.AbstractElement(me.dom) : me);
        return me;
    },

    
    createChild: function(config, insertBefore, returnDom) {
        config = config || {tag:'div'};
        if (insertBefore) {
            return Ext.core.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
        }
        else {
            return Ext.core.DomHelper[!this.dom.firstChild ? 'insertFirst' : 'append'](this.dom, config,  returnDom !== true);
        }
    },

    
    wrap: function(config, returnDom, selector) {
        var newEl = Ext.core.DomHelper.insertBefore(this.dom, config || {tag: "div"}, true),
            target = newEl;
        
        if (selector) {
            target = Ext.DomQuery.selectNode(selector, newEl.dom);
        }

        target.appendChild(this.dom);
        return returnDom ? newEl.dom : newEl;
    },

    
    insertHtml: function(where, html, returnEl) {
        var el = Ext.core.DomHelper.insertHtml(where, this.dom, html);
        return returnEl ? Ext.get(el) : el;
    }
});


(function(){

var Element = Ext.dom.AbstractElement;

Element.override({

    
    getX: function(el) {
        return this.getXY(el)[0];
    },

    
    getY: function(el) {
        return this.getXY(el)[1];
    },

    
    getXY: function() {
        
        var point = window.webkitConvertPointFromNodeToPage(this.dom, new WebKitPoint(0, 0));
        return [point.x, point.y];
    },

    
    getOffsetsTo: function(el){
        var o = this.getXY(),
            e = Ext.fly(el, '_internal').getXY();
        return [o[0]-e[0],o[1]-e[1]];
    },

    
    setX: function(x){
        return this.setXY([x, this.getY()]);
    },

    
    setY: function(y) {
        return this.setXY([this.getX(), y]);
    },

    
    setLeft: function(left) {
        this.setStyle('left', Element.addUnits(left));
        return this;
    },

    
    setTop: function(top) {
        this.setStyle('top', Element.addUnits(top));
        return this;
    },

    
    setRight: function(right) {
        this.setStyle('right', Element.addUnits(right));
        return this;
    },

    
    setBottom: function(bottom) {
        this.setStyle('bottom', Element.addUnits(bottom));
        return this;
    },

    
    setXY: function(pos) {
        var me = this,
            pts,
            style,
            pt;

        if (arguments.length > 1) {
            pos = [pos, arguments[1]];
        }

        
        pts = me.translatePoints(pos);
        style = me.dom.style;

        for (pt in pts) {
            if (!pts.hasOwnProperty(pt)) {
                continue;
            }
            if (!isNaN(pts[pt])) {
                style[pt] = pts[pt] + "px";
            }
        }
        return me;
    },

    
    getLeft: function(local) {
        return parseInt(this.getStyle('left'), 10) || 0;
    },

    
    getRight: function(local) {
        return parseInt(this.getStyle('right'), 10) || 0;
    },

    
    getTop: function(local) {
        return parseInt(this.getStyle('top'), 10) || 0;
    },

    
    getBottom: function(local) {
        return parseInt(this.getStyle('bottom'), 10) || 0;
    },

    
    translatePoints: function(x, y) {
        y = isNaN(x[1]) ? y : x[1];
        x = isNaN(x[0]) ? x : x[0];
        var me = this,
            relative = me.isStyle('position', 'relative'),
            o = me.getXY(),
            l = parseInt(me.getStyle('left'), 10),
            t = parseInt(me.getStyle('top'), 10);

        l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
        t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);

        return {left: (x - o[0] + l), top: (y - o[1] + t)};
    },

    
    setBox: function(box) {
        var me = this,
            width = box.width,
            height = box.height,
            top = box.top,
            left = box.left;

        if (left !== undefined) {
            me.setLeft(left);
        }
        if (top !== undefined) {
            me.setTop(top);
        }
        if (width !== undefined) {
            me.setWidth(width);
        }
        if (height !== undefined) {
            me.setHeight(height);
        }

        return this;
    },

    
    getBox: function(contentBox, local) {
        var me = this,
            dom = me.dom,
            width = dom.offsetWidth,
            height = dom.offsetHeight,
            xy, box, l, r, t, b;

        if (!local) {
            xy = me.getXY();
        }
        else if (contentBox) {
            xy = [0,0];
        }
        else {
            xy = [parseInt(me.getStyle("left"), 10) || 0, parseInt(me.getStyle("top"), 10) || 0];
        }

        if (!contentBox) {
            box = {
                x: xy[0],
                y: xy[1],
                0: xy[0],
                1: xy[1],
                width: width,
                height: height
            };
        }
        else {
            l = me.getBorderWidth.call(me, "l") + me.getPadding.call(me, "l");
            r = me.getBorderWidth.call(me, "r") + me.getPadding.call(me, "r");
            t = me.getBorderWidth.call(me, "t") + me.getPadding.call(me, "t");
            b = me.getBorderWidth.call(me, "b") + me.getPadding.call(me, "b");
            box = {
                x: xy[0] + l,
                y: xy[1] + t,
                0: xy[0] + l,
                1: xy[1] + t,
                width: width - (l + r),
                height: height - (t + b)
            };
        }

        box.left = box.x;
        box.top = box.y;
        box.right = box.x + box.width;
        box.bottom = box.y + box.height;

        return box;
    },

    
    getPageBox: function(getRegion) {
        var me = this,
            el = me.dom,
            w = el.offsetWidth,
            h = el.offsetHeight,
            xy = me.getXY(),
            t = xy[1],
            r = xy[0] + w,
            b = xy[1] + h,
            l = xy[0];

        if (!el) {
            return new Ext.util.Region();
        }

        if (getRegion) {
            return new Ext.util.Region(t, r, b, l);
        }
        else {
            return {
                left: l,
                top: t,
                width: w,
                height: h,
                right: r,
                bottom: b
            };
        }
    }
});

}());


(function(){
    
    var Element = Ext.dom.AbstractElement,
        view = document.defaultView,
        array = Ext.Array,
        trimRe = /^\s+|\s+$/g,
        wordsRe = /\w/g,
        spacesRe = /\s+/,
        transparentRe = /^(?:transparent|(?:rgba[(](?:\s*\d+\s*[,]){3}\s*0\s*[)]))$/i,
        hasClassList = Ext.supports.ClassList,
        PADDING = 'padding',
        MARGIN = 'margin',
        BORDER = 'border',
        LEFT_SUFFIX = '-left',
        RIGHT_SUFFIX = '-right',
        TOP_SUFFIX = '-top',
        BOTTOM_SUFFIX = '-bottom',
        WIDTH = '-width',
        
        borders = {l: BORDER + LEFT_SUFFIX + WIDTH, r: BORDER + RIGHT_SUFFIX + WIDTH, t: BORDER + TOP_SUFFIX + WIDTH, b: BORDER + BOTTOM_SUFFIX + WIDTH},
        paddings = {l: PADDING + LEFT_SUFFIX, r: PADDING + RIGHT_SUFFIX, t: PADDING + TOP_SUFFIX, b: PADDING + BOTTOM_SUFFIX},
        margins = {l: MARGIN + LEFT_SUFFIX, r: MARGIN + RIGHT_SUFFIX, t: MARGIN + TOP_SUFFIX, b: MARGIN + BOTTOM_SUFFIX};


    Element.override({

        
        styleHooks: {},

        
        addStyles : function(sides, styles){
            var totalSize = 0,
                sidesArr = (sides || '').match(wordsRe),
                i,
                len = sidesArr.length,
                side,
                styleSides = [];

            if (len == 1) {
                totalSize = Math.abs(parseFloat(this.getStyle(styles[sidesArr[0]])) || 0);
            } else if (len) {
                for (i = 0; i < len; i++) {
                    side = sidesArr[i];
                    styleSides.push(styles[side]);
                }
                
                styleSides = this.getStyle(styleSides);

                for (i=0; i < len; i++) {
                    side = sidesArr[i];
                    totalSize += Math.abs(parseFloat(styleSides[styles[side]]) || 0);
                }
            }

            return totalSize;
        },

        
        addCls: hasClassList ?
            function (className) {
                var me = this,
                    dom = me.dom,
                    classList,
                    newCls,
                    i,
                    len,
                    cls;

                if (typeof(className) == 'string') {
                    
                    className = className.replace(trimRe, '').split(spacesRe);
                }

                
                
                if (dom && className && !!(len = className.length)) {
                    if (!dom.className) {
                        dom.className = className.join(' ');
                    } else {
                        classList = dom.classList;
                        for (i = 0; i < len; ++i) {
                            cls = className[i];
                            if (cls) {
                                if (!classList.contains(cls)) {
                                    if (newCls) {
                                        newCls.push(cls);
                                    } else {
                                        newCls = dom.className.replace(trimRe, '');
                                        newCls = newCls ? [newCls, cls] : [cls];
                                    }
                                }
                            }
                        }

                        if (newCls) {
                            dom.className = newCls.join(' '); 
                        }
                    }
                }
                return me;
            } :
            function(className) {
                var me = this,
                    dom = me.dom,
                    changed,
                    elClasses;

                if (dom && className && className.length) {
                    elClasses = Ext.Element.mergeClsList(dom.className, className);
                    if (elClasses.changed) {
                        dom.className = elClasses.join(' '); 
                    }
                }
                return me;
            },


        
        removeCls: function(className) {
            var me = this,
                dom = me.dom,
                len,
                elClasses;

            if (typeof(className) == 'string') {
                
                className = className.replace(trimRe, '').split(spacesRe);
            }

            if (dom && dom.className && className && !!(len = className.length)) {
                if (len == 1 && hasClassList) {
                    if (className[0]) {
                        dom.classList.remove(className[0]); 
                    }
                } else {
                    elClasses = Ext.Element.removeCls(dom.className, className);
                    if (elClasses.changed) {
                        dom.className = elClasses.join(' ');
                    }
                }
            }
            return me;
        },

        
        radioCls: function(className) {
            var cn = this.dom.parentNode.childNodes,
                v,
                i, len;
            className = Ext.isArray(className) ? className: [className];
            for (i = 0, len = cn.length; i < len; i++) {
                v = cn[i];
                if (v && v.nodeType == 1) {
                    Ext.fly(v, '_internal').removeCls(className);
                }
            }
            return this.addCls(className);
        },

        
        toggleCls: hasClassList ?
            function (className) {
                var me = this,
                    dom = me.dom;

                if (dom) {
                    className = className.replace(trimRe, '');
                    if (className) {
                        dom.classList.toggle(className);
                    }
                }

                return me;
            } :
            function(className) {
                var me = this;
                return me.hasCls(className) ? me.removeCls(className) : me.addCls(className);
            },

        
        hasCls: hasClassList ?
            function (className) {
                var dom = this.dom;
                return (dom && className) ? dom.classList.contains(className) : false;
            } :
            function(className) {
                var dom = this.dom;
                return dom ? className && (' '+dom.className+' ').indexOf(' '+className+' ') != -1 : false;
            },

        
        replaceCls: function(oldClassName, newClassName){
            return this.removeCls(oldClassName).addCls(newClassName);
        },

        
        isStyle: function(style, val) {
            return this.getStyle(style) == val;
        },

        
        getStyle: function (property, inline) {
            var me = this,
                dom = me.dom,
                multiple = typeof property != 'string',
                hooks = me.styleHooks,
                prop = property,
                props = prop,
                len = 1,
                domStyle, camel, values, hook, out, style, i;

            if (multiple) {
                values = {};
                prop = props[0];
                i = 0;
                if (!(len = props.length)) {
                    return values;
                }
            }

            if (!dom || dom.documentElement) {
                return values || '';
            }

            domStyle = dom.style;

            if (inline) {
                style = domStyle;
            } else {
                
                
                
                
                style = dom.ownerDocument.defaultView.getComputedStyle(dom, null);

                
                if (!style) {
                    inline = true;
                    style = domStyle;
                }
            }

            do {
                hook = hooks[prop];

                if (!hook) {
                    hooks[prop] = hook = { name: Element.normalize(prop) };
                }

                if (hook.get) {
                    out = hook.get(dom, me, inline, style);
                } else {
                    camel = hook.name;
                    out = style[camel];
                }

                if (!multiple) {
                   return out;
                }

                values[prop] = out;
                prop = props[++i];
            } while (i < len);

            return values;
        },

        getStyles: function () {
            var props = Ext.Array.slice(arguments),
                len = props.length,
                inline;

            if (len && typeof props[len-1] == 'boolean') {
                inline = props.pop();
            }

            return this.getStyle(props, inline);
        },

        
        isTransparent: function (prop) {
            var value = this.getStyle(prop);
            return value ? transparentRe.test(value) : false;
        },

        
        setStyle: function(prop, value) {
            var me = this,
                dom = me.dom,
                hooks = me.styleHooks,
                style = dom.style,
                name = prop,
                hook;

            
            if (typeof name == 'string') {
                hook = hooks[name];
                if (!hook) {
                    hooks[name] = hook = { name: Element.normalize(name) };
                }
                value = (value == null) ? '' : value;
                if (hook.set) {
                    hook.set(dom, value, me);
                } else {
                    style[hook.name] = value;
                }
                if (hook.afterSet) {
                    hook.afterSet(dom, value, me);
                }
            } else {
                for (name in prop) {
                    if (prop.hasOwnProperty(name)) {
                        hook = hooks[name];
                        if (!hook) {
                            hooks[name] = hook = { name: Element.normalize(name) };
                        }
                        value = prop[name];
                        value = (value == null) ? '' : value;
                        if (hook.set) {
                            hook.set(dom, value, me);
                        } else {
                            style[hook.name] = value;
                        }
                        if (hook.afterSet) {
                            hook.afterSet(dom, value, me);
                        }
                    }
                }
            }

            return me;
        },

        
        getHeight: function(contentHeight) {
            var dom = this.dom,
                height = contentHeight ? (dom.clientHeight - this.getPadding("tb")) : dom.offsetHeight;
            return height > 0 ? height: 0;
        },

        
        getWidth: function(contentWidth) {
            var dom = this.dom,
                width = contentWidth ? (dom.clientWidth - this.getPadding("lr")) : dom.offsetWidth;
            return width > 0 ? width: 0;
        },

        
        setWidth: function(width) {
            var me = this;
                me.dom.style.width = Element.addUnits(width);
            return me;
        },

        
        setHeight: function(height) {
            var me = this;
                me.dom.style.height = Element.addUnits(height);
            return me;
        },

        
        getBorderWidth: function(side){
            return this.addStyles(side, borders);
        },

        
        getPadding: function(side){
            return this.addStyles(side, paddings);
        },

        margins : margins,

        
        applyStyles: function(styles) {
            if (styles) {
                var i,
                    len,
                    dom = this.dom;

                if (typeof styles == 'function') {
                    styles = styles.call();
                }
                if (typeof styles == 'string') {
                    styles = Ext.util.Format.trim(styles).split(/\s*(?::|;)\s*/);
                    for (i = 0, len = styles.length; i < len;) {
                        dom.style[Element.normalize(styles[i++])] = styles[i++];
                    }
                }
                else if (typeof styles == 'object') {
                    this.setStyle(styles);
                }
            }
        },

        
        setSize: function(width, height) {
            var me = this,
                style = me.dom.style;

            if (Ext.isObject(width)) {
                
                height = width.height;
                width = width.width;
            }

            style.width = Element.addUnits(width);
            style.height = Element.addUnits(height);
            return me;
        },

        
        getViewSize: function() {
            var doc = document,
                dom = this.dom;

            if (dom == doc || dom == doc.body) {
                return {
                    width: Element.getViewportWidth(),
                    height: Element.getViewportHeight()
                };
            }
            else {
                return {
                    width: dom.clientWidth,
                    height: dom.clientHeight
                };
            }
        },

        
        getSize: function(contentSize) {
            var dom = this.dom;
            return {
                width: Math.max(0, contentSize ? (dom.clientWidth - this.getPadding("lr")) : dom.offsetWidth),
                height: Math.max(0, contentSize ? (dom.clientHeight - this.getPadding("tb")) : dom.offsetHeight)
            };
        },

        
        repaint: function(){
            var dom = this.dom;
            this.addCls(Ext.baseCSSPrefix + 'repaint');
            setTimeout(function(){
                Ext.fly(dom).removeCls(Ext.baseCSSPrefix + 'repaint');
            }, 1);
            return this;
        },

        
        getMargin: function(side){
            var me = this,
                hash = {t:"top", l:"left", r:"right", b: "bottom"},
                key,
                o,
                margins;

            if (!side) {
                margins = [];
                for (key in me.margins) {
                    if(me.margins.hasOwnProperty(key)) {
                        margins.push(me.margins[key]);
                    }
                }
                o = me.getStyle(margins);
                if(o && typeof o == 'object') {
                    
                    for (key in me.margins) {
                        if(me.margins.hasOwnProperty(key)) {
                            o[hash[key]] = parseFloat(o[me.margins[key]]) || 0;
                        }
                    }
                }

                return o;
            } else {
                return me.addStyles.call(me, side, me.margins);
            }
        },

        
        mask: function(msg, msgCls, transparent) {
            var me = this,
                dom = me.dom,
                data = (me.$cache || me.getCache()).data,
                el = data.mask,
                mask,
                size,
                cls = '',
                prefix = Ext.baseCSSPrefix;

            me.addCls(prefix + 'masked');
            if (me.getStyle("position") == "static") {
                me.addCls(prefix + 'masked-relative');
            }
            if (el) {
                el.remove();
            }
            if (msgCls && typeof msgCls == 'string' ) {
                cls = ' ' + msgCls;
            }
            else {
                cls = ' ' + prefix + 'mask-gray';
            }

            mask = me.createChild({
                cls: prefix + 'mask' + ((transparent !== false) ? '' : (' ' + prefix + 'mask-gray')),
                html: msg ? ('<div class="' + (msgCls || (prefix + 'mask-message')) + '">' + msg + '</div>') : ''
            });

            size = me.getSize();

            data.mask = mask;

            if (dom === document.body) {
                size.height = window.innerHeight;
                if (me.orientationHandler) {
                    Ext.EventManager.unOrientationChange(me.orientationHandler, me);
                }

                me.orientationHandler = function() {
                    size = me.getSize();
                    size.height = window.innerHeight;
                    mask.setSize(size);
                };

                Ext.EventManager.onOrientationChange(me.orientationHandler, me);
            }
            mask.setSize(size);
            if (Ext.is.iPad) {
                Ext.repaint();
            }
        },

        
        unmask: function() {
            var me = this,
                data = (me.$cache || me.getCache()).data,
                mask = data.mask,
                prefix = Ext.baseCSSPrefix;

            if (mask) {
                mask.remove();
                delete data.mask;
            }
            me.removeCls([prefix + 'masked', prefix + 'masked-relative']);

            if (me.dom === document.body) {
                Ext.EventManager.unOrientationChange(me.orientationHandler, me);
                delete me.orientationHandler;
            }
        }
    });

    
    Element.populateStyleMap = function (map, order) {
        var baseStyles = ['margin-', 'padding-', 'border-width-'],
            beforeAfter = ['before', 'after'],
            index, style, name, i;

        for (index = baseStyles.length; index--; ) {
            for (i = 2; i--; ) {
                style = baseStyles[index] + beforeAfter[i]; 
                
                map[Element.normalize(style)] = map[style] = {
                    name: Element.normalize(baseStyles[index] + order[i])
                };
            }
        }
    };

    Ext.onReady(function () {
        var supports = Ext.supports,
            styleHooks,
            colorStyles, i, name, camel;

        function fixTransparent (dom, el, inline, style) {
            var value = style[this.name] || '';
            return transparentRe.test(value) ? 'transparent' : value;
        }

        function fixRightMargin (dom, el, inline, style) {
            var result = style.marginRight,
                domStyle, display;

            
            
            if (result != '0px') {
                domStyle = dom.style;
                display = domStyle.display;
                domStyle.display = 'inline-block';
                result = (inline ? style : dom.ownerDocument.defaultView.getComputedStyle(dom, null)).marginRight;
                domStyle.display = display;
            }

            return result;
        }

        function fixRightMarginAndInputFocus (dom, el, inline, style) {
            var result = style.marginRight,
                domStyle, cleaner, display;

            if (result != '0px') {
                domStyle = dom.style;
                cleaner = Element.getRightMarginFixCleaner(dom);
                display = domStyle.display;
                domStyle.display = 'inline-block';
                result = (inline ? style : dom.ownerDocument.defaultView.getComputedStyle(dom, '')).marginRight;
                domStyle.display = display;
                cleaner();
            }

            return result;
        }

        styleHooks = Element.prototype.styleHooks;

        
        Element.populateStyleMap(styleHooks, ['left', 'right']);

        
        
        if (supports.init) {
            supports.init();
        }

        
        if (!supports.RightMargin) {
            styleHooks.marginRight = styleHooks['margin-right'] = {
                name: 'marginRight',
                
                
                get: (supports.DisplayChangeInputSelectionBug || supports.DisplayChangeTextAreaSelectionBug) ?
                        fixRightMarginAndInputFocus : fixRightMargin
            };
        }

        if (!supports.TransparentColor) {
            colorStyles = ['background-color', 'border-color', 'color', 'outline-color'];
            for (i = colorStyles.length; i--; ) {
                name = colorStyles[i];
                camel = Element.normalize(name);

                styleHooks[name] = styleHooks[camel] = {
                    name: camel,
                    get: fixTransparent
                };
            }
        }
    });
}());


Ext.dom.AbstractElement.override({
    
    findParent: function(simpleSelector, limit, returnEl) {
        var target = this.dom,
            topmost = document.documentElement,
            depth = 0,
            stopEl;

        limit = limit || 50;
        if (isNaN(limit)) {
            stopEl = Ext.getDom(limit);
            limit = Number.MAX_VALUE;
        }
        while (target && target.nodeType == 1 && depth < limit && target != topmost && target != stopEl) {
            if (Ext.DomQuery.is(target, simpleSelector)) {
                return returnEl ? Ext.get(target) : target;
            }
            depth++;
            target = target.parentNode;
        }
        return null;
    },

    
    findParentNode: function(simpleSelector, limit, returnEl) {
        var p = Ext.fly(this.dom.parentNode, '_internal');
        return p ? p.findParent(simpleSelector, limit, returnEl) : null;
    },

    
    up: function(simpleSelector, limit) {
        return this.findParentNode(simpleSelector, limit, true);
    },

    
    select: function(selector, composite) {
        return Ext.dom.Element.select(selector, this.dom, composite);
    },

    
    query: function(selector) {
        return Ext.DomQuery.select(selector, this.dom);
    },

    
    down: function(selector, returnDom) {
        var n = Ext.DomQuery.selectNode(selector, this.dom);
        return returnDom ? n : Ext.get(n);
    },

    
    child: function(selector, returnDom) {
        var node,
            me = this,
            id;

        
        
        id = Ext.id(me.dom);
        
        id = Ext.escapeId(id);
        node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
        return returnDom ? node : Ext.get(node);
    },

     
    parent: function(selector, returnDom) {
        return this.matchNode('parentNode', 'parentNode', selector, returnDom);
    },

     
    next: function(selector, returnDom) {
        return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
    },

    
    prev: function(selector, returnDom) {
        return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
    },


    
    first: function(selector, returnDom) {
        return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
    },

    
    last: function(selector, returnDom) {
        return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
    },

    matchNode: function(dir, start, selector, returnDom) {
        if (!this.dom) {
            return null;
        }

        var n = this.dom[start];
        while (n) {
            if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
                return !returnDom ? Ext.get(n) : n;
            }
            n = n[dir];
        }
        return null;
    },

    isAncestor: function(element) {
        return this.self.isAncestor.call(this.self, this.dom, element);
    }
});


(function() {


var afterbegin = 'afterbegin',
    afterend = 'afterend',
    beforebegin = 'beforebegin',
    beforeend = 'beforeend',
    ts = '<table>',
    te = '</table>',
    tbs = ts+'<tbody>',
    tbe = '</tbody>'+te,
    trs = tbs + '<tr>',
    tre = '</tr>'+tbe,
    detachedDiv = document.createElement('div'),
    bbValues = ['BeforeBegin', 'previousSibling'],
    aeValues = ['AfterEnd', 'nextSibling'],
    bb_ae_PositionHash = {
        beforebegin: bbValues,
        afterend: aeValues
    },
    fullPositionHash = {
        beforebegin: bbValues,
        afterend: aeValues,
        afterbegin: ['AfterBegin', 'firstChild'],
        beforeend: ['BeforeEnd', 'lastChild']
    };


Ext.define('Ext.dom.Helper', {
    extend: 'Ext.dom.AbstractHelper',

    tableRe: /^table|tbody|tr|td$/i,

    tableElRe: /td|tr|tbody/i,

    
    useDom : false,

    
    createDom: function(o, parentNode){
        var el,
            doc = document,
            useSet,
            attr,
            val,
            cn,
            i, l;

        if (Ext.isArray(o)) {                       
            el = doc.createDocumentFragment(); 
            for (i = 0, l = o.length; i < l; i++) {
                this.createDom(o[i], el);
            }
        } else if (typeof o == 'string') {         
            el = doc.createTextNode(o);
        } else {
            el = doc.createElement(o.tag || 'div');
            useSet = !!el.setAttribute; 
            for (attr in o) {
                if (!this.confRe.test(attr)) {
                    val = o[attr];
                    if (attr == 'cls') {
                        el.className = val;
                    } else {
                        if (useSet) {
                            el.setAttribute(attr, val);
                        } else {
                            el[attr] = val;
                        }
                    }
                }
            }
            Ext.DomHelper.applyStyles(el, o.style);

            if ((cn = o.children || o.cn)) {
                this.createDom(cn, el);
            } else if (o.html) {
                el.innerHTML = o.html;
            }
        }
        if (parentNode) {
            parentNode.appendChild(el);
        }
        return el;
    },

    ieTable: function(depth, openingTags, htmlContent, closingTags){
        detachedDiv.innerHTML = [openingTags, htmlContent, closingTags].join('');

        var i = -1,
            el = detachedDiv,
            ns;

        while (++i < depth) {
            el = el.firstChild;
        }
        
        ns = el.nextSibling;

        if (ns) {
            el = document.createDocumentFragment();
            while (ns) {
                el.appendChild(ns);
                ns = ns.nextSibling;
            }
        }
        return el;
    },

    
    insertIntoTable: function(tag, where, destinationEl, html) {
        var node,
            before,
            bb = where == beforebegin,
            ab = where == afterbegin,
            be = where == beforeend,
            ae = where == afterend;

        if (tag == 'td' && (ab || be) || !this.tableElRe.test(tag) && (bb || ae)) {
            return null;
        }
        before = bb ? destinationEl :
                 ae ? destinationEl.nextSibling :
                 ab ? destinationEl.firstChild : null;

        if (bb || ae) {
            destinationEl = destinationEl.parentNode;
        }

        if (tag == 'td' || (tag == 'tr' && (be || ab))) {
            node = this.ieTable(4, trs, html, tre);
        } else if ((tag == 'tbody' && (be || ab)) ||
                (tag == 'tr' && (bb || ae))) {
            node = this.ieTable(3, tbs, html, tbe);
        } else {
            node = this.ieTable(2, ts, html, te);
        }
        destinationEl.insertBefore(node, before);
        return node;
    },

    
    createContextualFragment: function(html) {
        var fragment = document.createDocumentFragment(),
            length, childNodes;

        detachedDiv.innerHTML = html;
        childNodes = detachedDiv.childNodes;
        length = childNodes.length;

        
        while (length--) {
            fragment.appendChild(childNodes[0]);
        }
        return fragment;
    },

    applyStyles: function(el, styles) {
        if (styles) {
            el = Ext.fly(el);
            if (typeof styles == "function") {
                styles = styles.call();
            }
            if (typeof styles == "string") {
                styles = Ext.dom.Element.parseStyles(styles);
            }
            if (typeof styles == "object") {
                el.setStyle(styles);
            }
        }
    },

    
    createHtml: function(spec) {
        return this.markup(spec);
    },

    doInsert: function(el, o, returnElement, pos, sibling, append) {
        
        el = el.dom || Ext.getDom(el);

        var newNode;

        if (this.useDom) {
            newNode = this.createDom(o, null);

            if (append) {
                el.appendChild(newNode);
            }
            else {
                (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
            }

        } else {
            newNode = this.insertHtml(pos, el, this.markup(o));
        }
        return returnElement ? Ext.get(newNode, true) : newNode;
    },

    
    overwrite: function(el, html, returnElement) {
        var newNode;

        el = Ext.getDom(el);
        html = this.markup(html);

        
        if (Ext.isIE && this.tableRe.test(el.tagName)) {
            
            while (el.firstChild) {
                el.removeChild(el.firstChild);
            }
            if (html) {
                newNode = this.insertHtml('afterbegin', el, html);
                return returnElement ? Ext.get(newNode) : newNode;
            }
            return null;
        }
        el.innerHTML = html;
        return returnElement ? Ext.get(el.firstChild) : el.firstChild;
    },

    insertHtml: function(where, el, html) {
        var hashVal,
            range,
            rangeEl,
            setStart,
            frag;

        where = where.toLowerCase();

        
        if (el.insertAdjacentHTML) {

            
            if (Ext.isIE && this.tableRe.test(el.tagName) && (frag = this.insertIntoTable(el.tagName.toLowerCase(), where, el, html))) {
                return frag;
            }

            if ((hashVal = fullPositionHash[where])) {
                el.insertAdjacentHTML(hashVal[0], html);
                return el[hashVal[1]];
            }
            
        } else {
            
            if (el.nodeType === 3) {
                where = where === 'afterbegin' ? 'beforebegin' : where;
                where = where === 'beforeend' ? 'afterend' : where;
            }
            range = Ext.supports.CreateContextualFragment ? el.ownerDocument.createRange() : undefined;
            setStart = 'setStart' + (this.endRe.test(where) ? 'After' : 'Before');
            if (bb_ae_PositionHash[where]) {
                if (range) {
                    range[setStart](el);
                    frag = range.createContextualFragment(html);
                } else {
                    frag = this.createContextualFragment(html);
                }
                el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
                return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
            } else {
                rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
                if (el.firstChild) {
                    if (range) {
                        range[setStart](el[rangeEl]);
                        frag = range.createContextualFragment(html);
                    } else {
                        frag = this.createContextualFragment(html);
                    }

                    if (where == afterbegin) {
                        el.insertBefore(frag, el.firstChild);
                    } else {
                        el.appendChild(frag);
                    }
                } else {
                    el.innerHTML = html;
                }
                return el[rangeEl];
            }
        }
    },

    
    createTemplate: function(o) {
        var html = this.markup(o);
        return new Ext.Template(html);
    }

}, function() {
    Ext.ns('Ext.core');
    Ext.DomHelper = Ext.core.DomHelper = new this;
});


}());



Ext.ns('Ext.core');

Ext.dom.Query = Ext.core.DomQuery = Ext.DomQuery = (function(){
    var cache = {},
        simpleCache = {},
        valueCache = {},
        nonSpace = /\S/,
        trimRe = /^\s+|\s+$/g,
        tplRe = /\{(\d+)\}/g,
        modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
        tagTokenRe = /^(#)?([\w\-\*\\]+)/,
        nthRe = /(\d*)n\+?(\d*)/,
        nthRe2 = /\D/,
        startIdRe = /^\s*\#/,
        
        
        
        isIE = window.ActiveXObject ? true : false,
        key = 30803,
        longHex = /\\([0-9a-fA-F]{6})/g,
        shortHex = /\\([0-9a-fA-F]{1,6})\s{0,1}/g,
        nonHex = /\\([^0-9a-fA-F]{1})/g,
        escapes = /\\/g,
        num, hasEscapes,

        
        
        longHexToChar = function($0, $1) {
            return String.fromCharCode(parseInt($1, 16));
        },

        
        shortToLongHex = function($0, $1) {
            while ($1.length < 6) {
                $1 = '0' + $1;
            }
            return '\\' + $1;
        },

        
        charToLongHex = function($0, $1) {
            num = $1.charCodeAt(0).toString(16);
            if (num.length === 1) {
                num = '0' + num;
            }
            return '\\0000' + num;
        },

        
        
        
        unescapeCssSelector = function (selector) {
            return (hasEscapes)
                ? selector.replace(longHex, longHexToChar)
                : selector;
        },
        
        
        setupEscapes = function(path){
            hasEscapes = (path.indexOf('\\') > -1);
            if (hasEscapes) {
                path = path
                    .replace(shortHex, shortToLongHex)
                    .replace(nonHex, charToLongHex)
                    .replace(escapes, '\\\\');  
            }
            return path;
        };

    
    
    eval("var batch = 30803;");

    
    
    function child(parent, index){
        var i = 0,
            n = parent.firstChild;
        while(n){
            if(n.nodeType == 1){
               if(++i == index){
                   return n;
               }
            }
            n = n.nextSibling;
        }
        return null;
    }

    
    function next(n){
        while((n = n.nextSibling) && n.nodeType != 1);
        return n;
    }

    
    function prev(n){
        while((n = n.previousSibling) && n.nodeType != 1);
        return n;
    }

    
    
    function children(parent){
        var n = parent.firstChild,
        nodeIndex = -1,
        nextNode;
        while(n){
            nextNode = n.nextSibling;
            
            if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
                parent.removeChild(n);
            }else{
                
                n.nodeIndex = ++nodeIndex;
            }
            n = nextNode;
        }
        return this;
    }

    
    
    function byClassName(nodeSet, cls){
        cls = unescapeCssSelector(cls);
        if(!cls){
            return nodeSet;
        }
        var result = [], ri = -1,
            i, ci;
        for(i = 0, ci; ci = nodeSet[i]; i++){
            if((' '+ci.className+' ').indexOf(cls) != -1){
                result[++ri] = ci;
            }
        }
        return result;
    }

    function attrValue(n, attr){
        
        if(!n.tagName && typeof n.length != "undefined"){
            n = n[0];
        }
        if(!n){
            return null;
        }

        if(attr == "for"){
            return n.htmlFor;
        }
        if(attr == "class" || attr == "className"){
            return n.className;
        }
        return n.getAttribute(attr) || n[attr];

    }


    
    
    
    function getNodes(ns, mode, tagName){
        var result = [], ri = -1, cs,
            i, ni, j, ci, cn, utag, n, cj;
        if(!ns){
            return result;
        }
        tagName = tagName || "*";
        
        if(typeof ns.getElementsByTagName != "undefined"){
            ns = [ns];
        }

        
        
        if(!mode){
            for(i = 0, ni; ni = ns[i]; i++){
                cs = ni.getElementsByTagName(tagName);
                for(j = 0, ci; ci = cs[j]; j++){
                    result[++ri] = ci;
                }
            }
        
        
        } else if(mode == "/" || mode == ">"){
            utag = tagName.toUpperCase();
            for(i = 0, ni, cn; ni = ns[i]; i++){
                cn = ni.childNodes;
                for(j = 0, cj; cj = cn[j]; j++){
                    if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
                        result[++ri] = cj;
                    }
                }
            }
        
        
        }else if(mode == "+"){
            utag = tagName.toUpperCase();
            for(i = 0, n; n = ns[i]; i++){
                while((n = n.nextSibling) && n.nodeType != 1);
                if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
                    result[++ri] = n;
                }
            }
        
        
        }else if(mode == "~"){
            utag = tagName.toUpperCase();
            for(i = 0, n; n = ns[i]; i++){
                while((n = n.nextSibling)){
                    if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
                        result[++ri] = n;
                    }
                }
            }
        }
        return result;
    }

    function concat(a, b){
        if(b.slice){
            return a.concat(b);
        }
        for(var i = 0, l = b.length; i < l; i++){
            a[a.length] = b[i];
        }
        return a;
    }

    function byTag(cs, tagName){
        if(cs.tagName || cs == document){
            cs = [cs];
        }
        if(!tagName){
            return cs;
        }
        var result = [], ri = -1,
            i, ci;
        tagName = tagName.toLowerCase();
        for(i = 0, ci; ci = cs[i]; i++){
            if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
                result[++ri] = ci;
            }
        }
        return result;
    }

    function byId(cs, id){
        id = unescapeCssSelector(id);
        if(cs.tagName || cs == document){
            cs = [cs];
        }
        if(!id){
            return cs;
        }
        var result = [], ri = -1,
            i, ci;
        for(i = 0, ci; ci = cs[i]; i++){
            if(ci && ci.id == id){
                result[++ri] = ci;
                return result;
            }
        }
        return result;
    }

    
    
    function byAttribute(cs, attr, value, op, custom){
        var result = [],
            ri = -1,
            useGetStyle = custom == "{",
            fn = Ext.DomQuery.operators[op],
            a,
            xml,
            hasXml,
            i, ci;

        value = unescapeCssSelector(value);

        for(i = 0, ci; ci = cs[i]; i++){
            
            if(ci.nodeType != 1){
                continue;
            }
            
            if(!hasXml){
                xml = Ext.DomQuery.isXml(ci);
                hasXml = true;
            }

            
            if(!xml){
                if(useGetStyle){
                    a = Ext.DomQuery.getStyle(ci, attr);
                } else if (attr == "class" || attr == "className"){
                    a = ci.className;
                } else if (attr == "for"){
                    a = ci.htmlFor;
                } else if (attr == "href"){
                    
                    
                    a = ci.getAttribute("href", 2);
                } else{
                    a = ci.getAttribute(attr);
                }
            }else{
                a = ci.getAttribute(attr);
            }
            if((fn && fn(a, value)) || (!fn && a)){
                result[++ri] = ci;
            }
        }
        return result;
    }

    function byPseudo(cs, name, value){
        value = unescapeCssSelector(value);
        return Ext.DomQuery.pseudos[name](cs, value);
    }

    function nodupIEXml(cs){
        var d = ++key,
            r,
            i, len, c;
        cs[0].setAttribute("_nodup", d);
        r = [cs[0]];
        for(i = 1, len = cs.length; i < len; i++){
            c = cs[i];
            if(!c.getAttribute("_nodup") != d){
                c.setAttribute("_nodup", d);
                r[r.length] = c;
            }
        }
        for(i = 0, len = cs.length; i < len; i++){
            cs[i].removeAttribute("_nodup");
        }
        return r;
    }

    function nodup(cs){
        if(!cs){
            return [];
        }
        var len = cs.length, c, i, r = cs, cj, ri = -1, d, j;
        if(!len || typeof cs.nodeType != "undefined" || len == 1){
            return cs;
        }
        if(isIE && typeof cs[0].selectSingleNode != "undefined"){
            return nodupIEXml(cs);
        }
        d = ++key;
        cs[0]._nodup = d;
        for(i = 1; c = cs[i]; i++){
            if(c._nodup != d){
                c._nodup = d;
            }else{
                r = [];
                for(j = 0; j < i; j++){
                    r[++ri] = cs[j];
                }
                for(j = i+1; cj = cs[j]; j++){
                    if(cj._nodup != d){
                        cj._nodup = d;
                        r[++ri] = cj;
                    }
                }
                return r;
            }
        }
        return r;
    }

    function quickDiffIEXml(c1, c2){
        var d = ++key,
            r = [],
            i, len;
        for(i = 0, len = c1.length; i < len; i++){
            c1[i].setAttribute("_qdiff", d);
        }
        for(i = 0, len = c2.length; i < len; i++){
            if(c2[i].getAttribute("_qdiff") != d){
                r[r.length] = c2[i];
            }
        }
        for(i = 0, len = c1.length; i < len; i++){
           c1[i].removeAttribute("_qdiff");
        }
        return r;
    }

    function quickDiff(c1, c2){
        var len1 = c1.length,
            d = ++key,
            r = [],
            i, len;
        if(!len1){
            return c2;
        }
        if(isIE && typeof c1[0].selectSingleNode != "undefined"){
            return quickDiffIEXml(c1, c2);
        }
        for(i = 0; i < len1; i++){
            c1[i]._qdiff = d;
        }
        for(i = 0, len = c2.length; i < len; i++){
            if(c2[i]._qdiff != d){
                r[r.length] = c2[i];
            }
        }
        return r;
    }

    function quickId(ns, mode, root, id){
        if(ns == root){
            id = unescapeCssSelector(id);
            var d = root.ownerDocument || root;
            return d.getElementById(id);
        }
        ns = getNodes(ns, mode, "*");
        return byId(ns, id);
    }

    return {
        getStyle : function(el, name){
            return Ext.fly(el).getStyle(name);
        },
        
        compile : function(path, type){
            type = type || "select";

            
            var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
                mode,
                lastPath,
                matchers = Ext.DomQuery.matchers,
                matchersLn = matchers.length,
                modeMatch,
                
                lmode = path.match(modeRe),
                tokenMatch, matched, j, t, m;

            path = setupEscapes(path);

            if(lmode && lmode[1]){
                fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
                path = path.replace(lmode[1], "");
            }

            
            while(path.substr(0, 1)=="/"){
                path = path.substr(1);
            }

            while(path && lastPath != path){
                lastPath = path;
                tokenMatch = path.match(tagTokenRe);
                if(type == "select"){
                    if(tokenMatch){
                        
                        if(tokenMatch[1] == "#"){
                            fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
                        }else{
                            fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
                        }
                        path = path.replace(tokenMatch[0], "");
                    }else if(path.substr(0, 1) != '@'){
                        fn[fn.length] = 'n = getNodes(n, mode, "*");';
                    }
                
                }else{
                    if(tokenMatch){
                        if(tokenMatch[1] == "#"){
                            fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
                        }else{
                            fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
                        }
                        path = path.replace(tokenMatch[0], "");
                    }
                }
                while(!(modeMatch = path.match(modeRe))){
                    matched = false;
                    for(j = 0; j < matchersLn; j++){
                        t = matchers[j];
                        m = path.match(t.re);
                        if(m){
                            fn[fn.length] = t.select.replace(tplRe, function(x, i){
                                return m[i];
                            });
                            path = path.replace(m[0], "");
                            matched = true;
                            break;
                        }
                    }
                    
                    if(!matched){
                        Ext.Error.raise({
                            sourceClass: 'Ext.DomQuery',
                            sourceMethod: 'compile',
                            msg: 'Error parsing selector. Parsing failed at "' + path + '"'
                        });
                    }
                }
                if(modeMatch[1]){
                    fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
                    path = path.replace(modeMatch[1], "");
                }
            }
            
            fn[fn.length] = "return nodup(n);\n}";

            
            eval(fn.join(""));
            return f;
        },

        
        jsSelect: function(path, root, type){
            
            root = root || document;

            if(typeof root == "string"){
                root = document.getElementById(root);
            }
            var paths = path.split(","),
                results = [],
                i, len, subPath, result;

            
            for(i = 0, len = paths.length; i < len; i++){
                subPath = paths[i].replace(trimRe, "");
                
                if(!cache[subPath]){
                    
                    cache[subPath] = Ext.DomQuery.compile(subPath, type);
                    if(!cache[subPath]){
                        Ext.Error.raise({
                            sourceClass: 'Ext.DomQuery',
                            sourceMethod: 'jsSelect',
                            msg: subPath + ' is not a valid selector'
                        });
                    }
                } else {
                    
                    
                    setupEscapes(subPath);
                }
                result = cache[subPath](root);
                if(result && result != document){
                    results = results.concat(result);
                }
            }

            
            
            if(paths.length > 1){
                return nodup(results);
            }
            return results;
        },

        isXml: function(el) {
            var docEl = (el ? el.ownerDocument || el : 0).documentElement;
            return docEl ? docEl.nodeName !== "HTML" : false;
        },

        
        select : document.querySelectorAll ? function(path, root, type) {
            root = root || document;
            if (!Ext.DomQuery.isXml(root)) {
                try {
                    
                    if (root.parentNode && (root.nodeType !== 9) && path.indexOf(',') === -1 && !startIdRe.test(path)) {
                        path = '#' + Ext.escapeId(Ext.id(root)) + ' ' + path;
                        root = root.parentNode;
                    }
                    return Ext.Array.toArray(root.querySelectorAll(path));
                }
                catch (e) {
                }
            }
            return Ext.DomQuery.jsSelect.call(this, path, root, type);
        } : function(path, root, type) {
            return Ext.DomQuery.jsSelect.call(this, path, root, type);
        },

        
        selectNode : function(path, root){
            return Ext.DomQuery.select(path, root)[0];
        },

        
        selectValue : function(path, root, defaultValue){
            path = path.replace(trimRe, "");
            if (!valueCache[path]) {
                valueCache[path] = Ext.DomQuery.compile(path, "select");
            } else {
                setupEscapes(path);
            }
            
            var n = valueCache[path](root), 
                v;
                
            n = n[0] ? n[0] : n;

            
            
            
            
            if (typeof n.normalize == 'function') {
                n.normalize();
            }

            v = (n && n.firstChild ? n.firstChild.nodeValue : null);
            return ((v === null||v === undefined||v==='') ? defaultValue : v);
        },

        
        selectNumber : function(path, root, defaultValue){
            var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
            return parseFloat(v);
        },

        
        is : function(el, ss){
            if(typeof el == "string"){
                el = document.getElementById(el);
            }
            var isArray = Ext.isArray(el),
                result = Ext.DomQuery.filter(isArray ? el : [el], ss);
            return isArray ? (result.length == el.length) : (result.length > 0);
        },

        
        filter : function(els, ss, nonMatches){
            ss = ss.replace(trimRe, "");
            if (!simpleCache[ss]) {
                simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
            } else {
                setupEscapes(ss);
            }
            
            var result = simpleCache[ss](els);
            return nonMatches ? quickDiff(result, els) : result;
        },

        
        matchers : [{
                re: /^\.([\w\-\\]+)/,
                select: 'n = byClassName(n, " {1} ");'
            }, {
                re: /^\:([\w\-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
                select: 'n = byPseudo(n, "{1}", "{2}");'
            },{
                re: /^(?:([\[\{])(?:@)?([\w\-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
                select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
            }, {
                re: /^#([\w\-\\]+)/,
                select: 'n = byId(n, "{1}");'
            },{
                re: /^@([\w\-]+)/,
                select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
            }
        ],

        
        operators : {
            "=" : function(a, v){
                return a == v;
            },
            "!=" : function(a, v){
                return a != v;
            },
            "^=" : function(a, v){
                return a && a.substr(0, v.length) == v;
            },
            "$=" : function(a, v){
                return a && a.substr(a.length-v.length) == v;
            },
            "*=" : function(a, v){
                return a && a.indexOf(v) !== -1;
            },
            "%=" : function(a, v){
                return (a % v) == 0;
            },
            "|=" : function(a, v){
                return a && (a == v || a.substr(0, v.length+1) == v+'-');
            },
            "~=" : function(a, v){
                return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
            }
        },

        
        pseudos : {
            "first-child" : function(c){
                var r = [], ri = -1, n,
                    i, ci;
                for(i = 0; (ci = n = c[i]); i++){
                    while((n = n.previousSibling) && n.nodeType != 1);
                    if(!n){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "last-child" : function(c){
                var r = [], ri = -1, n,
                    i, ci;
                for(i = 0; (ci = n = c[i]); i++){
                    while((n = n.nextSibling) && n.nodeType != 1);
                    if(!n){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "nth-child" : function(c, a) {
                var r = [], ri = -1,
                    m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
                    f = (m[1] || 1) - 0, l = m[2] - 0,
                    i, n, j, cn, pn;
                for(i = 0; n = c[i]; i++){
                    pn = n.parentNode;
                    if (batch != pn._batch) {
                        j = 0;
                        for(cn = pn.firstChild; cn; cn = cn.nextSibling){
                            if(cn.nodeType == 1){
                               cn.nodeIndex = ++j;
                            }
                        }
                        pn._batch = batch;
                    }
                    if (f == 1) {
                        if (l == 0 || n.nodeIndex == l){
                            r[++ri] = n;
                        }
                    } else if ((n.nodeIndex + l) % f == 0){
                        r[++ri] = n;
                    }
                }

                return r;
            },

            "only-child" : function(c){
                var r = [], ri = -1,
                    i, ci;
                for(i = 0; ci = c[i]; i++){
                    if(!prev(ci) && !next(ci)){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "empty" : function(c){
                var r = [], ri = -1,
                    i, ci, cns, j, cn, empty;
                for(i = 0, ci; ci = c[i]; i++){
                    cns = ci.childNodes;
                    j = 0;
                    empty = true;
                    while(cn = cns[j]){
                        ++j;
                        if(cn.nodeType == 1 || cn.nodeType == 3){
                            empty = false;
                            break;
                        }
                    }
                    if(empty){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "contains" : function(c, v){
                var r = [], ri = -1,
                    i, ci;
                for(i = 0; ci = c[i]; i++){
                    if((ci.textContent||ci.innerText||ci.text||'').indexOf(v) != -1){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "nodeValue" : function(c, v){
                var r = [], ri = -1,
                    i, ci;
                for(i = 0; ci = c[i]; i++){
                    if(ci.firstChild && ci.firstChild.nodeValue == v){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "checked" : function(c){
                var r = [], ri = -1,
                    i, ci;
                for(i = 0; ci = c[i]; i++){
                    if(ci.checked == true){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "not" : function(c, ss){
                return Ext.DomQuery.filter(c, ss, true);
            },

            "any" : function(c, selectors){
                var ss = selectors.split('|'),
                    r = [], ri = -1, s,
                    i, ci, j;
                for(i = 0; ci = c[i]; i++){
                    for(j = 0; s = ss[j]; j++){
                        if(Ext.DomQuery.is(ci, s)){
                            r[++ri] = ci;
                            break;
                        }
                    }
                }
                return r;
            },

            "odd" : function(c){
                return this["nth-child"](c, "odd");
            },

            "even" : function(c){
                return this["nth-child"](c, "even");
            },

            "nth" : function(c, a){
                return c[a-1] || [];
            },

            "first" : function(c){
                return c[0] || [];
            },

            "last" : function(c){
                return c[c.length-1] || [];
            },

            "has" : function(c, ss){
                var s = Ext.DomQuery.select,
                    r = [], ri = -1,
                    i, ci;
                for(i = 0; ci = c[i]; i++){
                    if(s(ss, ci).length > 0){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "next" : function(c, ss){
                var is = Ext.DomQuery.is,
                    r = [], ri = -1,
                    i, ci, n;
                for(i = 0; ci = c[i]; i++){
                    n = next(ci);
                    if(n && is(n, ss)){
                        r[++ri] = ci;
                    }
                }
                return r;
            },

            "prev" : function(c, ss){
                var is = Ext.DomQuery.is,
                    r = [], ri = -1,
                    i, ci, n;
                for(i = 0; ci = c[i]; i++){
                    n = prev(ci);
                    if(n && is(n, ss)){
                        r[++ri] = ci;
                    }
                }
                return r;
            }
        }
    };
}());


Ext.query = Ext.DomQuery.select;



(function() {

var HIDDEN = 'hidden',
    DOC             = document,
    VISIBILITY      = "visibility",
    DISPLAY         = "display",
    NONE            = "none",
    XMASKED         = Ext.baseCSSPrefix + "masked",
    XMASKEDRELATIVE = Ext.baseCSSPrefix + "masked-relative",
    EXTELMASKMSG    = Ext.baseCSSPrefix + "mask-msg",
    bodyRe          = /^body/i,
    visFly,

    
    noBoxAdjust = Ext.isStrict ? {
        select: 1
    }: {
        input: 1,
        select: 1,
        textarea: 1
    },

    
    isScrolled = function(c) {
        var r = [], ri = -1,
            i, ci;
        for (i = 0; ci = c[i]; i++) {
            if (ci.scrollTop > 0 || ci.scrollLeft > 0) {
                r[++ri] = ci;
            }
        }
        return r;
    },

    Element = Ext.define('Ext.dom.Element', {

    extend: 'Ext.dom.AbstractElement',

    alternateClassName: ['Ext.Element', 'Ext.core.Element'],

    addUnits: function() {
        return this.self.addUnits.apply(this.self, arguments);
    },

    
    focus: function(defer,  dom) {
        var me = this,
            scrollTop,
            body;

        dom = dom || me.dom;
        body = (dom.ownerDocument || DOC).body || DOC.body;
        try {
            if (Number(defer)) {
                Ext.defer(me.focus, defer, me, [null, dom]);
            } else {
                
                
                if (dom.offsetHeight > Element.getViewHeight()) {
                    scrollTop = body.scrollTop;
                }
                dom.focus();
                if (scrollTop !== undefined) {
                    body.scrollTop = scrollTop;
                }
            }
        } catch(e) {
        }
        return me;
    },

    
    blur: function() {
        try {
            this.dom.blur();
        } catch(e) {
        }
        return this;
    },

    
    isBorderBox: function() {
        var box = Ext.isBorderBox;
        if (box) {
            box = !((this.dom.tagName || "").toLowerCase() in noBoxAdjust);
        }
        return box;
    },

    
    hover: function(overFn, outFn, scope, options) {
        var me = this;
        me.on('mouseenter', overFn, scope || me.dom, options);
        me.on('mouseleave', outFn, scope || me.dom, options);
        return me;
    },

    
    getAttributeNS: function(ns, name) {
        return this.getAttribute(name, ns);
    },

    getAttribute: (Ext.isIE && !(Ext.isIE9 && DOC.documentMode === 9)) ?
        function(name, ns) {
            var d = this.dom,
                    type;
            if (ns) {
                type = typeof d[ns + ":" + name];
                if (type != 'undefined' && type != 'unknown') {
                    return d[ns + ":" + name] || null;
                }
                return null;
            }
            if (name === "for") {
                name = "htmlFor";
            }
            return d[name] || null;
        } : function(name, ns) {
            var d = this.dom;
            if (ns) {
                return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name);
            }
            return  d.getAttribute(name) || d[name] || null;
        },

    
    cacheScrollValues: function() {
        var me = this,
            scrolledDescendants,
            el, i,
            scrollValues = [],
            result = function() {
                for (i = 0; i < scrolledDescendants.length; i++) {
                    el = scrolledDescendants[i];
                    el.scrollLeft = scrollValues[i][0];
                    el.scrollTop  = scrollValues[i][1];
                }
            };

        if (!Ext.DomQuery.pseudos.isScrolled) {
            Ext.DomQuery.pseudos.isScrolled = isScrolled;
        }
        scrolledDescendants = me.query(':isScrolled');
        for (i = 0; i < scrolledDescendants.length; i++) {
            el = scrolledDescendants[i];
            scrollValues[i] = [el.scrollLeft, el.scrollTop];
        }
        return result;
    },

    
    autoBoxAdjust: true,

    
    isVisible : function(deep) {
        var me = this,
            dom = me.dom,
            stopNode = dom.ownerDocument.documentElement;

        if (!visFly) {
            visFly = new Element.Fly();
        }

        while (dom !== stopNode) {
            
            
            if (!dom || dom.nodeType === 11 || (visFly.attach(dom)).isStyle(VISIBILITY, HIDDEN) || visFly.isStyle(DISPLAY, NONE)) {
                return false;
            }
            
            if (!deep) {
                break;
            }
            dom = dom.parentNode;
        }
        return true;
    },

    
    isDisplayed : function() {
        return !this.isStyle(DISPLAY, NONE);
    },

    
    enableDisplayMode : function(display) {
        var me = this;
        
        me.setVisibilityMode(Element.DISPLAY);

        if (!Ext.isEmpty(display)) {
            (me.$cache || me.getCache()).data.originalDisplay = display;
        }

        return me;
    },

    
    mask : function(msg, msgCls , elHeight) {
        var me            = this,
            dom           = me.dom,
            
            
            setExpression = dom.style.setExpression,
            data          = (me.$cache || me.getCache()).data,
            maskEl        = data.maskEl,
            maskMsg       = data.maskMsg;

        if (!(bodyRe.test(dom.tagName) && me.getStyle('position') == 'static')) {
            me.addCls(XMASKEDRELATIVE);
        }
        
        
        if (maskEl) {
            maskEl.remove();
        }
        
        if (maskMsg) {
            maskMsg.remove();
        }

        Ext.DomHelper.append(dom, [{
            cls : Ext.baseCSSPrefix + "mask"
        }, {
            cls : msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG,
            cn  : {
                tag: 'div',
                html: msg || ''
            }
        }]);
            
        maskMsg = Ext.get(dom.lastChild);
        maskEl = Ext.get(maskMsg.dom.previousSibling);
        data.maskMsg = maskMsg;
        data.maskEl = maskEl;

        me.addCls(XMASKED);
        maskEl.setDisplayed(true);

        if (typeof msg == 'string') {
            maskMsg.setDisplayed(true);
            maskMsg.center(me);
        } else {
            maskMsg.setDisplayed(false);
        }
        
        
        
        
        
        if (!Ext.supports.IncludePaddingInWidthCalculation && setExpression) {
            
            try {
                maskEl.dom.style.setExpression('width', 'this.parentNode.clientWidth + "px"');
            } catch (e) {}
        }

        
        
        if (!Ext.supports.IncludePaddingInHeightCalculation && setExpression) {
            
            try {
                maskEl.dom.style.setExpression('height', 'this.parentNode.' + (dom == DOC.body ? 'scrollHeight' : 'offsetHeight') + ' + "px"');
            } catch (e) {}
        }
        
        else if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto') {
            maskEl.setSize(undefined, elHeight || me.getHeight());
        }
        return maskEl;
    },

    
    unmask : function() {
        var me      = this,
            data    = (me.$cache || me.getCache()).data,
            maskEl  = data.maskEl,
            maskMsg = data.maskMsg,
            style;

        if (maskEl) {
            style = maskEl.dom.style;
            
            if (style.clearExpression) {
                style.clearExpression('width');
                style.clearExpression('height');
            }
            
            if (maskEl) {
                maskEl.remove();
                delete data.maskEl;
            }
            
            if (maskMsg) {
                maskMsg.remove();
                delete data.maskMsg;
            }
            
            me.removeCls([XMASKED, XMASKEDRELATIVE]);
        }
    },

    
    isMasked : function() {
        var me      = this,
            data    = (me.$cache || me.getCache()).data,
            maskEl  = data.maskEl,
            maskMsg = data.maskMsg,
            hasMask = false; 

        if (maskEl && maskEl.isVisible()) {
            if (maskMsg) {
                maskMsg.center(me);
            }
            hasMask = true;
        }
        return hasMask;
    },

    
    createShim : function() {
        var el = DOC.createElement('iframe'),
            shim;

        el.frameBorder = '0';
        el.className = Ext.baseCSSPrefix + 'shim';
        el.src = Ext.SSL_SECURE_URL;
        shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
        shim.autoBoxAdjust = false;
        return shim;
    },

    
    addKeyListener : function(key, fn, scope){
        var config;
        if(typeof key != 'object' || Ext.isArray(key)){
            config = {
                target: this,
                key: key,
                fn: fn,
                scope: scope
            };
        }else{
            config = {
                target: this,
                key : key.key,
                shift : key.shift,
                ctrl : key.ctrl,
                alt : key.alt,
                fn: fn,
                scope: scope
            };
        }
        return new Ext.util.KeyMap(config);
    },

    
    addKeyMap : function(config) {
        return new Ext.util.KeyMap(Ext.apply({
            target: this
        }, config));
    },

    
    
    
    
    
    
    
    
    
    
    

    
    
    
    

    
    
    
    
    
    
    

    
    
    
    
    
    
    

    
    
    
    

    
    
    
    
    
    
    
    

    
    on: function(eventName, fn, scope, options) {
        Ext.EventManager.on(this, eventName, fn, scope || this, options);
        return this;
    },

    
    un: function(eventName, fn, scope) {
        Ext.EventManager.un(this, eventName, fn, scope || this);
        return this;
    },

    
    removeAllListeners: function() {
        Ext.EventManager.removeAll(this);
        return this;
    },

    
    purgeAllListeners: function() {
        Ext.EventManager.purgeElement(this);
        return this;
    }

}, function() {

    var EC              = Ext.cache,
        El              = this,
        AbstractElement = Ext.dom.AbstractElement,
        focusRe         = /a|button|embed|iframe|img|input|object|select|textarea/i,
        nonSpaceRe      = /\S/,
        scriptTagRe     = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
        replaceScriptTagRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
        srcRe           = /\ssrc=([\'\"])(.*?)\1/i,
        typeRe          = /\stype=([\'\"])(.*?)\1/i,
        useDocForId = !(Ext.isIE6 || Ext.isIE7 || Ext.isIE8);

    El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
    

    
    
    
    function garbageCollect() {
        if (!Ext.enableGarbageCollector) {
            clearInterval(El.collectorThreadId);
        } else {
            var eid,
                d,
                o,
                t;

            for (eid in EC) {
                if (!EC.hasOwnProperty(eid)) {
                    continue;
                }

                o = EC[eid];

                
                if (o.skipGarbageCollection) {
                    continue;
                }

                d = o.dom;


                
                
                
                
                
                
                
                
                
                
                
                
                
                
                if (!d.parentNode || (!d.offsetParent && !Ext.getElementById(eid))) {
                    if (d && Ext.enableListenerCollection) {
                        Ext.EventManager.removeAll(d);
                    }
                    delete EC[eid];
                }
            }
            
            if (Ext.isIE) {
                t = {};
                for (eid in EC) {
                    if (!EC.hasOwnProperty(eid)) {
                        continue;
                    }
                    t[eid] = EC[eid];
                }
                EC = Ext.cache = t;
            }
        }
    }

    El.collectorThreadId = setInterval(garbageCollect, 30000);

    
    El.addMethods({

        
        monitorMouseLeave: function(delay, handler, scope) {
            var me = this,
                timer,
                listeners = {
                    mouseleave: function(e) {
                        timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay);
                    },
                    mouseenter: function() {
                        clearTimeout(timer);
                    },
                    freezeEvent: true
                };

            me.on(listeners);
            return listeners;
        },

        
        swallowEvent : function(eventName, preventDefault) {
            var me = this,
                e, eLen;
            function fn(e) {
                e.stopPropagation();
                if (preventDefault) {
                    e.preventDefault();
                }
            }

            if (Ext.isArray(eventName)) {
                eLen = eventName.length;

                for (e = 0; e < eLen; e++) {
                    me.on(eventName[e], fn);
                }

                return me;
            }
            me.on(eventName, fn);
            return me;
        },

        
        relayEvent : function(eventName, observable) {
            this.on(eventName, function(e) {
                observable.fireEvent(eventName, e);
            });
        },

        
        clean : function(forceReclean) {
            var me   = this,
                dom  = me.dom,
                data = (me.$cache || me.getCache()).data,
                n    = dom.firstChild,
                ni   = -1,
                nx;

            if (data.isCleaned && forceReclean !== true) {
                return me;
            }

            while (n) {
                nx = n.nextSibling;
                if (n.nodeType == 3) {
                    
                    if (!(nonSpaceRe.test(n.nodeValue))) {
                        dom.removeChild(n);
                    
                    } else if (nx && nx.nodeType == 3) {
                        n.appendData(Ext.String.trim(nx.data));
                        dom.removeChild(nx);
                        nx = n.nextSibling;
                        n.nodeIndex = ++ni;
                    }
                } else {
                    
                    Ext.fly(n).clean();
                    n.nodeIndex = ++ni;
                }
                n = nx;
            }

            data.isCleaned = true;
            return me;
        },

        
        load : function(options) {
            this.getLoader().load(options);
            return this;
        },

        
        getLoader : function() {
            var me = this,
                data = (me.$cache || me.getCache()).data,
                loader = data.loader;

            if (!loader) {
                data.loader = loader = new Ext.ElementLoader({
                    target: me
                });
            }
            return loader;
        },

        
        syncContent: function(source) {
            source = Ext.getDom(source);
            var me = this,
                sourceNodes = source.childNodes,
                sourceLen = sourceNodes.length,
                dest = me.dom,
                destNodes = dest.childNodes,
                destLen = destNodes.length,
                i,  destNode, sourceNode,
                nodeType;

            
            dest.style.cssText = source.style.cssText;
            dest.className = source.className;

            
            if (sourceLen !== destLen) {
                source.innerHTML = dest.innerHTML;
                return;
            }

            
            
            for (i = 0; i < sourceLen; i++) {
                sourceNode = sourceNodes[i];
                destNode = destNodes[i];
                nodeType = sourceNode.nodeType;

                
                if (nodeType !== destNode.nodeType || (nodeType === 1 && sourceNode.tagName !== destNode.tagName)) {
                    dest.innerHTML = source.innerHTML;
                    return;
                }

                
                if (nodeType === 3) {
                    destNode.data = sourceNode.data;
                }
                
                else {
                    if (sourceNode.id && destNode.id !== sourceNode.id) {
                        destNode.id = sourceNode.id;
                    }
                    destNode.style.cssText = sourceNode.style.cssText;
                    destNode.className = sourceNode.className;
                    Ext.fly(destNode).syncContent(sourceNode);
                }
            }
        },

        
        update : function(html, loadScripts, callback) {
            var me = this,
                id,
                dom,
                interval;

            if (!me.dom) {
                return me;
            }
            html = html || '';
            dom = me.dom;

            if (loadScripts !== true) {
                dom.innerHTML = html;
                Ext.callback(callback, me);
                return me;
            }

            id  = Ext.id();
            html += '<span id="' + id + '"></span>';

            interval = setInterval(function() {
                var hd,
                    match,
                    attrs,
                    srcMatch,
                    typeMatch,
                    el,
                    s;
                if (!(el = DOC.getElementById(id))) {
                    return false;
                }
                clearInterval(interval);
                Ext.removeNode(el);
                hd = Ext.getHead().dom;

                while ((match = scriptTagRe.exec(html))) {
                    attrs = match[1];
                    srcMatch = attrs ? attrs.match(srcRe) : false;
                    if (srcMatch && srcMatch[2]) {
                       s = DOC.createElement("script");
                       s.src = srcMatch[2];
                       typeMatch = attrs.match(typeRe);
                       if (typeMatch && typeMatch[2]) {
                           s.type = typeMatch[2];
                       }
                       hd.appendChild(s);
                    } else if (match[2] && match[2].length > 0) {
                        if (window.execScript) {
                           window.execScript(match[2]);
                        } else {
                           window.eval(match[2]);
                        }
                    }
                }
                Ext.callback(callback, me);
            }, 20);
            dom.innerHTML = html.replace(replaceScriptTagRe, '');
            return me;
        },

        
        removeAllListeners : function() {
            this.removeAnchor();
            Ext.EventManager.removeAll(this.dom);
            return this;
        },

        
        createProxy : function(config, renderTo, matchBox) {
            config = (typeof config == 'object') ? config : {tag : "div", cls: config};

            var me = this,
                proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) :
                                   Ext.DomHelper.insertBefore(me.dom, config, true);

            proxy.setVisibilityMode(Element.DISPLAY);
            proxy.hide();
            if (matchBox && me.setBox && me.getBox) { 
               proxy.setBox(me.getBox());
            }
            return proxy;
        },
        
        
        getScopeParent: function() {
            var parent = this.dom.parentNode;
            if (Ext.scopeResetCSS) {
                
                parent = parent.parentNode;
                if (!Ext.supports.CSS3LinearGradient || !Ext.supports.CSS3BorderRadius) {
                    
                    
                    parent = parent.parentNode;
                }
            }
            return parent;
        },

        
        needsTabIndex: function() {
            if (this.dom) {
                if ((this.dom.nodeName === 'a') && (!this.dom.href)) {
                    return true;
                }
                return !focusRe.test(this.dom.nodeName);
            }
        },

        
        focusable: function () {
            var dom = this.dom,
                nodeName = dom.nodeName,
                canFocus = false;

            if (!dom.disabled) {
                if (focusRe.test(nodeName)) {
                    if ((nodeName !== 'a') || dom.href) {
                        canFocus = true;
                    }
                } else {
                    canFocus = !isNaN(dom.tabIndex);
                }
            }
            return canFocus && this.isVisible(true);
        }
    });

    if (Ext.isIE) {
        El.prototype.getById = function (id, asDom) {
            var dom = this.dom,
                cacheItem, el, ret;

            if (dom) {
                
                
                el = (useDocForId && DOC.getElementById(id)) || dom.all[id];
                if (el) {
                    if (asDom) {
                        ret = el;
                    } else {
                        
                        
                        cacheItem = EC[id];
                        if (cacheItem && cacheItem.el) {
                            ret = Ext.updateCacheEntry(cacheItem, el).el;
                        } else {
                            ret = new Element(el);
                        }
                    }
                    return ret;
                }
            }

            return asDom ? Ext.getDom(id) : El.get(id);
        };
    }

    El.createAlias({
        
        addListener: 'on',
        
        removeListener: 'un',
        
        clearListeners: 'removeAllListeners'
    });

    El.Fly = AbstractElement.Fly = new Ext.Class({
        extend: El,

        constructor: function(dom) {
            this.dom = dom;
        },
        
        attach: AbstractElement.Fly.prototype.attach
    });

    if (Ext.isIE) {
        Ext.getElementById = function (id) {
            var el = DOC.getElementById(id),
                detachedBodyEl;

            if (!el && (detachedBodyEl = AbstractElement.detachedBodyEl)) {
                el = detachedBodyEl.dom.all[id];
            }

            return el;
        };
    } else if (!DOC.querySelector) {
        Ext.getDetachedBody = Ext.getBody;

        Ext.getElementById = function (id) {
            return DOC.getElementById(id);
        };
    }
});

}());


Ext.dom.Element.override((function() {

    var doc = document,
        win = window,
        alignRe = /^([a-z]+)-([a-z]+)(\?)?$/,
        round = Math.round;

    return {

        
        getAnchorXY: function(anchor, local, mySize) {
            
            
            anchor = (anchor || "tl").toLowerCase();
            mySize = mySize || {};

            var me = this,
                isViewport = me.dom == doc.body || me.dom == doc,
                myWidth = mySize.width || isViewport ? Ext.dom.Element.getViewWidth() : me.getWidth(),
                myHeight = mySize.height || isViewport ? Ext.dom.Element.getViewHeight() : me.getHeight(),
                xy,
                myPos = me.getXY(),
                scroll = me.getScroll(),
                extraX = isViewport ? scroll.left : !local ? myPos[0] : 0,
                extraY = isViewport ? scroll.top : !local ? myPos[1] : 0;

            
            
            switch (anchor) {
                case 'tl' : xy = [ 0,                    0];
                            break;
                case 'bl' : xy = [ 0,                    myHeight];
                            break;
                case 'tr' : xy = [ myWidth,              0];
                            break;
                case 'c'  : xy = [ round(myWidth * 0.5), round(myHeight * 0.5)];
                            break;
                case 't'  : xy = [ round(myWidth * 0.5), 0];
                            break;
                case 'l'  : xy = [ 0,                    round(myHeight * 0.5)];
                            break;
                case 'r'  : xy = [ myWidth,              round(myHeight * 0.5)];
                            break;
                case 'b'  : xy = [ round(myWidth * 0.5), myHeight];
                            break;
                case 'br' : xy = [ myWidth,              myHeight];
            }
            return [xy[0] + extraX, xy[1] + extraY];
        },

        
        getAlignToXY : function(alignToEl, posSpec, offset) {
            alignToEl = Ext.get(alignToEl);

            if (!alignToEl || !alignToEl.dom) {
            }

            offset = offset || [0,0];
            posSpec = (!posSpec || posSpec == "?" ? "tl-bl?" : (!(/-/).test(posSpec) && posSpec !== "" ? "tl-" + posSpec : posSpec || "tl-bl")).toLowerCase();

            var me = this,
                    myPosition,
                    alignToElPosition,
                    x,
                    y,
                    myWidth,
                    myHeight,
                    alignToElRegion,
                    viewportWidth = Ext.dom.Element.getViewWidth() - 10, 
                    viewportHeight = Ext.dom.Element.getViewHeight() - 10, 
                    p1y,
                    p1x,
                    p2y,
                    p2x,
                    swapY,
                    swapX,
                    docElement = doc.documentElement,
                    docBody = doc.body,
                    scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0),
                    scrollY = (docElement.scrollTop  || docBody.scrollTop  || 0),
                    constrain, 
                    align1,
                    align2,
                    alignMatch = posSpec.match(alignRe);


            align1 = alignMatch[1];
            align2 = alignMatch[2];
            constrain = !!alignMatch[3];

            
            
            myPosition = me.getAnchorXY(align1, true);
            alignToElPosition = alignToEl.getAnchorXY(align2, false);

            x = alignToElPosition[0] - myPosition[0] + offset[0];
            y = alignToElPosition[1] - myPosition[1] + offset[1];

            
            if (constrain) {
                myWidth = me.getWidth();
                myHeight = me.getHeight();
                alignToElRegion = alignToEl.getRegion();
                
                
                
                p1y = align1.charAt(0);
                p1x = align1.charAt(align1.length - 1);
                p2y = align2.charAt(0);
                p2x = align2.charAt(align2.length - 1);
                swapY = ((p1y == "t" && p2y == "b") || (p1y == "b" && p2y == "t"));
                swapX = ((p1x == "r" && p2x == "l") || (p1x == "l" && p2x == "r"));

                if (x + myWidth > viewportWidth + scrollX) {
                    x = swapX ? alignToElRegion.left - myWidth : viewportWidth + scrollX - myWidth;
                }
                if (x < scrollX) {
                    x = swapX ? alignToElRegion.right : scrollX;
                }
                if (y + myHeight > viewportHeight + scrollY) {
                    y = swapY ? alignToElRegion.top - myHeight : viewportHeight + scrollY - myHeight;
                }
                if (y < scrollY) {
                    y = swapY ? alignToElRegion.bottom : scrollY;
                }
            }
            return [x,y];
        },


        
        anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback) {
            var me = this,
                dom = me.dom,
                scroll = !Ext.isEmpty(monitorScroll),
                action = function() {
                    Ext.fly(dom).alignTo(el, alignment, offsets, animate);
                    Ext.callback(callback, Ext.fly(dom));
                },
                anchor = this.getAnchor();

            
            this.removeAnchor();
            Ext.apply(anchor, {
                fn: action,
                scroll: scroll
            });

            Ext.EventManager.onWindowResize(action, null);

            if (scroll) {
                Ext.EventManager.on(win, 'scroll', action, null,
                        {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
            }
            action.call(me); 
            return me;
        },

        
        removeAnchor : function() {
            var me = this,
                anchor = this.getAnchor();

            if (anchor && anchor.fn) {
                Ext.EventManager.removeResizeListener(anchor.fn);
                if (anchor.scroll) {
                    Ext.EventManager.un(win, 'scroll', anchor.fn);
                }
                delete anchor.fn;
            }
            return me;
        },

        getAlignVector: function(el, spec, offset) {
            var me = this,
                myPos = me.getXY(),
                alignedPos = me.getAlignToXY(el, spec, offset);

            el = Ext.get(el);

            alignedPos[0] -= myPos[0];
            alignedPos[1] -= myPos[1];
            return alignedPos;
        },

        
        alignTo: function(element, position, offsets, animate) {
            var me = this;
            return me.setXY(me.getAlignToXY(element, position, offsets),
                    me.anim && !!animate ? me.anim(animate) : false);
        },

        
        getConstrainVector: function(constrainTo, proposedPosition) {
            if (!(constrainTo instanceof Ext.util.Region)) {
                constrainTo = Ext.get(constrainTo).getViewRegion();
            }
            var thisRegion = this.getRegion(),
                    vector = [0, 0],
                    shadowSize = (this.shadow && !this.shadowDisabled) ? this.shadow.getShadowSize() : undefined,
                    overflowed = false;

            
            if (proposedPosition) {
                thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
            }

            
            if (shadowSize) {
                constrainTo.adjust(shadowSize[0], -shadowSize[1], -shadowSize[2], shadowSize[3]);
            }

            
            if (thisRegion.right > constrainTo.right) {
                overflowed = true;
                vector[0] = (constrainTo.right - thisRegion.right);    
            }
            if (thisRegion.left + vector[0] < constrainTo.left) {
                overflowed = true;
                vector[0] = (constrainTo.left - thisRegion.left);      
            }

            
            if (thisRegion.bottom > constrainTo.bottom) {
                overflowed = true;
                vector[1] = (constrainTo.bottom - thisRegion.bottom);  
            }
            if (thisRegion.top + vector[1] < constrainTo.top) {
                overflowed = true;
                vector[1] = (constrainTo.top - thisRegion.top);        
            }
            return overflowed ? vector : false;
        },

        
        getCenterXY : function(){
            return this.getAlignToXY(doc, 'c-c');
        },

        
        center : function(centerIn){
            return this.alignTo(centerIn || doc, 'c-c');
        }
    };
}()));



Ext.dom.Element.override({
    
    animate: function(config) {
        var me = this,
            listeners,
            anim,
            animId = me.dom.id || Ext.id(me.dom);

        if (!Ext.fx.Manager.hasFxBlock(animId)) {
            
            if (config.listeners) {
                listeners = config.listeners;
                delete config.listeners;
            }
            if (config.internalListeners) {
                config.listeners = config.internalListeners;
                delete config.internalListeners;
            }
            anim = new Ext.fx.Anim(me.anim(config));
            if (listeners) {
                anim.on(listeners);
            }
            Ext.fx.Manager.queueFx(anim);
        }
        return me;
    },

    
    anim: function(config) {
        if (!Ext.isObject(config)) {
            return (config) ? {} : false;
        }

        var me = this,
            duration = config.duration || Ext.fx.Anim.prototype.duration,
            easing = config.easing || 'ease',
            animConfig;

        if (config.stopAnimation) {
            me.stopAnimation();
        }

        Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));

        
        Ext.fx.Manager.setFxDefaults(me.id, {
            delay: 0
        });

        animConfig = {
            
            target: me.dom,
            remove: config.remove,
            alternate: config.alternate || false,
            duration: duration,
            easing: easing,
            callback: config.callback,
            listeners: config.listeners,
            iterations: config.iterations || 1,
            scope: config.scope,
            block: config.block,
            concurrent: config.concurrent,
            delay: config.delay || 0,
            paused: true,
            keyframes: config.keyframes,
            from: config.from || {},
            to: Ext.apply({}, config)
        };
        Ext.apply(animConfig.to, config.to);

        
        delete animConfig.to.to;
        delete animConfig.to.from;
        delete animConfig.to.remove;
        delete animConfig.to.alternate;
        delete animConfig.to.keyframes;
        delete animConfig.to.iterations;
        delete animConfig.to.listeners;
        delete animConfig.to.target;
        delete animConfig.to.paused;
        delete animConfig.to.callback;
        delete animConfig.to.scope;
        delete animConfig.to.duration;
        delete animConfig.to.easing;
        delete animConfig.to.concurrent;
        delete animConfig.to.block;
        delete animConfig.to.stopAnimation;
        delete animConfig.to.delay;
        return animConfig;
    },

    
    slideIn: function(anchor, obj, slideOut) {
        var me = this,
            elStyle = me.dom.style,
            beforeAnim,
            wrapAnim,
            restoreScroll,
            wrapDomParentNode;

        anchor = anchor || "t";
        obj = obj || {};

        beforeAnim = function() {
            var animScope = this,
                listeners = obj.listeners,
                box, originalStyles, anim, wrap;

            if (!slideOut) {
                me.fixDisplay();
            }

            box = me.getBox();
            if ((anchor == 't' || anchor == 'b') && box.height === 0) {
                box.height = me.dom.scrollHeight;
            }
            else if ((anchor == 'l' || anchor == 'r') && box.width === 0) {
                box.width = me.dom.scrollWidth;
            }

            originalStyles = me.getStyles('width', 'height', 'left', 'right', 'top', 'bottom', 'position', 'z-index', true);
            me.setSize(box.width, box.height);

            
            if (obj.preserveScroll) {
                restoreScroll = me.cacheScrollValues();
            }

            wrap = me.wrap({
                id: Ext.id() + '-anim-wrap-for-' + me.id,
                style: {
                    visibility: slideOut ? 'visible' : 'hidden'
                }
            });
            wrapDomParentNode = wrap.dom.parentNode;
            wrap.setPositioning(me.getPositioning());
            if (wrap.isStyle('position', 'static')) {
                wrap.position('relative');
            }
            me.clearPositioning('auto');
            wrap.clip();

            
            if (restoreScroll) {
                restoreScroll();
            }

            
            
            
            me.setStyle({
                visibility: '',
                position: 'absolute'
            });
            if (slideOut) {
                wrap.setSize(box.width, box.height);
            }

            switch (anchor) {
                case 't':
                    anim = {
                        from: {
                            width: box.width + 'px',
                            height: '0px'
                        },
                        to: {
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    elStyle.bottom = '0px';
                    break;
                case 'l':
                    anim = {
                        from: {
                            width: '0px',
                            height: box.height + 'px'
                        },
                        to: {
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    elStyle.right = '0px';
                    break;
                case 'r':
                    anim = {
                        from: {
                            x: box.x + box.width,
                            width: '0px',
                            height: box.height + 'px'
                        },
                        to: {
                            x: box.x,
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    break;
                case 'b':
                    anim = {
                        from: {
                            y: box.y + box.height,
                            width: box.width + 'px',
                            height: '0px'
                        },
                        to: {
                            y: box.y,
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    break;
                case 'tl':
                    anim = {
                        from: {
                            x: box.x,
                            y: box.y,
                            width: '0px',
                            height: '0px'
                        },
                        to: {
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    elStyle.bottom = '0px';
                    elStyle.right = '0px';
                    break;
                case 'bl':
                    anim = {
                        from: {
                            y: box.y + box.height,
                            width: '0px',
                            height: '0px'
                        },
                        to: {
                            y: box.y,
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    elStyle.bottom = '0px';
                    break;
                case 'br':
                    anim = {
                        from: {
                            x: box.x + box.width,
                            y: box.y + box.height,
                            width: '0px',
                            height: '0px'
                        },
                        to: {
                            x: box.x,
                            y: box.y,
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    break;
                case 'tr':
                    anim = {
                        from: {
                            x: box.x + box.width,
                            width: '0px',
                            height: '0px'
                        },
                        to: {
                            x: box.x,
                            width: box.width + 'px',
                            height: box.height + 'px'
                        }
                    };
                    elStyle.right = '0px';
                    break;
            }

            wrap.show();
            wrapAnim = Ext.apply({}, obj);
            delete wrapAnim.listeners;
            wrapAnim = new Ext.fx.Anim(Ext.applyIf(wrapAnim, {
                target: wrap,
                duration: 500,
                easing: 'ease-out',
                from: slideOut ? anim.to : anim.from,
                to: slideOut ? anim.from : anim.to
            }));

            
            wrapAnim.on('afteranimate', function() {
                me.setStyle(originalStyles);
                if (slideOut) {
                    if (obj.useDisplay) {
                        me.setDisplayed(false);
                    } else {
                        me.hide();
                    }
                }
                if (wrap.dom) {
                    if (wrap.dom.parentNode) {
                        wrap.dom.parentNode.insertBefore(me.dom, wrap.dom);
                    } else {
                        wrapDomParentNode.appendChild(me.dom);
                    }
                    wrap.remove();
                }
                
                if (restoreScroll) {
                    restoreScroll();
                }
                
                animScope.end();
            });
            
            if (listeners) {
                wrapAnim.on(listeners);
            }
        };

        me.animate({
            
            duration: obj.duration ? Math.max(obj.duration, 500) * 2 : 1000,
            listeners: {
                beforeanimate: beforeAnim 
            }
        });
        return me;
    },


    
    slideOut: function(anchor, o) {
        return this.slideIn(anchor, o, true);
    },

    
    puff: function(obj) {
        var me = this,
            beforeAnim,
            box = me.getBox(),
            originalStyles = me.getStyles('width', 'height', 'left', 'right', 'top', 'bottom', 'position', 'z-index', 'font-size', 'opacity', true);

       obj = Ext.applyIf(obj || {}, {
            easing: 'ease-out',
            duration: 500,
            useDisplay: false
        });

        beforeAnim = function() {
            me.clearOpacity();
            me.show();
            this.to = {
                width: box.width * 2,
                height: box.height * 2,
                x: box.x - (box.width / 2),
                y: box.y - (box.height /2),
                opacity: 0,
                fontSize: '200%'
            };
            this.on('afteranimate',function() {
                if (me.dom) {
                    if (obj.useDisplay) {
                        me.setDisplayed(false);
                    } else {
                        me.hide();
                    }
                    me.setStyle(originalStyles);
                    obj.callback.call(obj.scope);
                }
            });
        };

        me.animate({
            duration: obj.duration,
            easing: obj.easing,
            listeners: {
                beforeanimate: {
                    fn: beforeAnim
                }
            }
        });
        return me;
    },

    
    switchOff: function(obj) {
        var me = this,
            beforeAnim;

        obj = Ext.applyIf(obj || {}, {
            easing: 'ease-in',
            duration: 500,
            remove: false,
            useDisplay: false
        });

        beforeAnim = function() {
            var animScope = this,
                size = me.getSize(),
                xy = me.getXY(),
                keyframe, position;
            me.clearOpacity();
            me.clip();
            position = me.getPositioning();

            keyframe = new Ext.fx.Animator({
                target: me,
                duration: obj.duration,
                easing: obj.easing,
                keyframes: {
                    33: {
                        opacity: 0.3
                    },
                    66: {
                        height: 1,
                        y: xy[1] + size.height / 2
                    },
                    100: {
                        width: 1,
                        x: xy[0] + size.width / 2
                    }
                }
            });
            keyframe.on('afteranimate', function() {
                if (obj.useDisplay) {
                    me.setDisplayed(false);
                } else {
                    me.hide();
                }
                me.clearOpacity();
                me.setPositioning(position);
                me.setSize(size);
                
                animScope.end();
            });
        };
        
        me.animate({
            
            duration: (Math.max(obj.duration, 500) * 2),
            listeners: {
                beforeanimate: {
                    fn: beforeAnim
                }
            }
        });
        return me;
    },

    
    frame : function(color, count, obj){
        var me = this,
            beforeAnim;

        color = color || '#C3DAF9';
        count = count || 1;
        obj = obj || {};

        beforeAnim = function() {
            me.show();
            var animScope = this,
                box = me.getBox(),
                proxy = Ext.getBody().createChild({
                    id: me.id + '-anim-proxy',
                    style: {
                        position : 'absolute',
                        'pointer-events': 'none',
                        'z-index': 35000,
                        border : '0px solid ' + color
                    }
                }),
                proxyAnim;
            proxyAnim = new Ext.fx.Anim({
                target: proxy,
                duration: obj.duration || 1000,
                iterations: count,
                from: {
                    top: box.y,
                    left: box.x,
                    borderWidth: 0,
                    opacity: 1,
                    height: box.height,
                    width: box.width
                },
                to: {
                    top: box.y - 20,
                    left: box.x - 20,
                    borderWidth: 10,
                    opacity: 0,
                    height: box.height + 40,
                    width: box.width + 40
                }
            });
            proxyAnim.on('afteranimate', function() {
                proxy.remove();
                
                animScope.end();
            });
        };

        me.animate({
            
            duration: (Math.max(obj.duration, 500) * 2) || 2000,
            listeners: {
                beforeanimate: {
                    fn: beforeAnim
                }
            }
        });
        return me;
    },

    
    ghost: function(anchor, obj) {
        var me = this,
            beforeAnim;

        anchor = anchor || "b";
        beforeAnim = function() {
            var width = me.getWidth(),
                height = me.getHeight(),
                xy = me.getXY(),
                position = me.getPositioning(),
                to = {
                    opacity: 0
                };
            switch (anchor) {
                case 't':
                    to.y = xy[1] - height;
                    break;
                case 'l':
                    to.x = xy[0] - width;
                    break;
                case 'r':
                    to.x = xy[0] + width;
                    break;
                case 'b':
                    to.y = xy[1] + height;
                    break;
                case 'tl':
                    to.x = xy[0] - width;
                    to.y = xy[1] - height;
                    break;
                case 'bl':
                    to.x = xy[0] - width;
                    to.y = xy[1] + height;
                    break;
                case 'br':
                    to.x = xy[0] + width;
                    to.y = xy[1] + height;
                    break;
                case 'tr':
                    to.x = xy[0] + width;
                    to.y = xy[1] - height;
                    break;
            }
            this.to = to;
            this.on('afteranimate', function () {
                if (me.dom) {
                    me.hide();
                    me.clearOpacity();
                    me.setPositioning(position);
                }
            });
        };

        me.animate(Ext.applyIf(obj || {}, {
            duration: 500,
            easing: 'ease-out',
            listeners: {
                beforeanimate: {
                    fn: beforeAnim
                }
            }
        }));
        return me;
    },

    
    highlight: function(color, o) {
        var me = this,
            dom = me.dom,
            from = {},
            restore, to, attr, lns, event, fn;

        o = o || {};
        lns = o.listeners || {};
        attr = o.attr || 'backgroundColor';
        from[attr] = color || 'ffff9c';

        if (!o.to) {
            to = {};
            to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
        }
        else {
            to = o.to;
        }

        
        o.listeners = Ext.apply(Ext.apply({}, lns), {
            beforeanimate: function() {
                restore = dom.style[attr];
                me.clearOpacity();
                me.show();

                event = lns.beforeanimate;
                if (event) {
                    fn = event.fn || event;
                    return fn.apply(event.scope || lns.scope || window, arguments);
                }
            },
            afteranimate: function() {
                if (dom) {
                    dom.style[attr] = restore;
                }

                event = lns.afteranimate;
                if (event) {
                    fn = event.fn || event;
                    fn.apply(event.scope || lns.scope || window, arguments);
                }
            }
        });

        me.animate(Ext.apply({}, o, {
            duration: 1000,
            easing: 'ease-in',
            from: from,
            to: to
        }));
        return me;
    },

   
    pause: function(ms) {
        var me = this;
        Ext.fx.Manager.setFxDefaults(me.id, {
            delay: ms
        });
        return me;
    },

    
    fadeIn: function(o) {
        var me = this;
        me.animate(Ext.apply({}, o, {
            opacity: 1,
            internalListeners: {
                beforeanimate: function(anim){
                    
                    
                    if (me.isStyle('display', 'none')) {
                        me.setDisplayed('');
                    } else {
                        me.show();
                    } 
                }
            }
        }));
        return this;
    },

    
    fadeOut: function(o) {
        var me = this;
        o = Ext.apply({
            opacity: 0,
            internalListeners: {
                afteranimate: function(anim){
                    var dom = me.dom;
                    if (dom && anim.to.opacity === 0) {
                        if (o.useDisplay) {
                            me.setDisplayed(false);
                        } else {
                            me.hide();
                        }
                    }         
                }
            }
        }, o);
        me.animate(o);
        return me;
    },

    
    scale: function(w, h, o) {
        this.animate(Ext.apply({}, o, {
            width: w,
            height: h
        }));
        return this;
    },

    
    shift: function(config) {
        this.animate(config);
        return this;
    }
});


Ext.dom.Element.override({
    
    initDD : function(group, config, overrides){
        var dd = new Ext.dd.DD(Ext.id(this.dom), group, config);
        return Ext.apply(dd, overrides);
    },

    
    initDDProxy : function(group, config, overrides){
        var dd = new Ext.dd.DDProxy(Ext.id(this.dom), group, config);
        return Ext.apply(dd, overrides);
    },

    
    initDDTarget : function(group, config, overrides){
        var dd = new Ext.dd.DDTarget(Ext.id(this.dom), group, config);
        return Ext.apply(dd, overrides);
    }
});


(function() {

var Element         = Ext.dom.Element,
    VISIBILITY      = "visibility",
    DISPLAY         = "display",
    NONE            = "none",
    HIDDEN          = 'hidden',
    VISIBLE         = 'visible',
    OFFSETS         = "offsets",
    ASCLASS         = "asclass",
    NOSIZE          = 'nosize',
    ORIGINALDISPLAY = 'originalDisplay',
    VISMODE         = 'visibilityMode',
    ISVISIBLE       = 'isVisible',
    OFFSETCLASS     = Ext.baseCSSPrefix + 'hide-offsets',
    getDisplay = function(el) {
        var data = (el.$cache || el.getCache()).data,
            display = data[ORIGINALDISPLAY];
            
        if (display === undefined) {
            data[ORIGINALDISPLAY] = display = '';
        }
        return display;
    },
    getVisMode = function(el){
        var data = (el.$cache || el.getCache()).data,
            visMode = data[VISMODE];
            
        if (visMode === undefined) {
            data[VISMODE] = visMode = Element.VISIBILITY;
        }
        return visMode;
    };

Element.override({
    
    originalDisplay : "",
    visibilityMode : 1,

    
    setVisible : function(visible, animate) {
        var me = this,
            dom = me.dom,
            visMode = getVisMode(me);

        
        if (typeof animate == 'string') {
            switch (animate) {
                case DISPLAY:
                    visMode = Element.DISPLAY;
                    break;
                case VISIBILITY:
                    visMode = Element.VISIBILITY;
                    break;
                case OFFSETS:
                    visMode = Element.OFFSETS;
                    break;
                case NOSIZE:
                case ASCLASS:
                    visMode = Element.ASCLASS;
                    break;
            }
            me.setVisibilityMode(visMode);
            animate = false;
        }

        if (!animate || !me.anim) {
            if (visMode == Element.DISPLAY) {
                return me.setDisplayed(visible);
            } else if (visMode == Element.OFFSETS) {
                me[visible?'removeCls':'addCls'](OFFSETCLASS);
            } else if (visMode == Element.VISIBILITY) {
                me.fixDisplay();
                
                dom.style.visibility = visible ? '' : HIDDEN;
            } else if (visMode == Element.ASCLASS) {
                me[visible?'removeCls':'addCls'](me.visibilityCls || Element.visibilityCls);
            }
        } else {
            
            if (visible) {
                me.setOpacity(0.01);
                me.setVisible(true);
            }
            if (!Ext.isObject(animate)) {
                animate = {
                    duration: 350,
                    easing: 'ease-in'
                };
            }
            me.animate(Ext.applyIf({
                callback: function() {
                    if (!visible) {
                        me.setVisible(false).setOpacity(1);
                    }
                },
                to: {
                    opacity: (visible) ? 1 : 0
                }
            }, animate));
        }
        (me.$cache || me.getCache()).data[ISVISIBLE] = visible;
        return me;
    },

    
    hasMetrics  : function(){
        var visMode = getVisMode(this);
        return this.isVisible() || (visMode == Element.OFFSETS) || (visMode == Element.VISIBILITY);
    },

    
    toggle : function(animate){
        var me = this;
        me.setVisible(!me.isVisible(), me.anim(animate));
        return me;
    },

    
    setDisplayed : function(value) {
        if(typeof value == "boolean"){
           value = value ? getDisplay(this) : NONE;
        }
        this.setStyle(DISPLAY, value);
        return this;
    },

    
    fixDisplay : function(){
        var me = this;
        if (me.isStyle(DISPLAY, NONE)) {
            me.setStyle(VISIBILITY, HIDDEN);
            me.setStyle(DISPLAY, getDisplay(me)); 
            if (me.isStyle(DISPLAY, NONE)) { 
                me.setStyle(DISPLAY, "block");
            }
        }
    },

    
    hide : function(animate){
        
        if (typeof animate == 'string'){
            this.setVisible(false, animate);
            return this;
        }
        this.setVisible(false, this.anim(animate));
        return this;
    },

    
    show : function(animate){
        
        if (typeof animate == 'string'){
            this.setVisible(true, animate);
            return this;
        }
        this.setVisible(true, this.anim(animate));
        return this;
    }
});

}());


(function() {

var Element = Ext.dom.Element,
    LEFT = "left",
    RIGHT = "right",
    TOP = "top",
    BOTTOM = "bottom",
    POSITION = "position",
    STATIC = "static",
    RELATIVE = "relative",
    AUTO = "auto",
    ZINDEX = "z-index",
    BODY = 'BODY',

    PADDING = 'padding',
    BORDER = 'border',
    SLEFT = '-left',
    SRIGHT = '-right',
    STOP = '-top',
    SBOTTOM = '-bottom',
    SWIDTH = '-width',
    
    borders = {l: BORDER + SLEFT + SWIDTH, r: BORDER + SRIGHT + SWIDTH, t: BORDER + STOP + SWIDTH, b: BORDER + SBOTTOM + SWIDTH},
    paddings = {l: PADDING + SLEFT, r: PADDING + SRIGHT, t: PADDING + STOP, b: PADDING + SBOTTOM},
    paddingsTLRB = [paddings.l, paddings.r, paddings.t, paddings.b],
    bordersTLRB = [borders.l,  borders.r,  borders.t,  borders.b],
    positionTopLeft = ['position', 'top', 'left'];

Element.override({

    getX: function() {
        return Element.getX(this.dom);
    },

    getY: function() {
        return Element.getY(this.dom);
    },

    
    getXY: function() {
        return Element.getXY(this.dom);
    },

    
    getOffsetsTo : function(el){
        var o = this.getXY(),
                e = Ext.fly(el, '_internal').getXY();
        return [o[0] - e[0],o[1] - e[1]];
    },

    setX: function(x, animate) {
        return this.setXY([x, this.getY()], animate);
    },

    setY: function(y, animate) {
        return this.setXY([this.getX(), y], animate);
    },

    setLeft: function(left) {
        this.setStyle(LEFT, this.addUnits(left));
        return this;
    },

    setTop: function(top) {
        this.setStyle(TOP, this.addUnits(top));
        return this;
    },

    setRight: function(right) {
        this.setStyle(RIGHT, this.addUnits(right));
        return this;
    },

    setBottom: function(bottom) {
        this.setStyle(BOTTOM, this.addUnits(bottom));
        return this;
    },

    
    setXY: function(pos, animate) {
        var me = this;
        if (!animate || !me.anim) {
            Element.setXY(me.dom, pos);
        }
        else {
            if (!Ext.isObject(animate)) {
                animate = {};
            }
            me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate));
        }
        return me;
    },

    pxRe: /^\d+(?:\.\d*)?px$/i,

    
    getLocalX: function() {
        var me = this,
            offsetParent,
            x = me.getStyle(LEFT);

        if (!x || x === AUTO) {
            return 0;
        }
        if (x && me.pxRe.test(x)) {
            return parseFloat(x);
        }

        x = me.getX();

        offsetParent = me.dom.offsetParent;
        if (offsetParent) {
            x -= Ext.fly(offsetParent).getX();
        }

        return x;
    },

    
    getLocalY: function() {
        var me = this,
            offsetParent,
            y = me.getStyle(TOP);

        if (!y || y === AUTO) {
            return 0;
        }
        if (y && me.pxRe.test(y)) {
            return parseFloat(y);
        }

        y = me.getY();

        offsetParent = me.dom.offsetParent;
        if (offsetParent) {
            y -= Ext.fly(offsetParent).getY();
        }

        return y;
    },

    getLeft: function(local) {
        return local ? this.getLocalX() : this.getX();
    },

    getRight: function(local) {
        return (local ? this.getLocalX() : this.getX()) + this.getWidth();
    },

    getTop: function(local) {
        return local ? this.getLocalY() : this.getY();
    },

    getBottom: function(local) {
        return (local ? this.getLocalY() : this.getY()) + this.getHeight();
    },

    translatePoints: function(x, y) {
        var me = this,
            styles = me.getStyle(positionTopLeft),
            relative = styles.position == 'relative',
            left = parseFloat(styles.left),
            top = parseFloat(styles.top),
            xy = me.getXY();

        if (Ext.isArray(x)) {
             y = x[1];
             x = x[0];
        }
        if (isNaN(left)) {
            left = relative ? 0 : me.dom.offsetLeft;
        }
        if (isNaN(top)) {
            top = relative ? 0 : me.dom.offsetTop;
        }
        left = (typeof x == 'number') ? x - xy[0] + left : undefined;
        top = (typeof y == 'number') ? y - xy[1] + top : undefined;
        return {
            left: left,
            top: top
        };

    },

    setBox: function(box, adjust, animate) {
        var me = this,
                w = box.width,
                h = box.height;
        if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) {
            w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
            h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
        }
        me.setBounds(box.x, box.y, w, h, animate);
        return me;
    },

    getBox: function(contentBox, local) {
        var me = this,
            xy,
            left,
            top,
            paddingWidth,
            bordersWidth,
            l, r, t, b, w, h, bx;

        if (!local) {
            xy = me.getXY();
        } else {
            xy = me.getStyle([LEFT, TOP]);
            xy = [ parseFloat(xy.left) || 0, parseFloat(xy.top) || 0];
        }
        w = me.getWidth();
        h = me.getHeight();
        if (!contentBox) {
            bx = {
                x: xy[0],
                y: xy[1],
                0: xy[0],
                1: xy[1],
                width: w,
                height: h
            };
        } else {
            paddingWidth = me.getStyle(paddingsTLRB);
            bordersWidth = me.getStyle(bordersTLRB);

            l = (parseFloat(bordersWidth[borders.l]) || 0) + (parseFloat(paddingWidth[paddings.l]) || 0);
            r = (parseFloat(bordersWidth[borders.r]) || 0) + (parseFloat(paddingWidth[paddings.r]) || 0);
            t = (parseFloat(bordersWidth[borders.t]) || 0) + (parseFloat(paddingWidth[paddings.t]) || 0);
            b = (parseFloat(bordersWidth[borders.b]) || 0) + (parseFloat(paddingWidth[paddings.b]) || 0);

            bx = {
                x: xy[0] + l,
                y: xy[1] + t,
                0: xy[0] + l,
                1: xy[1] + t,
                width: w - (l + r),
                height: h - (t + b)
            };
        }
        bx.right = bx.x + bx.width;
        bx.bottom = bx.y + bx.height;

        return bx;
    },

    getPageBox: function(getRegion) {
        var me = this,
            el = me.dom,
            isDoc = el.nodeName == BODY,
            w = isDoc ? Ext.dom.AbstractElement.getViewWidth() : el.offsetWidth,
            h = isDoc ? Ext.dom.AbstractElement.getViewHeight() : el.offsetHeight,
            xy = me.getXY(),
            t = xy[1],
            r = xy[0] + w,
            b = xy[1] + h,
            l = xy[0];

        if (getRegion) {
            return new Ext.util.Region(t, r, b, l);
        }
        else {
            return {
                left: l,
                top: t,
                width: w,
                height: h,
                right: r,
                bottom: b
            };
        }
    },

    
    setLocation : function(x, y, animate) {
        return this.setXY([x, y], animate);
    },

    
    moveTo : function(x, y, animate) {
        return this.setXY([x, y], animate);
    },

    
    position : function(pos, zIndex, x, y) {
        var me = this;

        if (!pos && me.isStyle(POSITION, STATIC)) {
            me.setStyle(POSITION, RELATIVE);
        } else if (pos) {
            me.setStyle(POSITION, pos);
        }
        if (zIndex) {
            me.setStyle(ZINDEX, zIndex);
        }
        if (x || y) {
            me.setXY([x || false, y || false]);
        }
    },

    
    clearPositioning : function(value) {
        value = value || '';
        this.setStyle({
            left : value,
            right : value,
            top : value,
            bottom : value,
            "z-index" : "",
            position : STATIC
        });
        return this;
    },

    
    getPositioning : function(){
        var styles = this.getStyle([LEFT, TOP, POSITION, RIGHT, BOTTOM, ZINDEX]);
        styles[RIGHT] =  styles[LEFT] ? '' : styles[RIGHT];
        styles[BOTTOM] = styles[TOP] ? '' : styles[BOTTOM];
        return styles;
    },

    
    setPositioning : function(pc) {
        var me = this,
            style = me.dom.style;

        me.setStyle(pc);

        if (pc.right == AUTO) {
            style.right = "";
        }
        if (pc.bottom == AUTO) {
            style.bottom = "";
        }

        return me;
    },

    
    move: function(direction, distance, animate) {
        var me = this,
            xy = me.getXY(),
            x = xy[0],
            y = xy[1],
            left = [x - distance, y],
            right = [x + distance, y],
            top = [x, y - distance],
            bottom = [x, y + distance],
            hash = {
                l: left,
                left: left,
                r: right,
                right: right,
                t: top,
                top: top,
                up: top,
                b: bottom,
                bottom: bottom,
                down: bottom
            };

        direction = direction.toLowerCase();
        me.moveTo(hash[direction][0], hash[direction][1], animate);
    },

    
    setLeftTop: function(left, top) {
        var style = this.dom.style;

        style.left = Element.addUnits(left);
        style.top = Element.addUnits(top);

        return this;
    },

    
    getRegion: function() {
        return this.getPageBox(true);
    },

    
    getViewRegion: function() {
        var me = this,
            isBody = me.dom.nodeName == BODY,
            scroll, pos, top, left, width, height;

        
        if (isBody) {
            scroll = me.getScroll();
            left = scroll.left;
            top = scroll.top;
            width = Ext.dom.AbstractElement.getViewportWidth();
            height = Ext.dom.AbstractElement.getViewportHeight();
        }
        else {
            pos = me.getXY();
            left = pos[0] + me.getBorderWidth('l') + me.getPadding('l');
            top = pos[1] + me.getBorderWidth('t') + me.getPadding('t');
            width = me.getWidth(true);
            height = me.getHeight(true);
        }

        return new Ext.util.Region(top, left + width - 1, top + height - 1, left);
    },

    
    setBounds: function(x, y, width, height, animate) {
        var me = this;
        if (!animate || !me.anim) {
            me.setSize(width, height);
            me.setLocation(x, y);
        } else {
            if (!Ext.isObject(animate)) {
                animate = {};
            }
            me.animate(Ext.applyIf({
                to: {
                    x: x,
                    y: y,
                    width: me.adjustWidth(width),
                    height: me.adjustHeight(height)
                }
            }, animate));
        }
        return me;
    },

    
    setRegion: function(region, animate) {
        return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate);
    }
});

}());



Ext.dom.Element.override({
    
    isScrollable: function() {
        var dom = this.dom;
        return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
    },

    
    getScroll: function() {
        var d = this.dom,
            doc = document,
            body = doc.body,
            docElement = doc.documentElement,
            l,
            t,
            ret;

        if (d == doc || d == body) {
            if (Ext.isIE && Ext.isStrict) {
                l = docElement.scrollLeft;
                t = docElement.scrollTop;
            } else {
                l = window.pageXOffset;
                t = window.pageYOffset;
            }
            ret = {
                left: l || (body ? body.scrollLeft : 0),
                top : t || (body ? body.scrollTop : 0)
            };
        } else {
            ret = {
                left: d.scrollLeft,
                top : d.scrollTop
            };
        }

        return ret;
    },

    
    scrollBy: function(deltaX, deltaY, animate) {
        var me = this,
            dom = me.dom;

        
        if (deltaX.length) {
            animate = deltaY;
            deltaY = deltaX[1];
            deltaX = deltaX[0];
        } else if (typeof deltaX != 'number') { 
            animate = deltaY;
            deltaY = deltaX.y;
            deltaX = deltaX.x;
        }

        if (deltaX) {
            me.scrollTo('left', Math.max(Math.min(dom.scrollLeft + deltaX, dom.scrollWidth - dom.clientWidth), 0), animate);
        }
        if (deltaY) {
            me.scrollTo('top', Math.max(Math.min(dom.scrollTop + deltaY, dom.scrollHeight - dom.clientHeight), 0), animate);
        }

        return me;
    },

    
    scrollTo: function(side, value, animate) {
        
        var top = /top/i.test(side),
            me = this,
            dom = me.dom,
            animCfg,
            prop;

        if (!animate || !me.anim) {
            
            prop = 'scroll' + (top ? 'Top' : 'Left');
            dom[prop] = value;
            
            dom[prop] = value;
        }
        else {
            animCfg = {
                to: {}
            };
            animCfg.to['scroll' + (top ? 'Top' : 'Left')] = value;
            if (Ext.isObject(animate)) {
                Ext.applyIf(animCfg, animate);
            }
            me.animate(animCfg);
        }
        return me;
    },

    
    scrollIntoView: function(container, hscroll, animate) {
        container = Ext.getDom(container) || Ext.getBody().dom;
        var el = this.dom,
            offsets = this.getOffsetsTo(container),
        
            left = offsets[0] + container.scrollLeft,
            top = offsets[1] + container.scrollTop,
            bottom = top + el.offsetHeight,
            right = left + el.offsetWidth,
        
            ctClientHeight = container.clientHeight,
            ctScrollTop = parseInt(container.scrollTop, 10),
            ctScrollLeft = parseInt(container.scrollLeft, 10),
            ctBottom = ctScrollTop + ctClientHeight,
            ctRight = ctScrollLeft + container.clientWidth,
            newPos;

        if (el.offsetHeight > ctClientHeight || top < ctScrollTop) {
            newPos = top;
        } else if (bottom > ctBottom) {
            newPos = bottom - ctClientHeight;
        }
        if (newPos != null) {
            Ext.get(container).scrollTo('top', newPos, animate);
        }

        if (hscroll !== false) {
            newPos = null;
            if (el.offsetWidth > container.clientWidth || left < ctScrollLeft) {
                newPos = left;
            } else if (right > ctRight) {
                newPos = right - container.clientWidth;
            }
            if (newPos != null) {
                Ext.get(container).scrollTo('left', newPos, animate);
            }
        }
        return this;
    },

    
    scrollChildIntoView: function(child, hscroll) {
        Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
    },

    
    scroll: function(direction, distance, animate) {
        if (!this.isScrollable()) {
            return false;
        }
        var el = this.dom,
            l = el.scrollLeft, t = el.scrollTop,
            w = el.scrollWidth, h = el.scrollHeight,
            cw = el.clientWidth, ch = el.clientHeight,
            scrolled = false, v,
            hash = {
                l: Math.min(l + distance, w - cw),
                r: v = Math.max(l - distance, 0),
                t: Math.max(t - distance, 0),
                b: Math.min(t + distance, h - ch)
            };

        hash.d = hash.b;
        hash.u = hash.t;

        direction = direction.substr(0, 1);
        if ((v = hash[direction]) > -1) {
            scrolled = true;
            this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.anim(animate));
        }
        return scrolled;
    }
});


(function() {

var Element = Ext.dom.Element,
    view = document.defaultView,
    adjustDirect2DTableRe = /table-row|table-.*-group/,
    INTERNAL = '_internal',
    HIDDEN = 'hidden',
    HEIGHT = 'height',
    WIDTH = 'width',
    ISCLIPPED = 'isClipped',
    OVERFLOW = 'overflow',
    OVERFLOWX = 'overflow-x',
    OVERFLOWY = 'overflow-y',
    ORIGINALCLIP = 'originalClip',
    DOCORBODYRE = /#document|body/i,
    
    
    styleHooks,
    edges, k, edge, borderWidth;

if (!view || !view.getComputedStyle) {
    Element.prototype.getStyle = function (property, inline) {
        var me = this,
            dom = me.dom,
            multiple = typeof property != 'string',
            hooks = me.styleHooks,
            prop = property,
            props = prop,
            len = 1,
            isInline = inline,
            camel, domStyle, values, hook, out, style, i;

        if (multiple) {
            values = {};
            prop = props[0];
            i = 0;
            if (!(len = props.length)) {
                return values;
            }
        }

        if (!dom || dom.documentElement) {
            return values || '';
        }

        domStyle = dom.style;

        if (inline) {
            style = domStyle;
        } else {
            style = dom.currentStyle;

            
            if (!style) {
                isInline = true;
                style = domStyle;
            }
        }

        do {
            hook = hooks[prop];

            if (!hook) {
                hooks[prop] = hook = { name: Element.normalize(prop) };
            }

            if (hook.get) {
                out = hook.get(dom, me, isInline, style);
            } else {
                camel = hook.name;

                
                
                
                
                if (hook.canThrow) {
                    try {
                        out = style[camel];
                    } catch (e) {
                        out = '';
                    }
                } else {
                    
                    
                    out = style ? style[camel] : '';
                }
            }

            if (!multiple) {
                return out;
            }

            values[prop] = out;
            prop = props[++i];
        } while (i < len);

        return values;
    };
}

Element.override({
    getHeight: function(contentHeight, preciseHeight) {
        var me = this,
            dom = me.dom,
            hidden = me.isStyle('display', 'none'),
            height,
            floating;

        if (hidden) {
            return 0;
        }

        height = Math.max(dom.offsetHeight, dom.clientHeight) || 0;

        
        if (Ext.supports.Direct2DBug) {
            floating = me.adjustDirect2DDimension(HEIGHT);
            if (preciseHeight) {
                height += floating;
            }
            else if (floating > 0 && floating < 0.5) {
                height++;
            }
        }

        if (contentHeight) {
            height -= me.getBorderWidth("tb") + me.getPadding("tb");
        }

        return (height < 0) ? 0 : height;
    },

    getWidth: function(contentWidth, preciseWidth) {
        var me = this,
            dom = me.dom,
            hidden = me.isStyle('display', 'none'),
            rect, width, floating;

        if (hidden) {
            return 0;
        }

        
        
        
        
        
        
        if (Ext.supports.BoundingClientRect) {
            rect = dom.getBoundingClientRect();
            width = rect.right - rect.left;
            width = preciseWidth ? width : Math.ceil(width);
        } else {
            width = dom.offsetWidth;
        }

        width = Math.max(width, dom.clientWidth) || 0;

        
        if (Ext.supports.Direct2DBug) {
            
            floating = me.adjustDirect2DDimension(WIDTH);
            if (preciseWidth) {
                width += floating;
            }
            
            
            
            else if (floating > 0 && floating < 0.5) {
                width++;
            }
        }

        if (contentWidth) {
            width -= me.getBorderWidth("lr") + me.getPadding("lr");
        }

        return (width < 0) ? 0 : width;
    },

    setWidth: function(width, animate) {
        var me = this;
        width = me.adjustWidth(width);
        if (!animate || !me.anim) {
            me.dom.style.width = me.addUnits(width);
        }
        else {
            if (!Ext.isObject(animate)) {
                animate = {};
            }
            me.animate(Ext.applyIf({
                to: {
                    width: width
                }
            }, animate));
        }
        return me;
    },

    setHeight : function(height, animate) {
        var me = this;

        height = me.adjustHeight(height);
        if (!animate || !me.anim) {
            me.dom.style.height = me.addUnits(height);
        }
        else {
            if (!Ext.isObject(animate)) {
                animate = {};
            }
            me.animate(Ext.applyIf({
                to: {
                    height: height
                }
            }, animate));
        }

        return me;
    },

    applyStyles: function(style) {
        Ext.DomHelper.applyStyles(this.dom, style);
        return this;
    },

    setSize: function(width, height, animate) {
        var me = this;

        if (Ext.isObject(width)) { 
            animate = height;
            height = width.height;
            width = width.width;
        }

        width = me.adjustWidth(width);
        height = me.adjustHeight(height);

        if (!animate || !me.anim) {
            me.dom.style.width = me.addUnits(width);
            me.dom.style.height = me.addUnits(height);
        }
        else {
            if (animate === true) {
                animate = {};
            }
            me.animate(Ext.applyIf({
                to: {
                    width: width,
                    height: height
                }
            }, animate));
        }

        return me;
    },

    getViewSize : function() {
        var me = this,
            dom = me.dom,
            isDoc = DOCORBODYRE.test(dom.nodeName),
            ret;

        
        if (isDoc) {
            ret = {
                width : Element.getViewWidth(),
                height : Element.getViewHeight()
            };
        } else {
            ret = {
                width : dom.clientWidth,
                height : dom.clientHeight
            };
        }

        return ret;
    },

    getSize: function(contentSize) {
        return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
    },

    

    
    adjustWidth : function(width) {
        var me = this,
            isNum = (typeof width == 'number');

        if (isNum && me.autoBoxAdjust && !me.isBorderBox()) {
            width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
        }
        return (isNum && width < 0) ? 0 : width;
    },

    
    adjustHeight : function(height) {
        var me = this,
            isNum = (typeof height == "number");

        if (isNum && me.autoBoxAdjust && !me.isBorderBox()) {
            height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
        }
        return (isNum && height < 0) ? 0 : height;
    },

    
    getColor : function(attr, defaultValue, prefix) {
        var v = this.getStyle(attr),
            color = prefix || prefix === '' ? prefix : '#',
            h, len, i=0;

        if (!v || (/transparent|inherit/.test(v))) {
            return defaultValue;
        }
        if (/^r/.test(v)) {
             v = v.slice(4, v.length - 1).split(',');
             len = v.length;
             for (; i<len; i++) {
                h = parseInt(v[i], 10);
                color += (h < 16 ? '0' : '') + h.toString(16);
            }
        } else {
            v = v.replace('#', '');
            color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
        }
        return(color.length > 5 ? color.toLowerCase() : defaultValue);
    },

    
    setOpacity: function(opacity, animate) {
        var me = this;

        if (!me.dom) {
            return me;
        }

        if (!animate || !me.anim) {
            me.setStyle('opacity', opacity);
        }
        else {
            if (typeof animate != 'object') {
                animate = {
                    duration: 350,
                    easing: 'ease-in'
                };
            }

            me.animate(Ext.applyIf({
                to: {
                    opacity: opacity
                }
            }, animate));
        }
        return me;
    },

    
    clearOpacity : function() {
        return this.setOpacity('');
    },

    
    adjustDirect2DDimension: function(dimension) {
        var me = this,
            dom = me.dom,
            display = me.getStyle('display'),
            inlineDisplay = dom.style.display,
            inlinePosition = dom.style.position,
            originIndex = dimension === WIDTH ? 0 : 1,
            currentStyle = dom.currentStyle,
            floating;

        if (display === 'inline') {
            dom.style.display = 'inline-block';
        }

        dom.style.position = display.match(adjustDirect2DTableRe) ? 'absolute' : 'static';

        
        
        
        
        
        floating = (parseFloat(currentStyle[dimension]) || parseFloat(currentStyle.msTransformOrigin.split(' ')[originIndex]) * 2) % 1;

        dom.style.position = inlinePosition;

        if (display === 'inline') {
            dom.style.display = inlineDisplay;
        }

        return floating;
    },

    
    clip : function() {
        var me = this,
            data = (me.$cache || me.getCache()).data,
            style;

        if (!data[ISCLIPPED]) {
            data[ISCLIPPED] = true;
            style = me.getStyle([OVERFLOW, OVERFLOWX, OVERFLOWY]);
            data[ORIGINALCLIP] = {
                o: style[OVERFLOW],
                x: style[OVERFLOWX],
                y: style[OVERFLOWY]
            };
            me.setStyle(OVERFLOW, HIDDEN);
            me.setStyle(OVERFLOWX, HIDDEN);
            me.setStyle(OVERFLOWY, HIDDEN);
        }
        return me;
    },

    
    unclip : function() {
        var me = this,
            data = (me.$cache || me.getCache()).data,
            clip;

        if (data[ISCLIPPED]) {
            data[ISCLIPPED] = false;
            clip = data[ORIGINALCLIP];
            if (clip.o) {
                me.setStyle(OVERFLOW, clip.o);
            }
            if (clip.x) {
                me.setStyle(OVERFLOWX, clip.x);
            }
            if (clip.y) {
                me.setStyle(OVERFLOWY, clip.y);
            }
        }
        return me;
    },

    
    boxWrap : function(cls) {
        cls = cls || Ext.baseCSSPrefix + 'box';
        var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + Ext.String.format(Element.boxMarkup, cls) + "</div>"));
        Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
        return el;
    },

    
    getComputedHeight : function() {
        var me = this,
            h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
        if (!h) {
            h = parseFloat(me.getStyle(HEIGHT)) || 0;
            if (!me.isBorderBox()) {
                h += me.getFrameWidth('tb');
            }
        }
        return h;
    },

    
    getComputedWidth : function() {
        var me = this,
            w = Math.max(me.dom.offsetWidth, me.dom.clientWidth);

        if (!w) {
            w = parseFloat(me.getStyle(WIDTH)) || 0;
            if (!me.isBorderBox()) {
                w += me.getFrameWidth('lr');
            }
        }
        return w;
    },

    
    getFrameWidth : function(sides, onlyContentBox) {
        return (onlyContentBox && this.isBorderBox()) ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
    },

    
    addClsOnOver : function(className, testFn, scope) {
        var me = this,
            dom = me.dom,
            hasTest = Ext.isFunction(testFn);
            
        me.hover(
            function() {
                if (hasTest && testFn.call(scope || me, me) === false) {
                    return;
                }
                Ext.fly(dom, INTERNAL).addCls(className);
            },
            function() {
                Ext.fly(dom, INTERNAL).removeCls(className);
            }
        );
        return me;
    },

    
    addClsOnFocus : function(className, testFn, scope) {
        var me = this,
            dom = me.dom,
            hasTest = Ext.isFunction(testFn);
            
        me.on("focus", function() {
            if (hasTest && testFn.call(scope || me, me) === false) {
                return false;
            }
            Ext.fly(dom, INTERNAL).addCls(className);
        });
        me.on("blur", function() {
            Ext.fly(dom, INTERNAL).removeCls(className);
        });
        return me;
    },

    
    addClsOnClick : function(className, testFn, scope) {
        var me = this,
            dom = me.dom,
            hasTest = Ext.isFunction(testFn);
            
        me.on("mousedown", function() {
            if (hasTest && testFn.call(scope || me, me) === false) {
                return false;
            }
            Ext.fly(dom, INTERNAL).addCls(className);
            var d = Ext.getDoc(),
                fn = function() {
                    Ext.fly(dom, INTERNAL).removeCls(className);
                    d.removeListener("mouseup", fn);
                };
            d.on("mouseup", fn);
        });
        return me;
    },

    
    getStyleSize : function() {
        var me = this,
            d = this.dom,
            isDoc = DOCORBODYRE.test(d.nodeName),
            s ,
            w, h;

        
        if (isDoc) {
            return {
                width : Element.getViewWidth(),
                height : Element.getViewHeight()
            };
        }

        s = me.getStyle([HEIGHT, WIDTH], true);  
        
        if (s.width && s.width != 'auto') {
            w = parseFloat(s.width);
            if (me.isBorderBox()) {
                w -= me.getFrameWidth('lr');
            }
        }
        
        if (s.height && s.height != 'auto') {
            h = parseFloat(s.height);
            if (me.isBorderBox()) {
                h -= me.getFrameWidth('tb');
            }
        }
        
        return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
    },

    
    selectable : function() {
        var me = this;
        me.dom.unselectable = "off";
        
        me.on('selectstart', function (e) {
            e.stopPropagation();
            return true;
        });
        me.applyStyles("-moz-user-select: text; -khtml-user-select: text;");
        me.removeCls(Ext.baseCSSPrefix + 'unselectable');
        return me;
    },

    
    unselectable : function() {
        var me = this;
        me.dom.unselectable = "on";

        me.swallowEvent("selectstart", true);
        me.applyStyles("-moz-user-select:-moz-none;-khtml-user-select:none;");
        me.addCls(Ext.baseCSSPrefix + 'unselectable');

        return me;
    }
});

Element.prototype.styleHooks = styleHooks = Ext.dom.AbstractElement.prototype.styleHooks;

if (Ext.isIE6 || Ext.isIE7) {
    styleHooks.fontSize = styleHooks['font-size'] = {
        name: 'fontSize',
        canThrow: true
    };
    
    styleHooks.fontStyle = styleHooks['font-style'] = {
        name: 'fontStyle',
        canThrow: true
    };
    
    styleHooks.fontFamily = styleHooks['font-family'] = {
        name: 'fontFamily',
        canThrow: true
    };
}


if (Ext.isIEQuirks || Ext.isIE && Ext.ieVersion <= 8) {
    function getBorderWidth (dom, el, inline, style) {
        if (style[this.styleName] == 'none') {
            return '0px';
        }
        return style[this.name];
    }

    edges = ['Top','Right','Bottom','Left'];
    k = edges.length;

    while (k--) {
        edge = edges[k];
        borderWidth = 'border' + edge + 'Width';

        styleHooks['border-'+edge.toLowerCase()+'-width'] = styleHooks[borderWidth] = {
            name: borderWidth,
            styleName: 'border' + edge + 'Style',
            get: getBorderWidth
        };
    }
}

}());

Ext.onReady(function () {
    var opacityRe = /alpha\(opacity=(.*)\)/i,
        trimRe = /^\s+|\s+$/g,
        hooks = Ext.dom.Element.prototype.styleHooks;

    
    hooks.opacity = {
        name: 'opacity',
        afterSet: function(dom, value, el) {
            if (el.isLayer) {
                el.onOpacitySet(value);
            }
        }
    };
    if (!Ext.supports.Opacity && Ext.isIE) {
        Ext.apply(hooks.opacity, {
            get: function (dom) {
                var filter = dom.style.filter,
                    match, opacity;
                if (filter.match) {
                    match = filter.match(opacityRe);
                    if (match) {
                        opacity = parseFloat(match[1]);
                        if (!isNaN(opacity)) {
                            return opacity ? opacity / 100 : 0;
                        }
                    }
                }
                return 1;
            },
            set: function (dom, value) {
                var style = dom.style,
                    val = style.filter.replace(opacityRe, '').replace(trimRe, '');

                style.zoom = 1; 

                
                if (typeof(value) == 'number' && value >= 0 && value < 1) {
                    value *= 100;
                    style.filter = val + (val.length ? ' ' : '') + 'alpha(opacity='+value+')';
                } else {
                    style.filter = val;
                }
            }  
        });
    }
    
    
});


Ext.dom.Element.override({
    select: function(selector) {
        return Ext.dom.Element.select(selector, false,  this.dom);
    }
});


Ext.define('Ext.dom.CompositeElementLite', {
    alternateClassName: 'Ext.CompositeElementLite',

    requires: ['Ext.dom.Element'],

    statics: {
        
        importElementMethods: function() {
            var name,
                elementPrototype = Ext.dom.Element.prototype,
                prototype = this.prototype;

            for (name in elementPrototype) {
                if (typeof elementPrototype[name] == 'function'){
                    (function(key) {
                        prototype[key] = prototype[key] || function() {
                            return this.invoke(key, arguments);
                        };
                    }).call(prototype, name);

                }
            }
        }
    },

    constructor: function(elements, root) {
        
        this.elements = [];
        this.add(elements, root);
        this.el = new Ext.dom.AbstractElement.Fly();
    },

    
    isComposite: true,

    
    getElement: function(el) {
        
        return this.el.attach(el);
    },

    
    transformElement: function(el) {
        return Ext.getDom(el);
    },

    
    getCount: function() {
        return this.elements.length;
    },

    
    add: function(els, root) {
        var elements = this.elements,
            i, ln;

        if (!els) {
            return this;
        }

        if (typeof els == "string") {
            els = Ext.dom.Element.selectorFunction(els, root);
        }
        else if (els.isComposite) {
            els = els.elements;
        }
        else if (!Ext.isIterable(els)) {
            els = [els];
        }

        for (i = 0, ln = els.length; i < ln; ++i) {
            elements.push(this.transformElement(els[i]));
        }

        return this;
    },

    invoke: function(fn, args) {
        var elements = this.elements,
            ln = elements.length,
            element,
            i;

        fn = Ext.dom.Element.prototype[fn];
        for (i = 0; i < ln; i++) {
            element = elements[i];

            if (element) {
                fn.apply(this.getElement(element), args);
            }
        }
        return this;
    },

    
    item: function(index) {
        var el = this.elements[index],
            out = null;

        if (el) {
            out = this.getElement(el);
        }

        return out;
    },

    
    addListener: function(eventName, handler, scope, opt) {
        var els = this.elements,
                len = els.length,
                i, e;

        for (i = 0; i < len; i++) {
            e = els[i];
            if (e) {
                Ext.EventManager.on(e, eventName, handler, scope || e, opt);
            }
        }
        return this;
    },
    
    each: function(fn, scope) {
        var me  = this,
            els = me.elements,
            len = els.length,
            i, e;

        for (i = 0; i < len; i++) {
            e = els[i];
            if (e) {
                e = this.getElement(e);
                if (fn.call(scope || e, e, me, i) === false) {
                    break;
                }
            }
        }
        return me;
    },

    
    fill: function(els) {
        var me = this;
        me.elements = [];
        me.add(els);
        return me;
    },

    
    filter: function(selector) {
        var me  = this,
            els = me.elements,
            len = els.length,
            out = [],
            i = 0,
            isFunc = typeof selector == 'function',
            add,
            el;

        for (; i < len; i++) {
            el = els[i];
            add = false;
            if (el) {
                el = me.getElement(el);

                if (isFunc) {
                    add = selector.call(el, el, me, i) !== false;
                } else {
                    add = el.is(selector);
                }
                
                if (add) {
                    out.push(me.transformElement(el));
                }
            }
        }

        me.elements = out;
        return me;
    },

    
    indexOf: function(el) {
        return Ext.Array.indexOf(this.elements, this.transformElement(el));
    },

    
    replaceElement: function(el, replacement, domReplace) {
        var index = !isNaN(el) ? el : this.indexOf(el),
                d;
        if (index > -1) {
            replacement = Ext.getDom(replacement);
            if (domReplace) {
                d = this.elements[index];
                d.parentNode.insertBefore(replacement, d);
                Ext.removeNode(d);
            }
            Ext.Array.splice(this.elements, index, 1, replacement);
        }
        return this;
    },

    
    clear: function() {
        this.elements = [];
    },

    addElements: function(els, root) {
        if (!els) {
            return this;
        }

        if (typeof els == "string") {
            els = Ext.dom.Element.selectorFunction(els, root);
        }

        var yels = this.elements,
            eLen = els.length,
            e;

        for (e = 0; e < eLen; e++) {
            yels.push(Ext.get(els[e]));
        }

        return this;
    },

    
    first: function() {
        return this.item(0);
    },

    
    last: function() {
        return this.item(this.getCount() - 1);
    },

    
    contains: function(el) {
        return this.indexOf(el) != -1;
    },

    
    removeElement: function(keys, removeDom) {
        keys = [].concat(keys);

        var me       = this,
            elements = me.elements,
            kLen     = keys.length,
            val, el, k;

        for (k = 0; k < kLen; k++) {
            val = keys[k];

            if ((el = (elements[val] || elements[val = me.indexOf(val)]))) {
                if (removeDom) {
                    if (el.dom) {
                        el.remove();
                    } else {
                        Ext.removeNode(el);
                    }
                }
                Ext.Array.erase(elements, val, 1);
            }
        }

        return me;
    }

}, function() {
    this.importElementMethods();

    this.prototype.on = this.prototype.addListener;

    if (Ext.DomQuery){
        Ext.dom.Element.selectorFunction = Ext.DomQuery.select;
    }

    
   Ext.dom.Element.select = function(selector, root) {
        var elements;

        if (typeof selector == "string") {
            elements = Ext.dom.Element.selectorFunction(selector, root);
        }
        else if (selector.length !== undefined) {
            elements = selector;
        }
        else {
        }

        return new Ext.CompositeElementLite(elements);
    };

    
    Ext.select = function() {
        return Ext.dom.Element.select.apply(Ext.dom.Element, arguments);
    };
});


Ext.define('Ext.dom.CompositeElement', {
    alternateClassName: 'Ext.CompositeElement',

    extend: 'Ext.dom.CompositeElementLite',

    
    getElement: function(el) {
        
        return el;
    },

    
    transformElement: function(el) {
        return Ext.get(el);
    }

}, function() {
    

    Ext.dom.Element.select = function(selector, unique, root) {
        var elements;

        if (typeof selector == "string") {
            elements = Ext.dom.Element.selectorFunction(selector, root);
        }
        else if (selector.length !== undefined) {
            elements = selector;
        }
        else {
        }
        return (unique === true) ? new Ext.CompositeElement(elements) : new Ext.CompositeElementLite(elements);
    };
});


Ext.select = Ext.Element.select;



Ext.define('Ext.AbstractPlugin', {
    disabled: false,

    constructor: function(config) {
        this.initialConfig = config;
        Ext.apply(this, config);
    },

    clone: function() {
        return new this.self(this.initialConfig);
    },

    getCmp: function() {
        return this.cmp;
    },

    

    
    init: Ext.emptyFn,

    
    destroy: Ext.emptyFn,

    
    enable: function() {
        this.disabled = false;
    },

    
    disable: function() {
        this.disabled = true;
    }
});

Ext.define('Ext.ComponentQuery', {
    singleton: true,
    uses: ['Ext.ComponentManager']
}, function() {

    var cq = this,

        
        
        filterFnPattern = [
            'var r = [],',
                'i = 0,',
                'it = items,',
                'l = it.length,',
                'c;',
            'for (; i < l; i++) {',
                'c = it[i];',
                'if (c.{0}) {',
                   'r.push(c);',
                '}',
            '}',
            'return r;'
        ].join(''),

        filterItems = function(items, operation) {
            
            
            
            return operation.method.apply(this, [ items ].concat(operation.args));
        },

        getItems = function(items, mode) {
            var result = [],
                i = 0,
                length = items.length,
                candidate,
                deep = mode !== '>';
                
            for (; i < length; i++) {
                candidate = items[i];
                if (candidate.getRefItems) {
                    result = result.concat(candidate.getRefItems(deep));
                }
            }
            return result;
        },

        getAncestors = function(items) {
            var result = [],
                i = 0,
                length = items.length,
                candidate;
            for (; i < length; i++) {
                candidate = items[i];
                while (!!(candidate = (candidate.ownerCt || candidate.floatParent))) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterByXType = function(items, xtype, shallow) {
            if (xtype === '*') {
                return items.slice();
            }
            else {
                var result = [],
                    i = 0,
                    length = items.length,
                    candidate;
                for (; i < length; i++) {
                    candidate = items[i];
                    if (candidate.isXType(xtype, shallow)) {
                        result.push(candidate);
                    }
                }
                return result;
            }
        },

        
        filterByClassName = function(items, className) {
            var EA = Ext.Array,
                result = [],
                i = 0,
                length = items.length,
                candidate;
            for (; i < length; i++) {
                candidate = items[i];
                if (candidate.hasCls(className)) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterByAttribute = function(items, property, operator, value) {
            var result = [],
                i = 0,
                length = items.length,
                candidate;
            for (; i < length; i++) {
                candidate = items[i];
                if (!value ? !!candidate[property] : (String(candidate[property]) === value)) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterById = function(items, id) {
            var result = [],
                i = 0,
                length = items.length,
                candidate;
            for (; i < length; i++) {
                candidate = items[i];
                if (candidate.getItemId() === id) {
                    result.push(candidate);
                }
            }
            return result;
        },

        
        filterByPseudo = function(items, name, value) {
            return cq.pseudos[name](items, value);
        },

        
        
        modeRe = /^(\s?([>\^])\s?|\s|$)/,

        
        tokenRe = /^(#)?([\w\-]+|\*)(?:\((true|false)\))?/,

        matchers = [{
            
            re: /^\.([\w\-]+)(?:\((true|false)\))?/,
            method: filterByXType
        },{
            
            re: /^(?:[\[](?:@)?([\w\-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]])/,
            method: filterByAttribute
        }, {
            
            re: /^#([\w\-]+)/,
            method: filterById
        }, {
            
            re: /^\:([\w\-]+)(?:\(((?:\{[^\}]+\})|(?:(?!\{)[^\s>\/]*?(?!\})))\))?/,
            method: filterByPseudo
        }, {
            
            re: /^(?:\{([^\}]+)\})/,
            method: filterFnPattern
        }];

    
    cq.Query = Ext.extend(Object, {
        constructor: function(cfg) {
            cfg = cfg || {};
            Ext.apply(this, cfg);
        },

        
        
        
        
        
        
        
        
        execute : function(root) {
            var operations = this.operations,
                i = 0,
                length = operations.length,
                operation,
                workingItems;

            
            if (!root) {
                workingItems = Ext.ComponentManager.all.getArray();
            }
            
            else if (Ext.isArray(root)) {
                workingItems = root;
            }
            
            else if (root.isMixedCollection) {
                workingItems = root.items;
            }

            
            
            for (; i < length; i++) {
                operation = operations[i];

                
                
                
                
                
                
                if (operation.mode === '^') {
                    workingItems = getAncestors(workingItems || [root]);
                }
                else if (operation.mode) {
                    workingItems = getItems(workingItems || [root], operation.mode);
                }
                else {
                    workingItems = filterItems(workingItems || getItems([root]), operation);
                }

                
                
                if (i === length -1) {
                    return workingItems;
                }
            }
            return [];
        },

        is: function(component) {
            var operations = this.operations,
                components = Ext.isArray(component) ? component : [component],
                originalLength = components.length,
                lastOperation = operations[operations.length-1],
                ln, i;

            components = filterItems(components, lastOperation);
            if (components.length === originalLength) {
                if (operations.length > 1) {
                    for (i = 0, ln = components.length; i < ln; i++) {
                        if (Ext.Array.indexOf(this.execute(), components[i]) === -1) {
                            return false;
                        }
                    }
                }
                return true;
            }
            return false;
        }
    });

    Ext.apply(this, {

        
        cache: {},

        
        pseudos: {
            not: function(components, selector){
                var CQ = Ext.ComponentQuery,
                    i = 0,
                    length = components.length,
                    results = [],
                    index = -1,
                    component;
                
                for(; i < length; ++i) {
                    component = components[i];
                    if (!CQ.is(component, selector)) {
                        results[++index] = component;
                    }
                }
                return results;
            },
            first: function(components) {
                var ret = [];
                    
                if (components.length > 0) {
                    ret.push(components[0]);
                }
                return ret;       
            },
            last: function(components) {
                var len = components.length,
                    ret = [];
                    
                if (len > 0) {
                    ret.push(components[len - 1]);
                }
                return ret;
            }
        },

        
        query: function(selector, root) {
            var selectors = selector.split(','),
                length = selectors.length,
                i = 0,
                results = [],
                noDupResults = [], 
                dupMatcher = {}, 
                query, resultsLn, cmp;

            for (; i < length; i++) {
                selector = Ext.String.trim(selectors[i]);
                query = this.cache[selector] || (this.cache[selector] = this.parse(selector));
                results = results.concat(query.execute(root));
            }

            
            
            if (length > 1) {
                resultsLn = results.length;
                for (i = 0; i < resultsLn; i++) {
                    cmp = results[i];
                    if (!dupMatcher[cmp.id]) {
                        noDupResults.push(cmp);
                        dupMatcher[cmp.id] = true;
                    }
                }
                results = noDupResults;
            }
            return results;
        },

        
        is: function(component, selector) {
            if (!selector) {
                return true;
            }
            var selectors = selector.split(','),
                length = selectors.length,
                i = 0,
                query;

            for (; i < length; i++) {
                selector = Ext.String.trim(selectors[i]);
                query = this.cache[selector] || (this.cache[selector] = this.parse(selector));
                if (query.is(component)) {
                    return true;
                }
            }
            return false;
        },

        parse: function(selector) {
            var operations = [],
                length = matchers.length,
                lastSelector,
                tokenMatch,
                matchedChar,
                modeMatch,
                selectorMatch,
                i, matcher, method;

            
            
            
            while (selector && lastSelector !== selector) {
                lastSelector = selector;

                
                tokenMatch = selector.match(tokenRe);

                if (tokenMatch) {
                    matchedChar = tokenMatch[1];

                    
                    if (matchedChar === '#') {
                        operations.push({
                            method: filterById,
                            args: [Ext.String.trim(tokenMatch[2])]
                        });
                    }
                    
                    
                    else if (matchedChar === '.') {
                        operations.push({
                            method: filterByClassName,
                            args: [Ext.String.trim(tokenMatch[2])]
                        });
                    }
                    
                    
                    else {
                        operations.push({
                            method: filterByXType,
                            args: [Ext.String.trim(tokenMatch[2]), Boolean(tokenMatch[3])]
                        });
                    }

                    
                    selector = selector.replace(tokenMatch[0], '');
                }

                
                
                
                while (!(modeMatch = selector.match(modeRe))) {
                    
                    
                    for (i = 0; selector && i < length; i++) {
                        matcher = matchers[i];
                        selectorMatch = selector.match(matcher.re);
                        method = matcher.method;

                        
                        
                        
                        if (selectorMatch) {
                            operations.push({
                                method: Ext.isString(matcher.method)
                                    
                                    
                                    
                                    ? Ext.functionFactory('items', Ext.String.format.apply(Ext.String, [method].concat(selectorMatch.slice(1))))
                                    : matcher.method,
                                args: selectorMatch.slice(1)
                            });
                            selector = selector.replace(selectorMatch[0], '');
                            break; 
                        }
                        
                        if (i === (length - 1)) {
                            Ext.Error.raise('Invalid ComponentQuery selector: "' + arguments[0] + '"');
                        }
                    }
                }

                
                
                
                
                if (modeMatch[1]) { 
                    operations.push({
                        mode: modeMatch[2]||modeMatch[1]
                    });
                    selector = selector.replace(modeMatch[0], '');
                }
            }

            
            
            return new cq.Query({
                operations: operations
            });
        }
    });
});

Ext.define('Ext.Template', {

    

    requires: ['Ext.dom.Helper', 'Ext.util.Format'],

    inheritableStatics: {
        
        from: function(el, config) {
            el = Ext.getDom(el);
            return new this(el.value || el.innerHTML, config || '');
        }
    },

    

    
    constructor: function(html) {
        var me = this,
            args = arguments,
            buffer = [],
            i = 0,
            length = args.length,
            value;

        me.initialConfig = {};
        
        
        
        
        if (length === 1 && Ext.isArray(html)) {
            args = html;
            length = args.length;
        }

        if (length > 1) {
            for (; i < length; i++) {
                value = args[i];
                if (typeof value == 'object') {
                    Ext.apply(me.initialConfig, value);
                    Ext.apply(me, value);
                } else {
                    buffer.push(value);
                }
            }
        } else {
            buffer.push(html);
        }

        
        me.html = buffer.join('');

        if (me.compiled) {
            me.compile();
        }
    },

    
    isTemplate: true,

    

    
    disableFormats: false,

    re: /\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,

    
    apply: function(values) {
        var me = this,
            useFormat = me.disableFormats !== true,
            fm = Ext.util.Format,
            tpl = me,
            ret;

        if (me.compiled) {
            return me.compiled(values).join('');
        }

        function fn(m, name, format, args) {
            if (format && useFormat) {
                if (args) {
                    args = [values[name]].concat(Ext.functionFactory('return ['+ args +'];')());
                } else {
                    args = [values[name]];
                }
                if (format.substr(0, 5) == "this.") {
                    return tpl[format.substr(5)].apply(tpl, args);
                }
                else {
                    return fm[format].apply(fm, args);
                }
            }
            else {
                return values[name] !== undefined ? values[name] : "";
            }
        }

        ret = me.html.replace(me.re, fn);
        return ret;
    },

    
    applyOut: function(values, out) {
        var me = this;

        if (me.compiled) {
            out.push.apply(out, me.compiled(values));
        } else {
            out.push(me.apply(values));
        }

        return out;
    },

    
    applyTemplate: function () {
        return this.apply.apply(this, arguments);
    },

    
    set: function(html, compile) {
        var me = this;
        me.html = html;
        me.compiled = null;
        return compile ? me.compile() : me;
    },

    compileARe: /\\/g,
    compileBRe: /(\r\n|\n)/g,
    compileCRe: /'/g,

    /**
     * Compiles the template into an internal function, eliminating the RegEx overhead.
     * @return {Ext.Template} this
     */
    compile: function() {
        var me = this,
            fm = Ext.util.Format,
            useFormat = me.disableFormats !== true,
            body, bodyReturn;

        function fn(m, name, format, args) {
            if (format && useFormat) {
                args = args ? ',' + args: "";
                if (format.substr(0, 5) != "this.") {
                    format = "fm." + format + '(';
                }
                else {
                    format = 'this.' + format.substr(5) + '(';
                }
            }
            else {
                args = '';
                format = "(values['" + name + "'] == undefined ? '' : ";
            }
            return "'," + format + "values['" + name + "']" + args + ") ,'";
        }

        bodyReturn = me.html.replace(me.compileARe, '\\\\').replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn);
        body = "this.compiled = function(values){ return ['" + bodyReturn + "'];};";
        eval(body);
        return me;
    },

    /**
     * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
     *
     * @param {String/HTMLElement/Ext.Element} el The context element
     * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
     * @param {Boolean} returnElement (optional) true to return a Ext.Element.
     * @return {HTMLElement/Ext.Element} The new node or Element
     */
    insertFirst: function(el, values, returnElement) {
        return this.doInsert('afterBegin', el, values, returnElement);
    },

    /**
     * Applies the supplied values to the template and inserts the new node(s) before el.
     *
     * @param {String/HTMLElement/Ext.Element} el The context element
     * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
     * @param {Boolean} returnElement (optional) true to return a Ext.Element.
     * @return {HTMLElement/Ext.Element} The new node or Element
     */
    insertBefore: function(el, values, returnElement) {
        return this.doInsert('beforeBegin', el, values, returnElement);
    },

    /**
     * Applies the supplied values to the template and inserts the new node(s) after el.
     *
     * @param {String/HTMLElement/Ext.Element} el The context element
     * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
     * @param {Boolean} returnElement (optional) true to return a Ext.Element.
     * @return {HTMLElement/Ext.Element} The new node or Element
     */
    insertAfter: function(el, values, returnElement) {
        return this.doInsert('afterEnd', el, values, returnElement);
    },

    /**
     * Applies the supplied `values` to the template and appends the new node(s) to the specified `el`.
     *
     * For example usage see {@link Ext.Template Ext.Template class docs}.
     *
     * @param {String/HTMLElement/Ext.Element} el The context element
     * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
     * @param {Boolean} returnElement (optional) true to return an Ext.Element.
     * @return {HTMLElement/Ext.Element} The new node or Element
     */
    append: function(el, values, returnElement) {
        return this.doInsert('beforeEnd', el, values, returnElement);
    },

    doInsert: function(where, el, values, returnElement) {
        var newNode = Ext.DomHelper.insertHtml(where, Ext.getDom(el), this.apply(values));
        return returnElement ? Ext.get(newNode) : newNode;
    },

    /**
     * Applies the supplied values to the template and overwrites the content of el with the new node(s).
     *
     * @param {String/HTMLElement/Ext.Element} el The context element
     * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
     * @param {Boolean} returnElement (optional) true to return a Ext.Element.
     * @return {HTMLElement/Ext.Element} The new node or Element
     */
    overwrite: function(el, values, returnElement) {
        var newNode = Ext.DomHelper.overwrite(Ext.getDom(el), this.apply(values));
        return returnElement ? Ext.get(newNode) : newNode;
    }
});

/**
 * This class parses the XTemplate syntax and calls abstract methods to process the parts.
 * @private
 */
Ext.define('Ext.XTemplateParser', {
    constructor: function (config) {
        Ext.apply(this, config);
    },

    /**
     * @property {Number} level The 'for' loop context level. This is adjusted up by one
     * prior to calling {@link #doFor} and down by one after calling the corresponding
     * {@link #doEnd} that closes the loop. This will be 1 on the first {@link #doFor}
     * call.
     */

    /**
     * This method is called to process a piece of raw text from the tpl.
     * @param {String} text
     * @method doText
     */
    // doText: function (text)

    /**
     * This method is called to process expressions (like `{[expr]}`).
     * @param {String} expr The body of the expression (inside "{[" and "]}").
     * @method doExpr
     */
    // doExpr: function (expr)

    /**
     * This method is called to process simple tags (like `{tag}`).
     * @method doTag
     */
    // doTag: function (tag)

    /**
     * This method is called to process `<tpl else>`.
     * @method doElse
     */
    // doElse: function ()

    /**
     * This method is called to process `{% text %}`.
     * @param {String} text
     * @method doEval
     */
    // doEval: function (text)

    /**
     * This method is called to process `<tpl if="action">`. If there are other attributes,
     * these are passed in the actions object.
     * @param {String} action
     * @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
     * @method doIf
     */
    // doIf: function (action, actions)

    /**
     * This method is called to process `<tpl elseif="action">`. If there are other attributes,
     * these are passed in the actions object.
     * @param {String} action
     * @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
     * @method doElseIf
     */
    // doElseIf: function (action, actions)

    /**
     * This method is called to process `<tpl switch="action">`. If there are other attributes,
     * these are passed in the actions object.
     * @param {String} action
     * @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
     * @method doSwitch
     */
    // doSwitch: function (action, actions)

    /**
     * This method is called to process `<tpl case="action">`. If there are other attributes,
     * these are passed in the actions object.
     * @param {String} action
     * @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
     * @method doCase
     */
    // doCase: function (action, actions)

    /**
     * This method is called to process `<tpl default>`.
     * @method doDefault
     */
    // doDefault: function ()

    /**
     * This method is called to process `</tpl>`. It is given the action type that started
     * the tpl and the set of additional actions.
     * @param {String} type The type of action that is being ended.
     * @param {Object} actions The other actions keyed by the attribute name (such as 'exec').
     * @method doEnd
     */
    // doEnd: function (type, actions) 

    /**
     * This method is called to process `<tpl for="action">`. If there are other attributes,
     * these are passed in the actions object.
     * @param {String} action
     * @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
     * @method doFor
     */
    // doFor: function (action, actions)

    /**
     * This method is called to process `<tpl exec="action">`. If there are other attributes,
     * these are passed in the actions object.
     * @param {String} action
     * @param {Object} actions Other actions keyed by the attribute name.
     * @method doExec
     */
    // doExec: function (action, actions)

    /**
     * This method is called to process an empty `<tpl>`. This is unlikely to need to be
     * implemented, so a default (do nothing) version is provided.
     * @method
     */
    doTpl: Ext.emptyFn,

    parse: function (str) {
        var me = this,
            len = str.length,
            aliases = { elseif: 'elif' },
            topRe = me.topRe,
            actionsRe = me.actionsRe,
            index, stack, s, m, t, prev, frame, subMatch, begin, end, actions,
            prop;

        me.level = 0;
        me.stack = stack = [];

        for (index = 0; index < len; index = end) {
            topRe.lastIndex = index;
            m = topRe.exec(str);

            if (!m) {
                me.doText(str.substring(index, len));
                break;
            }

            begin = m.index;
            end = topRe.lastIndex;

            if (index < begin) {
                me.doText(str.substring(index, begin));
            }

            if (m[1]) {
                end = str.indexOf('%}', begin+2);
                me.doEval(str.substring(begin+2, end));
                end += 2;
            } else if (m[2]) {
                end = str.indexOf(']}', begin+2);
                me.doExpr(str.substring(begin+2, end));
                end += 2;
            } else if (m[3]) { // if ('{' token)
                me.doTag(m[3]);
            } else if (m[4]) { // content of a <tpl xxxxxx xxx> tag
                actions = null;
                while ((subMatch = actionsRe.exec(m[4])) !== null) {
                    s = subMatch[2] || subMatch[3];
                    if (s) {
                        s = Ext.String.htmlDecode(s); // decode attr value
                        t = subMatch[1];
                        t = aliases[t] || t;
                        actions = actions || {};
                        prev = actions[t];

                        if (typeof prev == 'string') {
                            actions[t] = [prev, s];
                        } else if (prev) {
                            actions[t].push(s);
                        } else {
                            actions[t] = s;
                        }
                    }
                }

                if (!actions) {
                    if (me.elseRe.test(m[4])) {
                        me.doElse();
                    } else if (me.defaultRe.test(m[4])) {
                        me.doDefault();
                    } else {
                        me.doTpl();
                        stack.push({ type: 'tpl' });
                    }
                }
                else if (actions['if']) {
                    me.doIf(actions['if'], actions);
                    stack.push({ type: 'if' });
                }
                else if (actions['switch']) {
                    me.doSwitch(actions['switch'], actions);
                    stack.push({ type: 'switch' });
                }
                else if (actions['case']) {
                    me.doCase(actions['case'], actions);
                }
                else if (actions['elif']) {
                    me.doElseIf(actions['elif'], actions);
                }
                else if (actions['for']) {
                    ++me.level;

                    // Extract property name to use from indexed item
                    if (prop = me.propRe.exec(m[4])) {
                        actions.propName = prop[1] || prop[2];
                    }
                    me.doFor(actions['for'], actions);
                    stack.push({ type: 'for', actions: actions });
                }
                else if (actions.exec) {
                    me.doExec(actions.exec, actions);
                    stack.push({ type: 'exec', actions: actions });
                }
                /*
                else {
                    // todo - error
                }
                */
            } else if (m[0].length === 5) {
                // if the length of m[0] is 5, assume that we're dealing with an opening tpl tag with no attributes (e.g. <tpl>...</tpl>)
                // in this case no action is needed other than pushing it on to the stack
                stack.push({ type: 'tpl' });
            } else {
                frame = stack.pop();
                me.doEnd(frame.type, frame.actions);
                if (frame.type == 'for') {
                    --me.level;
                }
            }
        }
    },

    // Internal regexes
    
    topRe:     /(?:(\{\%)|(\{\[)|\{([^{}]*)\})|(?:<tpl([^>]*)\>)|(?:<\/tpl>)/g,
    actionsRe: /\s*(elif|elseif|if|for|exec|switch|case|eval)\s*\=\s*(?:(?:"([^"]*)")|(?:'([^']*)'))\s*/g,
    propRe:    /prop=(?:(?:"([^"]*)")|(?:'([^']*)'))/,
    defaultRe: /^\s*default\s*$/,
    elseRe:    /^\s*else\s*$/
});


Ext.define('Ext.chart.Callout', {

    

    

    constructor: function(config) {
        if (config.callouts) {
            config.callouts.styles = Ext.applyIf(config.callouts.styles || {}, {
                color: "#000",
                font: "11px Helvetica, sans-serif"
            });
            this.callouts = Ext.apply(this.callouts || {}, config.callouts);
            this.calloutsArray = [];
        }
    },

    renderCallouts: function() {
        if (!this.callouts) {
            return;
        }

        var me = this,
            items = me.items,
            animate = me.chart.animate,
            config = me.callouts,
            styles = config.styles,
            group = me.calloutsArray,
            store = me.chart.store,
            len = store.getCount(),
            ratio = items.length / len,
            previouslyPlacedCallouts = [],
            i,
            count,
            j,
            p,
            item,
            label,
            storeItem,
            display;
            
        for (i = 0, count = 0; i < len; i++) {
            for (j = 0; j < ratio; j++) {
                item = items[count];
                label = group[count];
                storeItem = store.getAt(i);
                
                display = config.filter(storeItem);
                
                if (!display && !label) {
                    count++;
                    continue;               
                }
                
                if (!label) {
                    group[count] = label = me.onCreateCallout(storeItem, item, i, display, j, count);
                }
                for (p in label) {
                    if (label[p] && label[p].setAttributes) {
                        label[p].setAttributes(styles, true);
                    }
                }
                if (!display) {
                    for (p in label) {
                        if (label[p]) {
                            if (label[p].setAttributes) {
                                label[p].setAttributes({
                                    hidden: true
                                }, true);
                            } else if(label[p].setVisible) {
                                label[p].setVisible(false);
                            }
                        }
                    }
                }
                config.renderer(label, storeItem);
                me.onPlaceCallout(label, storeItem, item, i, display, animate,
                                  j, count, previouslyPlacedCallouts);
                previouslyPlacedCallouts.push(label);
                count++;
            }
        }
        this.hideCallouts(count);
    },

    onCreateCallout: function(storeItem, item, i, display) {
        var me = this,
            group = me.calloutsGroup,
            config = me.callouts,
            styles = config.styles,
            width = styles.width,
            height = styles.height,
            chart = me.chart,
            surface = chart.surface,
            calloutObj = {
                
                
                lines: false
            };

        calloutObj.lines = surface.add(Ext.apply({},
        {
            type: 'path',
            path: 'M0,0',
            stroke: me.getLegendColor() || '#555'
        },
        styles));

        if (config.items) {
            calloutObj.panel = new Ext.Panel({
                style: "position: absolute;",    
                width: width,
                height: height,
                items: config.items,
                renderTo: chart.el
            });
        }

        return calloutObj;
    },

    hideCallouts: function(index) {
        var calloutsArray = this.calloutsArray,
            len = calloutsArray.length,
            co,
            p;
        while (len-->index) {
            co = calloutsArray[len];
            for (p in co) {
                if (co[p]) {
                    co[p].hide(true);
                }
            }
        }
    }
});


Ext.define('Ext.chart.Navigation', {

    constructor: function() {
        this.originalStore = this.store;
    },

    
    setZoom: function(zoomConfig) {
        var me = this,
            axes = me.axes,
            axesItems = axes.items,
            i, ln, axis,
            bbox = me.chartBBox,
            xScale = 1 / bbox.width,
            yScale = 1 / bbox.height,
            zoomer = {
                x : zoomConfig.x * xScale,
                y : zoomConfig.y * yScale,
                width : zoomConfig.width * xScale,
                height : zoomConfig.height * yScale
            },
            ends, from, to;
        for (i = 0, ln = axesItems.length; i < ln; i++) {
            axis = axesItems[i];
            ends = axis.calcEnds();
            if (axis.position == 'bottom' || axis.position == 'top') {
                from = (ends.to - ends.from) * zoomer.x + ends.from;
                to = (ends.to - ends.from) * zoomer.width + from;
                axis.minimum = from;
                axis.maximum = to;
            } else {
                to = (ends.to - ends.from) * (1 - zoomer.y) + ends.from;
                from = to - (ends.to - ends.from) * zoomer.height;
                axis.minimum = from;
                axis.maximum = to;
            }
        }
        me.redraw(false);
    },

    
    restoreZoom: function() {
        if (this.originalStore) {
            this.store = this.substore = this.originalStore;
            this.redraw(true);
        }
    }

});


Ext.define('Ext.chart.Shape', {

    

    singleton: true,

    

    circle: function (surface, opts) {
        return surface.add(Ext.apply({
            type: 'circle',
            x: opts.x,
            y: opts.y,
            stroke: null,
            radius: opts.radius
        }, opts));
    },
    line: function (surface, opts) {
        return surface.add(Ext.apply({
            type: 'rect',
            x: opts.x - opts.radius,
            y: opts.y - opts.radius,
            height: 2 * opts.radius,
            width: 2 * opts.radius / 5
        }, opts));
    },
    square: function (surface, opts) {
        return surface.add(Ext.applyIf({
            type: 'rect',
            x: opts.x - opts.radius,
            y: opts.y - opts.radius,
            height: 2 * opts.radius,
            width: 2 * opts.radius,
            radius: null
        }, opts));
    },
    triangle: function (surface, opts) {
        opts.radius *= 1.75;
        return surface.add(Ext.apply({
            type: 'path',
            stroke: null,
            path: "M".concat(opts.x, ",", opts.y, "m0-", opts.radius * 0.58, "l", opts.radius * 0.5, ",", opts.radius * 0.87, "-", opts.radius, ",0z")
        }, opts));
    },
    diamond: function (surface, opts) {
        var r = opts.radius;
        r *= 1.5;
        return surface.add(Ext.apply({
            type: 'path',
            stroke: null,
            path: ["M", opts.x, opts.y - r, "l", r, r, -r, r, -r, -r, r, -r, "z"]
        }, opts));
    },
    cross: function (surface, opts) {
        var r = opts.radius;
        r = r / 1.7;
        return surface.add(Ext.apply({
            type: 'path',
            stroke: null,
            path: "M".concat(opts.x - r, ",", opts.y, "l", [-r, -r, r, -r, r, r, r, -r, r, r, -r, r, r, r, -r, r, -r, -r, -r, r, -r, -r, "z"])
        }, opts));
    },
    plus: function (surface, opts) {
        var r = opts.radius / 1.3;
        return surface.add(Ext.apply({
            type: 'path',
            stroke: null,
            path: "M".concat(opts.x - r / 2, ",", opts.y - r / 2, "l", [0, -r, r, 0, 0, r, r, 0, 0, r, -r, 0, 0, r, -r, 0, 0, -r, -r, 0, 0, -r, "z"])
        }, opts));
    },
    arrow: function (surface, opts) {
        var r = opts.radius;
        return surface.add(Ext.apply({
            type: 'path',
            path: "M".concat(opts.x - r * 0.7, ",", opts.y - r * 0.4, "l", [r * 0.6, 0, 0, -r * 0.4, r, r * 0.8, -r, r * 0.8, 0, -r * 0.4, -r * 0.6, 0], "z")
        }, opts));
    },
    drop: function (surface, x, y, text, size, angle) {
        size = size || 30;
        angle = angle || 0;
        surface.add({
            type: 'path',
            path: ['M', x, y, 'l', size, 0, 'A', size * 0.4, size * 0.4, 0, 1, 0, x + size * 0.7, y - size * 0.7, 'z'],
            fill: '#000',
            stroke: 'none',
            rotate: {
                degrees: 22.5 - angle,
                x: x,
                y: y
            }
        });
        angle = (angle + 90) * Math.PI / 180;
        surface.add({
            type: 'text',
            x: x + size * Math.sin(angle) - 10, 
            y: y + size * Math.cos(angle) + 5,
            text:  text,
            'font-size': size * 12 / 40,
            stroke: 'none',
            fill: '#fff'
        });
    }
});

Ext.define('Ext.data.IdGenerator', {

    
    isGenerator: true,

    
    constructor: function(config) {
        var me = this;

        Ext.apply(me, config);

        if (me.id) {
            Ext.data.IdGenerator.all[me.id] = me;
        }
    },

    

    getRecId: function (rec) {
        return rec.modelName + '-' + rec.internalId;
    },

    

    statics: {
        
        all: {},

        
        get: function (config) {
            var generator,
                id,
                type;

            if (typeof config == 'string') {
                id = type = config;
                config = null;
            } else if (config.isGenerator) {
                return config;
            } else {
                id = config.id || config.type;
                type = config.type;
            }

            generator = this.all[id];
            if (!generator) {
                generator = Ext.create('idgen.' + type, config);
            }

            return generator;
        }
    }
});


Ext.define('Ext.data.JsonP', {

    

    singleton: true,

    

    
    requestCount: 0,

    
    requests: {},

    
    timeout: 30000,

    
    disableCaching: true,

    
    disableCachingParam: '_dc',

    
    callbackKey: 'callback',

    
    request: function(options){
        options = Ext.apply({}, options);


        var me = this,
            disableCaching = Ext.isDefined(options.disableCaching) ? options.disableCaching : me.disableCaching,
            cacheParam = options.disableCachingParam || me.disableCachingParam,
            id = ++me.requestCount,
            callbackName = options.callbackName || 'callback' + id,
            callbackKey = options.callbackKey || me.callbackKey,
            timeout = Ext.isDefined(options.timeout) ? options.timeout : me.timeout,
            params = Ext.apply({}, options.params),
            url = options.url,
            name = Ext.name,
            request,
            script;

        params[callbackKey] = name + '.data.JsonP.' + callbackName;
        if (disableCaching) {
            params[cacheParam] = new Date().getTime();
        }

        script = me.createScript(url, params, options);

        me.requests[id] = request = {
            url: url,
            params: params,
            script: script,
            id: id,
            scope: options.scope,
            success: options.success,
            failure: options.failure,
            callback: options.callback,
            callbackKey: callbackKey,
            callbackName: callbackName
        };

        if (timeout > 0) {
            request.timeout = setTimeout(Ext.bind(me.handleTimeout, me, [request]), timeout);
        }

        me.setupErrorHandling(request);
        me[callbackName] = Ext.bind(me.handleResponse, me, [request], true);
        me.loadScript(request);
        return request;
    },

    
    abort: function(request){
        var me = this,
            requests = me.requests,
            key;

        if (request) {
            if (!request.id) {
                request = requests[request];
            }
            me.handleAbort(request);
        } else {
            for (key in requests) {
                if (requests.hasOwnProperty(key)) {
                    me.abort(requests[key]);
                }
            }
        }
    },

    
    setupErrorHandling: function(request){
        request.script.onerror = Ext.bind(this.handleError, this, [request]);
    },

    
    handleAbort: function(request){
        request.errorType = 'abort';
        this.handleResponse(null, request);
    },

    
    handleError: function(request){
        request.errorType = 'error';
        this.handleResponse(null, request);
    },

    
    cleanupErrorHandling: function(request){
        request.script.onerror = null;
    },

    
    handleTimeout: function(request){
        request.errorType = 'timeout';
        this.handleResponse(null, request);
    },

    
    handleResponse: function(result, request){

        var success = true;

        if (request.timeout) {
            clearTimeout(request.timeout);
        }
        delete this[request.callbackName];
        delete this.requests[request.id];
        this.cleanupErrorHandling(request);
        Ext.fly(request.script).remove();

        if (request.errorType) {
            success = false;
            Ext.callback(request.failure, request.scope, [request.errorType]);
        } else {
            Ext.callback(request.success, request.scope, [result]);
        }
        Ext.callback(request.callback, request.scope, [success, result, request.errorType]);
    },

    
    createScript: function(url, params, options) {
        var script = document.createElement('script');
        script.setAttribute("src", Ext.urlAppend(url, Ext.Object.toQueryString(params)));
        script.setAttribute("async", true);
        script.setAttribute("type", "text/javascript");
        return script;
    },

    
    loadScript: function (request) {
        Ext.getHead().appendChild(request.script);
    }
});


Ext.define('Ext.data.Operation', {
    
    synchronous: true,

    
    action: undefined,

    
    filters: undefined,

    
    sorters: undefined,

    
    groupers: undefined,

    
    start: undefined,

    
    limit: undefined,

    
    batch: undefined,
    
    

    
    callback: undefined,

    
    scope: undefined,

    
    started: false,

    
    running: false,

    
    complete: false,

    
    success: undefined,

    
    exception: false,

    
    error: undefined,

    
    actionCommitRecordsRe: /^(?:create|update)$/i,

    
    actionSkipSyncRe: /^destroy$/i,

    
    constructor: function(config) {
        Ext.apply(this, config || {});
    },

    
    commitRecords: function (serverRecords) {
        var me = this,
            mc, index, clientRecords, serverRec, clientRec, i, len;

        if (!me.actionSkipSyncRe.test(me.action)) {
            clientRecords = me.records;

            if (clientRecords && clientRecords.length) {
                if (clientRecords.length > 1) {
                    
                    
                    
                    
                    if (me.action == 'update' || clientRecords[0].clientIdProperty) {
                        mc = new Ext.util.MixedCollection();
                        mc.addAll(serverRecords);

                        for (index = clientRecords.length; index--; ) {
                            clientRec = clientRecords[index];
                            serverRec = mc.findBy(me.matchClientRec, clientRec);

                            
                            clientRec.copyFrom(serverRec);
                        }
                    } else {
                        for (i = 0, len = clientRecords.length; i < len; ++i) {
                            clientRec = clientRecords[i];
                            serverRec = serverRecords[i];
                            if (clientRec && serverRec) {
                                me.updateRecord(clientRec, serverRec);
                            }
                        }
                    }
                } else {
                    
                    this.updateRecord(clientRecords[0], serverRecords[0]);   
                }

                if (me.actionCommitRecordsRe.test(me.action)) {
                    for (index = clientRecords.length; index--; ) {
                        clientRecords[index].commit();
                    }
                }
            }
        }
    },
    
    updateRecord: function(clientRec, serverRec) {
        
        if(serverRec && (clientRec.phantom || clientRec.getId() === serverRec.getId())) {
            clientRec.copyFrom(serverRec);
        }
    },

    
    
    
    matchClientRec: function(record) {
        var clientRec = this,
            clientRecordId = clientRec.getId();

        if(clientRecordId && record.getId() === clientRecordId) {
            return true;
        }
        
        
        
        return record.internalId === clientRec.internalId;
    },

    
    setStarted: function() {
        this.started = true;
        this.running = true;
    },

    
    setCompleted: function() {
        this.complete = true;
        this.running  = false;
    },

    
    setSuccessful: function() {
        this.success = true;
    },

    
    setException: function(error) {
        this.exception = true;
        this.success = false;
        this.running = false;
        this.error = error;
    },

    
    hasException: function() {
        return this.exception === true;
    },

    
    getError: function() {
        return this.error;
    },

    
    getRecords: function() {
        var resultSet = this.getResultSet();
        return this.records || (resultSet ? resultSet.records : null);
    },

    
    getResultSet: function() {
        return this.resultSet;
    },

    
    isStarted: function() {
        return this.started === true;
    },

    
    isRunning: function() {
        return this.running === true;
    },

    
    isComplete: function() {
        return this.complete === true;
    },

    
    wasSuccessful: function() {
        return this.isComplete() && this.success === true;
    },

    
    setBatch: function(batch) {
        this.batch = batch;
    },

    
    allowWrite: function() {
        return this.action != 'read';
    }
});


Ext.define('Ext.data.Request', {
    
    action: undefined,
    
    
    params: undefined,
    
    
    method: 'GET',
    
    
    url: undefined,

    
    constructor: function(config) {
        Ext.apply(this, config);
    }
});

Ext.define('Ext.data.ResultSet', {
    
    loaded: true,

    
    count: 0,

    
    total: 0,

    
    success: false,

    

    
    constructor: function(config) {
        Ext.apply(this, config);

        
        this.totalRecords = this.total;

        if (config.count === undefined) {
            this.count = this.records.length;
        }
    }
});

Ext.define('Ext.data.SequentialIdGenerator', {
    extend: 'Ext.data.IdGenerator',
    alias: 'idgen.sequential',

    constructor: function() {
        var me = this;

        me.callParent(arguments);

        me.parts = [ me.prefix, ''];
    },

    
    prefix: '',

    
    seed: 1,

    
    generate: function () {
        var me = this,
            parts = me.parts;

        parts[1] = me.seed++;
        return parts.join('');
    }
});


Ext.define('Ext.data.SortTypes', {
    
    singleton: true,
    
    
    none : function(s) {
        return s;
    },

    
    stripTagsRE : /<\/?[^>]+>/gi,

    
    asText : function(s) {
        return String(s).replace(this.stripTagsRE, "");
    },

    
    asUCText : function(s) {
        return String(s).toUpperCase().replace(this.stripTagsRE, "");
    },

    
    asUCString : function(s) {
        return String(s).toUpperCase();
    },

    
    asDate : function(s) {
        if(!s){
            return 0;
        }
        if(Ext.isDate(s)){
            return s.getTime();
        }
        return Date.parse(String(s));
    },

    
    asFloat : function(s) {
        var val = parseFloat(String(s).replace(/,/g, ""));
        return isNaN(val) ? 0 : val;
    },

    
    asInt : function(s) {
        var val = parseInt(String(s).replace(/,/g, ""), 10);
        return isNaN(val) ? 0 : val;
    }
});

Ext.define('Ext.data.Types', {
    singleton: true,
    requires: ['Ext.data.SortTypes']
}, function() {
    var st = Ext.data.SortTypes;

    Ext.apply(Ext.data.Types, {
        
        stripRe: /[\$,%]/g,

        
        AUTO: {
            sortType: st.none,
            type: 'auto'
        },

        
        STRING: {
            convert: function(v) {
                var defaultValue = this.useNull ? null : '';
                return (v === undefined || v === null) ? defaultValue : String(v);
            },
            sortType: st.asUCString,
            type: 'string'
        },

        
        INT: {
            convert: function(v) {
                return v !== undefined && v !== null && v !== '' ?
                    parseInt(String(v).replace(Ext.data.Types.stripRe, ''), 10) : (this.useNull ? null : 0);
            },
            sortType: st.none,
            type: 'int'
        },

        
        FLOAT: {
            convert: function(v) {
                return v !== undefined && v !== null && v !== '' ?
                    parseFloat(String(v).replace(Ext.data.Types.stripRe, ''), 10) : (this.useNull ? null : 0);
            },
            sortType: st.none,
            type: 'float'
        },

        
        BOOL: {
            convert: function(v) {
                if (this.useNull && (v === undefined || v === null || v === '')) {
                    return null;
                }
                return v === true || v === 'true' || v == 1;
            },
            sortType: st.none,
            type: 'bool'
        },

        
        DATE: {
            convert: function(v) {
                var df = this.dateFormat,
                    parsed;

                if (!v) {
                    return null;
                }
                if (Ext.isDate(v)) {
                    return v;
                }
                if (df) {
                    if (df == 'timestamp') {
                        return new Date(v*1000);
                    }
                    if (df == 'time') {
                        return new Date(parseInt(v, 10));
                    }
                    return Ext.Date.parse(v, df);
                }

                parsed = Date.parse(v);
                return parsed ? new Date(parsed) : null;
            },
            sortType: st.asDate,
            type: 'date'
        }
    });

    Ext.apply(Ext.data.Types, {
        
        BOOLEAN: this.BOOL,

        
        INTEGER: this.INT,

        
        NUMBER: this.FLOAT
    });
});


Ext.define('Ext.data.UuidGenerator', (function () {
    var twoPow14 = Math.pow(2, 14),
        twoPow16 = Math.pow(2, 16),
        twoPow28 = Math.pow(2, 28),
        twoPow32 = Math.pow(2, 32);

    function toHex (value, length) {
        var ret = value.toString(16);
        if (ret.length > length) {
            ret = ret.substring(ret.length - length); 
        } else if (ret.length < length) {
            ret = Ext.String.leftPad(ret, length, '0');
        }
        return ret;
    }

    function rand (lo, hi) {
        var v = Math.random() * (hi - lo + 1);
        return Math.floor(v) + lo;
    }

    function split (bignum) {
        if (typeof(bignum) == 'number') {
            var hi = Math.floor(bignum / twoPow32);
            return {
                lo: Math.floor(bignum - hi * twoPow32),
                hi: hi
            };
        }
        return bignum;
    }

    return {
        extend: 'Ext.data.IdGenerator',

        alias: 'idgen.uuid',

        id: 'uuid', 

        

        

        
        version: 4,

        constructor: function() {
            var me = this;

            me.callParent(arguments);

            me.parts = [];
            me.init();
        },

        generate: function () {
            var me = this,
                parts = me.parts,
                ts = me.timestamp;

            
            parts[0] = toHex(ts.lo, 8);
            parts[1] = toHex(ts.hi & 0xFFFF, 4);
            parts[2] = toHex(((ts.hi >>> 16) & 0xFFF) | (me.version << 12), 4);
            parts[3] = toHex(0x80 | ((me.clockSeq >>> 8) & 0x3F), 2) +
                       toHex(me.clockSeq & 0xFF, 2);
            parts[4] = toHex(me.salt.hi, 4) + toHex(me.salt.lo, 8);

            if (me.version == 4) {
                me.init(); 
            } else {
                
                ++ts.lo;
                if (ts.lo >= twoPow32) { 
                    ts.lo = 0;
                    ++ts.hi;
                }
            }

            return parts.join('-').toLowerCase();
        },

        getRecId: function (rec) {
            return rec.getId();
        },

        
        init: function () {
            var me = this,
                salt, time;

            if (me.version == 4) {
                
                
                
                
                me.clockSeq = rand(0, twoPow14-1);

                
                salt = me.salt || (me.salt = {});
                time = me.timestamp || (me.timestamp = {});

                
                salt.lo = rand(0, twoPow32-1);
                salt.hi = rand(0, twoPow16-1);
                time.lo = rand(0, twoPow32-1);
                time.hi = rand(0, twoPow28-1);
            } else {
                
                me.salt = split(me.salt);
                me.timestamp = split(me.timestamp);

                
                
                me.salt.hi |= 0x100;
            }
        },

        
        reconfigure: function (config) {
            Ext.apply(this, config);
            this.init();
        }
    };
}()));


Ext.define('Ext.data.validations', {
    singleton: true,
    
    
    presenceMessage: 'must be present',
    
    
    lengthMessage: 'is the wrong length',
    
    
    formatMessage: 'is the wrong format',
    
    
    inclusionMessage: 'is not included in the list of acceptable values',
    
    
    exclusionMessage: 'is not an acceptable value',
    
    
    emailMessage: 'is not a valid email address',
    
    
    emailRe: /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,
    
    
    presence: function(config, value) {
        
        if (arguments.length === 1) {
            value = config;
        }
        
        
        return !!value || value === 0;
    },
    
    
    length: function(config, value) {
        if (value === undefined || value === null) {
            return false;
        }
        
        var length = value.length,
            min    = config.min,
            max    = config.max;
        
        if ((min && length < min) || (max && length > max)) {
            return false;
        } else {
            return true;
        }
    },
    
    
    email: function(config, email) {
        return Ext.data.validations.emailRe.test(email);
    },
    
    
    format: function(config, value) {
        return !!(config.matcher && config.matcher.test(value));
    },
    
    
    inclusion: function(config, value) {
        return config.list && Ext.Array.indexOf(config.list,value) != -1;
    },
    
    
    exclusion: function(config, value) {
        return config.list && Ext.Array.indexOf(config.list,value) == -1;
    }
});

Ext.define('Ext.data.association.Association', {
    alternateClassName: 'Ext.data.Association',
    

    

    

    
    primaryKey: 'id',

    
    
    

    defaultReaderType: 'json',

    isAssociation: true,

    initialConfig: null,

    statics: {
        AUTO_ID: 1000,
        
        create: function(association){
            if (Ext.isString(association)) {
                association = {
                    type: association
                };
            }

            switch (association.type) {
                case 'belongsTo':
                    return new Ext.data.association.BelongsTo(association);
                case 'hasMany':
                    return new Ext.data.association.HasMany(association);
                case 'hasOne':
                    return new Ext.data.association.HasOne(association);
                


                default:
            }
            return association;
        }
    },

    
    constructor: function(config) {
        Ext.apply(this, config);

        var me = this,
            types           = Ext.ModelManager.types,
            ownerName       = config.ownerModel,
            associatedName  = config.associatedModel,
            ownerModel      = types[ownerName],
            associatedModel = types[associatedName];

        me.initialConfig = config;


        me.ownerModel = ownerModel;
        me.associatedModel = associatedModel;

        

        

        Ext.applyIf(me, {
            ownerName : ownerName,
            associatedName: associatedName
        });
        
        me.associationId = 'association' + (++me.statics().AUTO_ID);
    },

    
    getReader: function(){
        var me = this,
            reader = me.reader,
            model = me.associatedModel;

        if (reader) {
            if (Ext.isString(reader)) {
                reader = {
                    type: reader
                };
            }
            if (reader.isReader) {
                reader.setModel(model);
            } else {
                Ext.applyIf(reader, {
                    model: model,
                    type : me.defaultReaderType
                });
            }
            me.reader = Ext.createByAlias('reader.' + reader.type, reader);
        }
        return me.reader || null;
    }
});


Ext.define('Ext.data.association.BelongsTo', {
    extend: 'Ext.data.association.Association',
    alternateClassName: 'Ext.data.BelongsToAssociation',
    alias: 'association.belongsto',

    

    

    

    
    constructor: function(config) {
        this.callParent(arguments);

        var me             = this,
            ownerProto     = me.ownerModel.prototype,
            associatedName = me.associatedName,
            getterName     = me.getterName || 'get' + associatedName,
            setterName     = me.setterName || 'set' + associatedName;

        Ext.applyIf(me, {
            name        : associatedName,
            foreignKey  : associatedName.toLowerCase() + "_id",
            instanceName: associatedName + 'BelongsToInstance',
            associationKey: associatedName.toLowerCase()
        });

        ownerProto[getterName] = me.createGetter();
        ownerProto[setterName] = me.createSetter();
    },

    
    createSetter: function() {
        var me = this,
            foreignKey = me.foreignKey;

        
        return function(value, options, scope) {
            
            if (value && value.isModel) {
                value = value.getId();
            }
            this.set(foreignKey, value);

            if (Ext.isFunction(options)) {
                options = {
                    callback: options,
                    scope: scope || this
                };
            }

            if (Ext.isObject(options)) {
                return this.save(options);
            }
        };
    },

    
    createGetter: function() {
        var me              = this,
            associatedName  = me.associatedName,
            associatedModel = me.associatedModel,
            foreignKey      = me.foreignKey,
            primaryKey      = me.primaryKey,
            instanceName    = me.instanceName;

        
        return function(options, scope) {
            options = options || {};

            var model = this,
                foreignKeyId = model.get(foreignKey),
                success,
                instance,
                args;

            if (options.reload === true || model[instanceName] === undefined) {
                instance = Ext.ModelManager.create({}, associatedName);
                instance.set(primaryKey, foreignKeyId);

                if (typeof options == 'function') {
                    options = {
                        callback: options,
                        scope: scope || model
                    };
                }
                
                
                success = options.success;
                options.success = function(rec){
                    model[instanceName] = rec;
                    if (success) {
                        success.apply(this, arguments);
                    }
                };

                associatedModel.load(foreignKeyId, options);
                
                model[instanceName] = instance;
                return instance;
            } else {
                instance = model[instanceName];
                args = [instance];
                scope = scope || options.scope || model;

                
                
                
                Ext.callback(options, scope, args);
                Ext.callback(options.success, scope, args);
                Ext.callback(options.failure, scope, args);
                Ext.callback(options.callback, scope, args);

                return instance;
            }
        };
    },

    
    read: function(record, reader, associationData){
        record[this.instanceName] = reader.read([associationData]).records[0];
    }
});


Ext.define('Ext.data.association.HasOne', {
    extend: 'Ext.data.association.Association',
    alternateClassName: 'Ext.data.HasOneAssociation',

    alias: 'association.hasone',
    
    

    

    

    
    
    constructor: function(config) {
        this.callParent(arguments);

        var me             = this,
            ownerProto     = me.ownerModel.prototype,
            associatedName = me.associatedName,
            getterName     = me.getterName || 'get' + associatedName,
            setterName     = me.setterName || 'set' + associatedName;

        Ext.applyIf(me, {
            name        : associatedName,
            foreignKey  : associatedName.toLowerCase() + "_id",
            instanceName: associatedName + 'HasOneInstance',
            associationKey: associatedName.toLowerCase()
        });

        ownerProto[getterName] = me.createGetter();
        ownerProto[setterName] = me.createSetter();
    },
    
    
    createSetter: function() {
        var me              = this,
            ownerModel      = me.ownerModel,
            foreignKey      = me.foreignKey;

        
        return function(value, options, scope) {
            if (value && value.isModel) {
                value = value.getId();
            }
            
            this.set(foreignKey, value);

            if (Ext.isFunction(options)) {
                options = {
                    callback: options,
                    scope: scope || this
                };
            }

            if (Ext.isObject(options)) {
                return this.save(options);
            }
        };
    },

    
    createGetter: function() {
        var me              = this,
            ownerModel      = me.ownerModel,
            associatedName  = me.associatedName,
            associatedModel = me.associatedModel,
            foreignKey      = me.foreignKey,
            primaryKey      = me.primaryKey,
            instanceName    = me.instanceName;

        
        return function(options, scope) {
            options = options || {};

            var model = this,
                foreignKeyId = model.get(foreignKey),
                success,
                instance,
                args;

            if (options.reload === true || model[instanceName] === undefined) {
                instance = Ext.ModelManager.create({}, associatedName);
                instance.set(primaryKey, foreignKeyId);

                if (typeof options == 'function') {
                    options = {
                        callback: options,
                        scope: scope || model
                    };
                }
                
                
                success = options.success;
                options.success = function(rec){
                    model[instanceName] = rec;
                    if (success) {
                        success.apply(this, arguments);
                    }
                };

                associatedModel.load(foreignKeyId, options);
                
                model[instanceName] = instance;
                return instance;
            } else {
                instance = model[instanceName];
                args = [instance];
                scope = scope || options.scope || model;

                
                
                
                Ext.callback(options, scope, args);
                Ext.callback(options.success, scope, args);
                Ext.callback(options.failure, scope, args);
                Ext.callback(options.callback, scope, args);

                return instance;
            }
        };
    },
    
    
    read: function(record, reader, associationData){
        var inverse = this.associatedModel.prototype.associations.findBy(function(assoc){
            return assoc.type === 'belongsTo' && assoc.associatedName === record.$className;
        }), newRecord = reader.read([associationData]).records[0];
        
        record[this.instanceName] = newRecord;
    
        
        if (inverse) {
            newRecord[inverse.instanceName] = record;
        }
    }
});

Ext.define('Ext.data.writer.Writer', {
    alias: 'writer.base',
    alternateClassName: ['Ext.data.DataWriter', 'Ext.data.Writer'],
    
    
    writeAllFields: true,
    
    
    nameProperty: 'name',

    
    isWriter: true,

    
    constructor: function(config) {
        Ext.apply(this, config);
    },

    
    write: function(request) {
        var operation = request.operation,
            records   = operation.records || [],
            len       = records.length,
            i         = 0,
            data      = [];

        for (; i < len; i++) {
            data.push(this.getRecordData(records[i], operation));
        }
        return this.writeRecords(request, data);
    },

    
    getRecordData: function(record, operation) {
        var isPhantom = record.phantom === true,
            writeAll = this.writeAllFields || isPhantom,
            nameProperty = this.nameProperty,
            fields = record.fields,
            fieldItems = fields.items,
            data = {},
            clientIdProperty = record.clientIdProperty,
            changes,
            name,
            field,
            key,
            value,
            f, fLen;

        if (writeAll) {
            fLen = fieldItems.length;

            for (f = 0; f < fLen; f++) {
                field = fieldItems[f];
                if (field.persist) {
                    name = field[nameProperty] || field.name;
                    value = record.get(field.name);
                    if (field.serialize) {
                        data[name] = field.serialize(value, record);
                    } else if (field.type === Ext.data.Types.DATE && field.dateFormat) {
                        data[name] = Ext.Date.format(value, field.dateFormat);
                    } else {
                        data[name] = value;
                    }
                }
            }
        } else {
            
            changes = record.getChanges();
            for (key in changes) {
                if (changes.hasOwnProperty(key)) {
                    field = fields.get(key);
                    if (field.persist) {
                        name = field[nameProperty] || field.name;
                        value = record.get(field.name);
                        if (field.serialize) {
                            data[name] = field.serialize(value, record);
                        } else if (field.type === Ext.data.Types.DATE && field.dateFormat) {
                            data[name] = Ext.Date.format(value, field.dateFormat);
                        } else {
                            data[name] = value;
                        }
                    }
                }
            }
        }
        if (isPhantom) {
            if (clientIdProperty && operation && operation.records.length > 1) {
                
                
                data[clientIdProperty] = record.internalId;
            }
        } else {
            
            data[record.idProperty] = record.getId();
        }

        return data;
    }
});


Ext.define('Ext.data.writer.Xml', {
    
    
    
    extend: 'Ext.data.writer.Writer',
    alternateClassName: 'Ext.data.XmlWriter',
    
    alias: 'writer.xml',
    
    
    
    
    documentRoot: 'xmlData',
    
    
    defaultDocumentRoot: 'xmlData',

    
    header: '',

    
    record: 'record',

    
    writeRecords: function(request, data) {
        var me = this,
            xml = [],
            i = 0,
            len = data.length,
            root = me.documentRoot,
            record = me.record,
            needsRoot = data.length !== 1,
            item,
            key;
            
        
        xml.push(me.header || '');
        
        if (!root && needsRoot) {
            root = me.defaultDocumentRoot;
        }
        
        if (root) {
            xml.push('<', root, '>');
        }
            
        for (; i < len; ++i) {
            item = data[i];
            xml.push('<', record, '>');
            for (key in item) {
                if (item.hasOwnProperty(key)) {
                    xml.push('<', key, '>', item[key], '</', key, '>');
                }
            }
            xml.push('</', record, '>');
        }
        
        if (root) {
            xml.push('</', root, '>');
        }
            
        request.xmlData = xml.join('');
        return request;
    }
});


Ext.define('Ext.direct.RemotingMethod', {

    constructor: function(config){
        var me = this,
            params = Ext.isDefined(config.params) ? config.params : config.len,
            name, pLen, p, param;

        me.name = config.name;
        me.formHandler = config.formHandler;
        if (Ext.isNumber(params)) {
            
            me.len = params;
            me.ordered = true;
        } else {
            
            me.params = [];
			pLen = params.length;
            for (p = 0; p < pLen; p++) {
                param = params[p];
                name  = Ext.isObject(param) ? param.name : param;
                me.params.push(name);
            }
        }
    },
    
    getArgs: function(params, paramOrder, paramsAsHash){
        var args = [],
            i,
            len;
        
        if (this.ordered) {
            if (this.len > 0) {
                
                if (paramOrder) {
                    for (i = 0, len = paramOrder.length; i < len; i++) {
                        args.push(params[paramOrder[i]]);
                    }
                } else if (paramsAsHash) {
                    
                    args.push(params);
                }
            }
        } else {
            args.push(params);
        } 
        
        return args;
    },

    
    getCallData: function(args){
        var me = this,
            data = null,
            len  = me.len,
            params = me.params,
            callback,
            scope,
            name;

        if (me.ordered) {
            callback = args[len];
            scope = args[len + 1];
            if (len !== 0) {
                data = args.slice(0, len);
            }
        } else {
            data = Ext.apply({}, args[0]);
            callback = args[1];
            scope = args[2];

            
            for (name in data) {
                if (data.hasOwnProperty(name)) {
                    if (!Ext.Array.contains(params, name)) {
                        delete data[name];
                    }
                }
            }
        }

        return {
            data: data,
            callback: callback,
            scope: scope
        };
    }
});


Ext.define('Ext.direct.Transaction', {
    
    
   
    alias: 'direct.transaction',
    alternateClassName: 'Ext.Direct.Transaction',
   
    statics: {
        TRANSACTION_ID: 0
    },
   
    

    
    constructor: function(config){
        var me = this;
        
        Ext.apply(me, config);
        me.id = me.tid = ++me.self.TRANSACTION_ID;
        me.retryCount = 0;
    },
   
    send: function(){
         this.provider.queueTransaction(this);
    },

    retry: function(){
        this.retryCount++;
        this.send();
    },

    getProvider: function(){
        return this.provider;
    }
});


Ext.define('Ext.draw.Color', {

    

    

    colorToHexRe: /(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
    rgbRe: /\s*rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)\s*/,
    hexRe: /\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,

    
    lightnessFactor: 0.2,

    
    constructor : function(red, green, blue) {
        var me = this,
            clamp = Ext.Number.constrain;
        me.r = clamp(red, 0, 255);
        me.g = clamp(green, 0, 255);
        me.b = clamp(blue, 0, 255);
    },

    
    getRed: function() {
        return this.r;
    },

    
    getGreen: function() {
        return this.g;
    },

    
    getBlue: function() {
        return this.b;
    },

    
    getRGB: function() {
        var me = this;
        return [me.r, me.g, me.b];
    },

    
    getHSL: function() {
        var me = this,
            r = me.r / 255,
            g = me.g / 255,
            b = me.b / 255,
            max = Math.max(r, g, b),
            min = Math.min(r, g, b),
            delta = max - min,
            h,
            s = 0,
            l = 0.5 * (max + min);

        
        if (min != max) {
            s = (l < 0.5) ? delta / (max + min) : delta / (2 - max - min);
            if (r == max) {
                h = 60 * (g - b) / delta;
            } else if (g == max) {
                h = 120 + 60 * (b - r) / delta;
            } else {
                h = 240 + 60 * (r - g) / delta;
            }
            if (h < 0) {
                h += 360;
            }
            if (h >= 360) {
                h -= 360;
            }
        }
        return [h, s, l];
    },

    
    getLighter: function(factor) {
        var hsl = this.getHSL();
        factor = factor || this.lightnessFactor;
        hsl[2] = Ext.Number.constrain(hsl[2] + factor, 0, 1);
        return this.fromHSL(hsl[0], hsl[1], hsl[2]);
    },

    
    getDarker: function(factor) {
        factor = factor || this.lightnessFactor;
        return this.getLighter(-factor);
    },

    
    toString: function() {
        var me = this,
            round = Math.round,
            r = round(me.r).toString(16),
            g = round(me.g).toString(16),
            b = round(me.b).toString(16);
        r = (r.length == 1) ? '0' + r : r;
        g = (g.length == 1) ? '0' + g : g;
        b = (b.length == 1) ? '0' + b : b;
        return ['#', r, g, b].join('');
    },

    
    toHex: function(color) {
        if (Ext.isArray(color)) {
            color = color[0];
        }
        if (!Ext.isString(color)) {
            return '';
        }
        if (color.substr(0, 1) === '#') {
            return color;
        }
        var digits = this.colorToHexRe.exec(color),
            red,
            green,
            blue,
            rgb;

        if (Ext.isArray(digits)) {
            red = parseInt(digits[2], 10);
            green = parseInt(digits[3], 10);
            blue = parseInt(digits[4], 10);
            rgb = blue | (green << 8) | (red << 16);
            return digits[1] + '#' + ("000000" + rgb.toString(16)).slice(-6);
        }
        else {
            return color;
        }
    },

    
    fromString: function(str) {
        var values, r, g, b,
            parse = parseInt;

        if ((str.length == 4 || str.length == 7) && str.substr(0, 1) === '#') {
            values = str.match(this.hexRe);
            if (values) {
                r = parse(values[1], 16) >> 0;
                g = parse(values[2], 16) >> 0;
                b = parse(values[3], 16) >> 0;
                if (str.length == 4) {
                    r += (r * 16);
                    g += (g * 16);
                    b += (b * 16);
                }
            }
        }
        else {
            values = str.match(this.rgbRe);
            if (values) {
                r = values[1];
                g = values[2];
                b = values[3];
            }
        }

        return (typeof r == 'undefined') ? undefined : new Ext.draw.Color(r, g, b);
    },

    
    getGrayscale: function() {
        
        return this.r * 0.3 + this.g * 0.59 + this.b * 0.11;
    },

    
    fromHSL: function(h, s, l) {
        var C, X, m, i, rgb = [],
            abs = Math.abs,
            floor = Math.floor;

        if (s == 0 || h == null) {
            
            rgb = [l, l, l];
        }
        else {
            
            
            
            
            h /= 60;
            C = s * (1 - abs(2 * l - 1));
            X = C * (1 - abs(h - 2 * floor(h / 2) - 1));
            m = l - C / 2;
            switch (floor(h)) {
                case 0:
                    rgb = [C, X, 0];
                    break;
                case 1:
                    rgb = [X, C, 0];
                    break;
                case 2:
                    rgb = [0, C, X];
                    break;
                case 3:
                    rgb = [0, X, C];
                    break;
                case 4:
                    rgb = [X, 0, C];
                    break;
                case 5:
                    rgb = [C, 0, X];
                    break;
            }
            rgb = [rgb[0] + m, rgb[1] + m, rgb[2] + m];
        }
        return new Ext.draw.Color(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
    }
}, function() {
    var prototype = this.prototype;

    
    this.addStatics({
        fromHSL: function() {
            return prototype.fromHSL.apply(prototype, arguments);
        },
        fromString: function() {
            return prototype.fromString.apply(prototype, arguments);
        },
        toHex: function() {
            return prototype.toHex.apply(prototype, arguments);
        }
    });
});


Ext.define('Ext.draw.Draw', {
    

    singleton: true,

    requires: ['Ext.draw.Color'],

    

    pathToStringRE: /,?([achlmqrstvxz]),?/gi,
    pathCommandRE: /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,
    pathValuesRE: /(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig,
    stopsRE: /^(\d+%?)$/,
    radian: Math.PI / 180,

    availableAnimAttrs: {
        along: "along",
        blur: null,
        "clip-rect": "csv",
        cx: null,
        cy: null,
        fill: "color",
        "fill-opacity": null,
        "font-size": null,
        height: null,
        opacity: null,
        path: "path",
        r: null,
        rotation: "csv",
        rx: null,
        ry: null,
        scale: "csv",
        stroke: "color",
        "stroke-opacity": null,
        "stroke-width": null,
        translation: "csv",
        width: null,
        x: null,
        y: null
    },

    is: function(o, type) {
        type = String(type).toLowerCase();
        return (type == "object" && o === Object(o)) ||
            (type == "undefined" && typeof o == type) ||
            (type == "null" && o === null) ||
            (type == "array" && Array.isArray && Array.isArray(o)) ||
            (Object.prototype.toString.call(o).toLowerCase().slice(8, -1)) == type;
    },

    ellipsePath: function(sprite) {
        var attr = sprite.attr;
        return Ext.String.format("M{0},{1}A{2},{3},0,1,1,{0},{4}A{2},{3},0,1,1,{0},{1}z", attr.x, attr.y - attr.ry, attr.rx, attr.ry, attr.y + attr.ry);
    },

    rectPath: function(sprite) {
        var attr = sprite.attr;
        if (attr.radius) {
            return Ext.String.format("M{0},{1}l{2},0a{3},{3},0,0,1,{3},{3}l0,{5}a{3},{3},0,0,1,{4},{3}l{6},0a{3},{3},0,0,1,{4},{4}l0,{7}a{3},{3},0,0,1,{3},{4}z", attr.x + attr.radius, attr.y, attr.width - attr.radius * 2, attr.radius, -attr.radius, attr.height - attr.radius * 2, attr.radius * 2 - attr.width, attr.radius * 2 - attr.height);
        }
        else {
            return Ext.String.format("M{0},{1}L{2},{1},{2},{3},{0},{3}z", attr.x, attr.y, attr.width + attr.x, attr.height + attr.y);
        }
    },

    
    path2string: function () {
        return this.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1");
    },

    
    pathToString: function(arrayPath) {
        return arrayPath.join(",").replace(Ext.draw.Draw.pathToStringRE, "$1");
    },

    parsePathString: function (pathString) {
        if (!pathString) {
            return null;
        }
        var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0},
            data = [],
            me = this;
        if (me.is(pathString, "array") && me.is(pathString[0], "array")) { 
            data = me.pathClone(pathString);
        }
        if (!data.length) {
            String(pathString).replace(me.pathCommandRE, function (a, b, c) {
                var params = [],
                    name = b.toLowerCase();
                c.replace(me.pathValuesRE, function (a, b) {
                    b && params.push(+b);
                });
                if (name == "m" && params.length > 2) {
                    data.push([b].concat(Ext.Array.splice(params, 0, 2)));
                    name = "l";
                    b = (b == "m") ? "l" : "L";
                }
                while (params.length >= paramCounts[name]) {
                    data.push([b].concat(Ext.Array.splice(params, 0, paramCounts[name])));
                    if (!paramCounts[name]) {
                        break;
                    }
                }
            });
        }
        data.toString = me.path2string;
        return data;
    },

    mapPath: function (path, matrix) {
        if (!matrix) {
            return path;
        }
        var x, y, i, ii, j, jj, pathi;
        path = this.path2curve(path);
        for (i = 0, ii = path.length; i < ii; i++) {
            pathi = path[i];
            for (j = 1, jj = pathi.length; j < jj-1; j += 2) {
                x = matrix.x(pathi[j], pathi[j + 1]);
                y = matrix.y(pathi[j], pathi[j + 1]);
                pathi[j] = x;
                pathi[j + 1] = y;
            }
        }
        return path;
    },

    pathClone: function(pathArray) {
        var res = [],
            j, jj, i, ii;
        if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { 
            pathArray = this.parsePathString(pathArray);
        }
        for (i = 0, ii = pathArray.length; i < ii; i++) {
            res[i] = [];
            for (j = 0, jj = pathArray[i].length; j < jj; j++) {
                res[i][j] = pathArray[i][j];
            }
        }
        res.toString = this.path2string;
        return res;
    },

    pathToAbsolute: function (pathArray) {
        if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { 
            pathArray = this.parsePathString(pathArray);
        }
        var res = [],
            x = 0,
            y = 0,
            mx = 0,
            my = 0,
            i = 0,
            ln = pathArray.length,
            r, pathSegment, j, ln2;
        
        if (ln && pathArray[0][0] == "M") {
            x = +pathArray[0][1];
            y = +pathArray[0][2];
            mx = x;
            my = y;
            i++;
            res[0] = ["M", x, y];
        }
        for (; i < ln; i++) {
            r = res[i] = [];
            pathSegment = pathArray[i];
            if (pathSegment[0] != pathSegment[0].toUpperCase()) {
                r[0] = pathSegment[0].toUpperCase();
                switch (r[0]) {
                    
                    case "A":
                        r[1] = pathSegment[1];
                        r[2] = pathSegment[2];
                        r[3] = pathSegment[3];
                        r[4] = pathSegment[4];
                        r[5] = pathSegment[5];
                        r[6] = +(pathSegment[6] + x);
                        r[7] = +(pathSegment[7] + y);
                        break;
                    
                    case "V":
                        r[1] = +pathSegment[1] + y;
                        break;
                    
                    case "H":
                        r[1] = +pathSegment[1] + x;
                        break;
                    case "M":
                    
                        mx = +pathSegment[1] + x;
                        my = +pathSegment[2] + y;
                    default:
                        j = 1;
                        ln2 = pathSegment.length;
                        for (; j < ln2; j++) {
                            r[j] = +pathSegment[j] + ((j % 2) ? x : y);
                        }
                }
            }
            else {
                j = 0;
                ln2 = pathSegment.length;
                for (; j < ln2; j++) {
                    res[i][j] = pathSegment[j];
                }
            }
            switch (r[0]) {
                
                case "Z":
                    x = mx;
                    y = my;
                    break;
                
                case "H":
                    x = r[1];
                    break;
                
                case "V":
                    y = r[1];
                    break;
                
                case "M":
                    pathSegment = res[i];
                    ln2 = pathSegment.length;
                    mx = pathSegment[ln2 - 2];
                    my = pathSegment[ln2 - 1];
                default:
                    pathSegment = res[i];
                    ln2 = pathSegment.length;
                    x = pathSegment[ln2 - 2];
                    y = pathSegment[ln2 - 1];
            }
        }
        res.toString = this.path2string;
        return res;
    },

    
    pathToRelative: function (pathArray) {
        if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) {
            pathArray = this.parsePathString(pathArray);
        }
        var res = [],
            x = 0,
            y = 0,
            mx = 0,
            my = 0,
            start = 0,
            r,
            pa,
            i,
            j,
            k,
            len,
            ii,
            jj,
            kk;
        
        if (pathArray[0][0] == "M") {
            x = pathArray[0][1];
            y = pathArray[0][2];
            mx = x;
            my = y;
            start++;
            res.push(["M", x, y]);
        }
        for (i = start, ii = pathArray.length; i < ii; i++) {
            r = res[i] = [];
            pa = pathArray[i];
            if (pa[0] != pa[0].toLowerCase()) {
                r[0] = pa[0].toLowerCase();
                switch (r[0]) {
                    case "a":
                        r[1] = pa[1];
                        r[2] = pa[2];
                        r[3] = pa[3];
                        r[4] = pa[4];
                        r[5] = pa[5];
                        r[6] = +(pa[6] - x).toFixed(3);
                        r[7] = +(pa[7] - y).toFixed(3);
                        break;
                    case "v":
                        r[1] = +(pa[1] - y).toFixed(3);
                        break;
                    case "m":
                        mx = pa[1];
                        my = pa[2];
                    default:
                        for (j = 1, jj = pa.length; j < jj; j++) {
                            r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
                        }
                }
            } else {
                r = res[i] = [];
                if (pa[0] == "m") {
                    mx = pa[1] + x;
                    my = pa[2] + y;
                }
                for (k = 0, kk = pa.length; k < kk; k++) {
                    res[i][k] = pa[k];
                }
            }
            len = res[i].length;
            switch (res[i][0]) {
                case "z":
                    x = mx;
                    y = my;
                    break;
                case "h":
                    x += +res[i][len - 1];
                    break;
                case "v":
                    y += +res[i][len - 1];
                    break;
                default:
                    x += +res[i][len - 2];
                    y += +res[i][len - 1];
            }
        }
        res.toString = this.path2string;
        return res;
    },

    
    path2curve: function (path) {
        var me = this,
            points = me.pathToAbsolute(path),
            ln = points.length,
            attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
            i, seg, segLn, point;
            
        for (i = 0; i < ln; i++) {
            points[i] = me.command2curve(points[i], attrs);
            if (points[i].length > 7) {
                    points[i].shift();
                    point = points[i];
                    while (point.length) {
                        Ext.Array.splice(points, i++, 0, ["C"].concat(Ext.Array.splice(point, 0, 6)));
                    }
                    Ext.Array.erase(points, i, 1);
                    ln = points.length;
                    i--;
                }
            seg = points[i];
            segLn = seg.length;
            attrs.x = seg[segLn - 2];
            attrs.y = seg[segLn - 1];
            attrs.bx = parseFloat(seg[segLn - 4]) || attrs.x;
            attrs.by = parseFloat(seg[segLn - 3]) || attrs.y;
        }
        return points;
    },
    
    interpolatePaths: function (path, path2) {
        var me = this,
            p = me.pathToAbsolute(path),
            p2 = me.pathToAbsolute(path2),
            attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
            attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
            fixArc = function (pp, i) {
                if (pp[i].length > 7) {
                    pp[i].shift();
                    var pi = pp[i];
                    while (pi.length) {
                        Ext.Array.splice(pp, i++, 0, ["C"].concat(Ext.Array.splice(pi, 0, 6)));
                    }
                    Ext.Array.erase(pp, i, 1);
                    ii = Math.max(p.length, p2.length || 0);
                }
            },
            fixM = function (path1, path2, a1, a2, i) {
                if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
                    Ext.Array.splice(path2, i, 0, ["M", a2.x, a2.y]);
                    a1.bx = 0;
                    a1.by = 0;
                    a1.x = path1[i][1];
                    a1.y = path1[i][2];
                    ii = Math.max(p.length, p2.length || 0);
                }
            },
            i, ii,
            seg, seg2, seglen, seg2len;
        for (i = 0, ii = Math.max(p.length, p2.length || 0); i < ii; i++) {
            p[i] = me.command2curve(p[i], attrs);
            fixArc(p, i);
            (p2[i] = me.command2curve(p2[i], attrs2));
            fixArc(p2, i);
            fixM(p, p2, attrs, attrs2, i);
            fixM(p2, p, attrs2, attrs, i);
            seg = p[i];
            seg2 = p2[i];
            seglen = seg.length;
            seg2len = seg2.length;
            attrs.x = seg[seglen - 2];
            attrs.y = seg[seglen - 1];
            attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;
            attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;
            attrs2.bx = (parseFloat(seg2[seg2len - 4]) || attrs2.x);
            attrs2.by = (parseFloat(seg2[seg2len - 3]) || attrs2.y);
            attrs2.x = seg2[seg2len - 2];
            attrs2.y = seg2[seg2len - 1];
        }
        return [p, p2];
    },
    
    
    command2curve: function (pathCommand, d) {
        var me = this;
        if (!pathCommand) {
            return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
        }
        if (pathCommand[0] != "T" && pathCommand[0] != "Q") {
            d.qx = d.qy = null;
        }
        switch (pathCommand[0]) {
            case "M":
                d.X = pathCommand[1];
                d.Y = pathCommand[2];
                break;
            case "A":
                pathCommand = ["C"].concat(me.arc2curve.apply(me, [d.x, d.y].concat(pathCommand.slice(1))));
                break;
            case "S":
                pathCommand = ["C", d.x + (d.x - (d.bx || d.x)), d.y + (d.y - (d.by || d.y))].concat(pathCommand.slice(1));
                break;
            case "T":
                d.qx = d.x + (d.x - (d.qx || d.x));
                d.qy = d.y + (d.y - (d.qy || d.y));
                pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, d.qx, d.qy, pathCommand[1], pathCommand[2]));
                break;
            case "Q":
                d.qx = pathCommand[1];
                d.qy = pathCommand[2];
                pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[3], pathCommand[4]));
                break;
            case "L":
                pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[1], pathCommand[2]);
                break;
            case "H":
                pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], d.y, pathCommand[1], d.y);
                break;
            case "V":
                pathCommand = ["C"].concat(d.x, d.y, d.x, pathCommand[1], d.x, pathCommand[1]);
                break;
            case "Z":
                pathCommand = ["C"].concat(d.x, d.y, d.X, d.Y, d.X, d.Y);
                break;
        }
        return pathCommand;
    },

    quadratic2curve: function (x1, y1, ax, ay, x2, y2) {
        var _13 = 1 / 3,
            _23 = 2 / 3;
        return [
                _13 * x1 + _23 * ax,
                _13 * y1 + _23 * ay,
                _13 * x2 + _23 * ax,
                _13 * y2 + _23 * ay,
                x2,
                y2
            ];
    },
    
    rotate: function (x, y, rad) {
        var cos = Math.cos(rad),
            sin = Math.sin(rad),
            X = x * cos - y * sin,
            Y = x * sin + y * cos;
        return {x: X, y: Y};
    },

    arc2curve: function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
        
        
        var me = this,
            PI = Math.PI,
            radian = me.radian,
            _120 = PI * 120 / 180,
            rad = radian * (+angle || 0),
            res = [],
            math = Math,
            mcos = math.cos,
            msin = math.sin,
            msqrt = math.sqrt,
            mabs = math.abs,
            masin = math.asin,
            xy, cos, sin, x, y, h, rx2, ry2, k, cx, cy, f1, f2, df, c1, s1, c2, s2,
            t, hx, hy, m1, m2, m3, m4, newres, i, ln, f2old, x2old, y2old;
        if (!recursive) {
            xy = me.rotate(x1, y1, -rad);
            x1 = xy.x;
            y1 = xy.y;
            xy = me.rotate(x2, y2, -rad);
            x2 = xy.x;
            y2 = xy.y;
            cos = mcos(radian * angle);
            sin = msin(radian * angle);
            x = (x1 - x2) / 2;
            y = (y1 - y2) / 2;
            h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
            if (h > 1) {
                h = msqrt(h);
                rx = h * rx;
                ry = h * ry;
            }
            rx2 = rx * rx;
            ry2 = ry * ry;
            k = (large_arc_flag == sweep_flag ? -1 : 1) *
                    msqrt(mabs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));
            cx = k * rx * y / ry + (x1 + x2) / 2;
            cy = k * -ry * x / rx + (y1 + y2) / 2;
            f1 = masin(((y1 - cy) / ry).toFixed(7));
            f2 = masin(((y2 - cy) / ry).toFixed(7));

            f1 = x1 < cx ? PI - f1 : f1;
            f2 = x2 < cx ? PI - f2 : f2;
            if (f1 < 0) {
                f1 = PI * 2 + f1;
            }
            if (f2 < 0) {
                f2 = PI * 2 + f2;
            }
            if (sweep_flag && f1 > f2) {
                f1 = f1 - PI * 2;
            }
            if (!sweep_flag && f2 > f1) {
                f2 = f2 - PI * 2;
            }
        }
        else {
            f1 = recursive[0];
            f2 = recursive[1];
            cx = recursive[2];
            cy = recursive[3];
        }
        df = f2 - f1;
        if (mabs(df) > _120) {
            f2old = f2;
            x2old = x2;
            y2old = y2;
            f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
            x2 = cx + rx * mcos(f2);
            y2 = cy + ry * msin(f2);
            res = me.arc2curve(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
        }
        df = f2 - f1;
        c1 = mcos(f1);
        s1 = msin(f1);
        c2 = mcos(f2);
        s2 = msin(f2);
        t = math.tan(df / 4);
        hx = 4 / 3 * rx * t;
        hy = 4 / 3 * ry * t;
        m1 = [x1, y1];
        m2 = [x1 + hx * s1, y1 - hy * c1];
        m3 = [x2 + hx * s2, y2 - hy * c2];
        m4 = [x2, y2];
        m2[0] = 2 * m1[0] - m2[0];
        m2[1] = 2 * m1[1] - m2[1];
        if (recursive) {
            return [m2, m3, m4].concat(res);
        }
        else {
            res = [m2, m3, m4].concat(res).join().split(",");
            newres = [];
            ln = res.length;
            for (i = 0;  i < ln; i++) {
                newres[i] = i % 2 ? me.rotate(res[i - 1], res[i], rad).y : me.rotate(res[i], res[i + 1], rad).x;
            }
            return newres;
        }
    },

    
    rotateAndTranslatePath: function (sprite) {
        var alpha = sprite.rotation.degrees,
            cx = sprite.rotation.x,
            cy = sprite.rotation.y,
            dx = sprite.translation.x,
            dy = sprite.translation.y,
            path,
            i,
            p,
            xy,
            j,
            res = [];
        if (!alpha && !dx && !dy) {
            return this.pathToAbsolute(sprite.attr.path);
        }
        dx = dx || 0;
        dy = dy || 0;
        path = this.pathToAbsolute(sprite.attr.path);
        for (i = path.length; i--;) {
            p = res[i] = path[i].slice();
            if (p[0] == "A") {
                xy = this.rotatePoint(p[6], p[7], alpha, cx, cy);
                p[6] = xy.x + dx;
                p[7] = xy.y + dy;
            } else {
                j = 1;
                while (p[j + 1] != null) {
                    xy = this.rotatePoint(p[j], p[j + 1], alpha, cx, cy);
                    p[j] = xy.x + dx;
                    p[j + 1] = xy.y + dy;
                    j += 2;
                }
            }
        }
        return res;
    },

    
    rotatePoint: function (x, y, alpha, cx, cy) {
        if (!alpha) {
            return {
                x: x,
                y: y
            };
        }
        cx = cx || 0;
        cy = cy || 0;
        x = x - cx;
        y = y - cy;
        alpha = alpha * this.radian;
        var cos = Math.cos(alpha),
            sin = Math.sin(alpha);
        return {
            x: x * cos - y * sin + cx,
            y: x * sin + y * cos + cy
        };
    },

    pathDimensions: function (path) {
        if (!path || !(path + "")) {
            return {x: 0, y: 0, width: 0, height: 0};
        }
        path = this.path2curve(path);
        var x = 0, 
            y = 0,
            X = [],
            Y = [],
            i = 0,
            ln = path.length,
            p, xmin, ymin, dim;
        for (; i < ln; i++) {
            p = path[i];
            if (p[0] == "M") {
                x = p[1];
                y = p[2];
                X.push(x);
                Y.push(y);
            }
            else {
                dim = this.curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
                X = X.concat(dim.min.x, dim.max.x);
                Y = Y.concat(dim.min.y, dim.max.y);
                x = p[5];
                y = p[6];
            }
        }
        xmin = Math.min.apply(0, X);
        ymin = Math.min.apply(0, Y);
        return {
            x: xmin,
            y: ymin,
            path: path,
            width: Math.max.apply(0, X) - xmin,
            height: Math.max.apply(0, Y) - ymin
        };
    },

    intersectInside: function(path, cp1, cp2) {
        return (cp2[0] - cp1[0]) * (path[1] - cp1[1]) > (cp2[1] - cp1[1]) * (path[0] - cp1[0]);
    },

    intersectIntersection: function(s, e, cp1, cp2) {
        var p = [],
            dcx = cp1[0] - cp2[0],
            dcy = cp1[1] - cp2[1],
            dpx = s[0] - e[0],
            dpy = s[1] - e[1],
            n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
            n2 = s[0] * e[1] - s[1] * e[0],
            n3 = 1 / (dcx * dpy - dcy * dpx);

        p[0] = (n1 * dpx - n2 * dcx) * n3;
        p[1] = (n1 * dpy - n2 * dcy) * n3;
        return p;
    },

    intersect: function(subjectPolygon, clipPolygon) {
        var me = this,
            i = 0,
            ln = clipPolygon.length,
            cp1 = clipPolygon[ln - 1],
            outputList = subjectPolygon,
            cp2, s, e, point, ln2, inputList, j;
        for (; i < ln; ++i) {
            cp2 = clipPolygon[i];
            inputList = outputList;
            outputList = [];
            s = inputList[inputList.length - 1];
            j = 0;
            ln2 = inputList.length;
            for (; j < ln2; j++) {
                e = inputList[j];
                if (me.intersectInside(e, cp1, cp2)) {
                    if (!me.intersectInside(s, cp1, cp2)) {
                        outputList.push(me.intersectIntersection(s, e, cp1, cp2));
                    }
                    outputList.push(e);
                }
                else if (me.intersectInside(s, cp1, cp2)) {
                    outputList.push(me.intersectIntersection(s, e, cp1, cp2));
                }
                s = e;
            }
            cp1 = cp2;
        }
        return outputList;
    },
    
    bezier : function (a, b, c, d, x) {
        if (x === 0) {
            return a;
        } 
        else if (x === 1) {
            return d;
        }
        var du = 1 - x,
            d3 = du * du * du,
            r = x / du;
        return d3 * (a + r * (3 * b + r * (3 * c + d * r)));
    },
    
    bezierDim : function (a, b, c, d) {
        var points = [], r,
            A, top, C, delta, bottom, s,
            min, max, i;
        
        if (a + 3 * c == d + 3 * b) {   
            r = a - b;
            r /= 2 * (a - b - b + c);
            if ( r < 1 && r > 0) {
                points.push(r);
            }
        } else {
            
            
            A = a - 3 * b + 3 * c - d;
            top = 2 * (a - b - b + c);
            C = a - b;
            delta = top * top - 4 * A * C;
            bottom = A + A;
            if (delta === 0) {
                r = top / bottom;
                if (r < 1 && r > 0) {
                    points.push(r);
                }
            } else if (delta > 0) {
                s = Math.sqrt(delta);
                r = (s + top) / bottom;
                
                if (r < 1 && r > 0) {
                    points.push(r);
                }
                
                r = (top - s) / bottom;
                
                if (r < 1 && r > 0) {
                    points.push(r);
                }
            }
        }
        min = Math.min(a, d);
        max = Math.max(a, d);
        for (i = 0; i < points.length; i++) {
            min = Math.min(min, this.bezier(a, b, c, d, points[i]));
            max = Math.max(max, this.bezier(a, b, c, d, points[i]));
        }
        return [min, max];
    },
    
    curveDim: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
        var x = this.bezierDim(p1x, c1x, c2x, p2x),
            y = this.bezierDim(p1y, c1y, c2y, p2y);
        return {
            min: {
                x: x[0],
                y: y[0]
            },
            max: {
                x: x[1],
                y: y[1]
            }
        };
    },

    
    getAnchors: function (prevX, prevY, curX, curY, nextX, nextY, value) {
        value = value || 4;
        var M = Math,
            PI = M.PI,
            halfPI = PI / 2,
            abs = M.abs,
            sin = M.sin,
            cos = M.cos,
            atan = M.atan,
            control1Length, control2Length, control1Angle, control2Angle,
            control1X, control1Y, control2X, control2Y, alpha;

        
        
        control1Length = (curX - prevX) / value;
        control2Length = (nextX - curX) / value;

        
        
        
        
        if ((curY >= prevY && curY >= nextY) || (curY <= prevY && curY <= nextY)) {
            control1Angle = control2Angle = halfPI;
        } else {
            control1Angle = atan((curX - prevX) / abs(curY - prevY));
            if (prevY < curY) {
                control1Angle = PI - control1Angle;
            }
            control2Angle = atan((nextX - curX) / abs(curY - nextY));
            if (nextY < curY) {
                control2Angle = PI - control2Angle;
            }
        }

        
        alpha = halfPI - ((control1Angle + control2Angle) % (PI * 2)) / 2;
        if (alpha > halfPI) {
            alpha -= PI;
        }
        control1Angle += alpha;
        control2Angle += alpha;

        
        control1X = curX - control1Length * sin(control1Angle);
        control1Y = curY + control1Length * cos(control1Angle);
        control2X = curX + control2Length * sin(control2Angle);
        control2Y = curY + control2Length * cos(control2Angle);

        
        
        
        
        if ((curY > prevY && control1Y < prevY) || (curY < prevY && control1Y > prevY)) {
            control1X += abs(prevY - control1Y) * (control1X - curX) / (control1Y - curY);
            control1Y = prevY;
        }
        if ((curY > nextY && control2Y < nextY) || (curY < nextY && control2Y > nextY)) {
            control2X -= abs(nextY - control2Y) * (control2X - curX) / (control2Y - curY);
            control2Y = nextY;
        }
        
        return {
            x1: control1X,
            y1: control1Y,
            x2: control2X,
            y2: control2Y
        };
    },

    
    smooth: function (originalPath, value) {
        var path = this.path2curve(originalPath),
            newp = [path[0]],
            x = path[0][1],
            y = path[0][2],
            j,
            points,
            i = 1,
            ii = path.length,
            beg = 1,
            mx = x,
            my = y,
            cx = 0,
            cy = 0,
            pathi,
            pathil,
            pathim,
            pathiml,
            pathip,
            pathipl,
            begl;
        
        for (; i < ii; i++) {
            pathi = path[i];
            pathil = pathi.length;
            pathim = path[i - 1];
            pathiml = pathim.length;
            pathip = path[i + 1];
            pathipl = pathip && pathip.length;
            if (pathi[0] == "M") {
                mx = pathi[1];
                my = pathi[2];
                j = i + 1;
                while (path[j][0] != "C") {
                    j++;
                }
                cx = path[j][5];
                cy = path[j][6];
                newp.push(["M", mx, my]);
                beg = newp.length;
                x = mx;
                y = my;
                continue;
            }
            if (pathi[pathil - 2] == mx && pathi[pathil - 1] == my && (!pathip || pathip[0] == "M")) {
                begl = newp[beg].length;
                points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], mx, my, newp[beg][begl - 2], newp[beg][begl - 1], value);
                newp[beg][1] = points.x2;
                newp[beg][2] = points.y2;
            }
            else if (!pathip || pathip[0] == "M") {
                points = {
                    x1: pathi[pathil - 2],
                    y1: pathi[pathil - 1]
                };
            } else {
                points = this.getAnchors(pathim[pathiml - 2], pathim[pathiml - 1], pathi[pathil - 2], pathi[pathil - 1], pathip[pathipl - 2], pathip[pathipl - 1], value);
            }
            newp.push(["C", x, y, points.x1, points.y1, pathi[pathil - 2], pathi[pathil - 1]]);
            x = points.x2;
            y = points.y2;
        }
        return newp;
    },

    findDotAtSegment: function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
        var t1 = 1 - t;
        return {
            x: Math.pow(t1, 3) * p1x + Math.pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + Math.pow(t, 3) * p2x,
            y: Math.pow(t1, 3) * p1y + Math.pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + Math.pow(t, 3) * p2y
        };
    },

    
    snapEnds: function (from, to, stepsMax, prettyNumbers) {
        if (Ext.isDate(from)) {
            return this.snapEndsByDate(from, to, stepsMax);
        }
        var step = (to - from) / stepsMax,
            level = Math.floor(Math.log(step) / Math.LN10) + 1,
            m = Math.pow(10, level),
            cur,
            modulo = Math.round((step % m) * Math.pow(10, 2 - level)),
            interval = [[0, 15], [20, 4], [30, 2], [40, 4], [50, 9], [60, 4], [70, 2], [80, 4], [100, 15]],
            stepCount = 0,
            value,
            weight,
            i,
            topValue,
            topWeight = 1e9,
            ln = interval.length;
        cur = from = Math.floor(from / m) * m;
        
        if(prettyNumbers){
            for (i = 0; i < ln; i++) {
                value = interval[i][0];
                weight = (value - modulo) < 0 ? 1e6 : (value - modulo) / interval[i][1];
                if (weight < topWeight) {
                    topValue = value;
                    topWeight = weight;
                }
            }
            step = Math.floor(step * Math.pow(10, -level)) * Math.pow(10, level) + topValue * Math.pow(10, level - 2);
            while (cur < to) {
                cur += step;
                stepCount++;
            }
            to = +cur.toFixed(10);
        }else{
            stepCount = stepsMax;
        }
        
        return {
            from: from,
            to: to,
            power: level,
            step: step,
            steps: stepCount
        };
    },

    
    snapEndsByDate: function (from, to, stepsMax, lockEnds) {
        var selectedStep = false,
            scales       = [
                [Ext.Date.MILLI, [1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500]],
                [Ext.Date.SECOND, [1, 2, 3, 5, 10, 15, 30]],
                [Ext.Date.MINUTE, [1, 2, 3, 5, 10, 20, 30]],
                [Ext.Date.HOUR, [1, 2, 3, 4, 6, 12]],
                [Ext.Date.DAY, [1, 2, 3, 7, 14]],
                [Ext.Date.MONTH, [1, 2, 3, 4, 6]]
            ],
            sLen         = scales.length,
            stop         = false,
            scale, j, yearDiff, s;

        
        for (s = 0; s < sLen; s++) {
            scale = scales[s];
            if (!stop) {
                for (j = 0; j < scale[1].length; j++) {
                    if (to < Ext.Date.add(from, scale[0], scale[1][j] * stepsMax)) {
                        selectedStep = [scale[0], scale[1][j]];
                        stop         = true;
                        break;
                    }
                }
            }
        }

        if (!selectedStep) {
            yearDiff = this.snapEnds(from.getFullYear(), to.getFullYear() + 1, stepsMax, lockEnds);
            selectedStep = [Date.YEAR, Math.round(yearDiff.step)];
        }
        return this.snapEndsByDateAndStep(from, to, selectedStep, lockEnds);
    },


    
    snapEndsByDateAndStep: function(from, to, step, lockEnds) {
        var fromStat = [from.getFullYear(), from.getMonth(), from.getDate(),
                from.getHours(), from.getMinutes(), from.getSeconds(), from.getMilliseconds()],
            steps = 0, testFrom, testTo;
        if (lockEnds) {
            testFrom = from;
        } else {
            switch (step[0]) {
                case Ext.Date.MILLI:
                    testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
                            fromStat[4], fromStat[5], Math.floor(fromStat[6] / step[1]) * step[1]);
                    break;
                case Ext.Date.SECOND:
                    testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
                            fromStat[4], Math.floor(fromStat[5] / step[1]) * step[1], 0);
                    break;
                case Ext.Date.MINUTE:
                    testFrom = new Date(fromStat[0], fromStat[1], fromStat[2], fromStat[3],
                            Math.floor(fromStat[4] / step[1]) * step[1], 0, 0);
                    break;
                case Ext.Date.HOUR:
                    testFrom = new Date(fromStat[0], fromStat[1], fromStat[2],
                            Math.floor(fromStat[3] / step[1]) * step[1], 0, 0, 0);
                    break;
                case Ext.Date.DAY:
                    testFrom = new Date(fromStat[0], fromStat[1],
                            Math.floor(fromStat[2] - 1 / step[1]) * step[1] + 1, 0, 0, 0, 0);
                    break;
                case Ext.Date.MONTH:
                    testFrom = new Date(fromStat[0], Math.floor(fromStat[1] / step[1]) * step[1], 1, 0, 0, 0, 0);
                    break;
                default: 
                    testFrom = new Date(Math.floor(fromStat[0] / step[1]) * step[1], 0, 1, 0, 0, 0, 0);
                    break;
            }
        }

        testTo = testFrom;
        
        while (testTo < to) {
            testTo = Ext.Date.add(testTo, step[0], step[1]);
            steps++;
        }

        if (lockEnds) {
            testTo = to;
        }
        return {
            from : +testFrom,
            to : +testTo,
            step : (testTo - testFrom) / steps,
            steps : steps
        };
    },

    sorter: function (a, b) {
        return a.offset - b.offset;
    },

    rad: function(degrees) {
        return degrees % 360 * Math.PI / 180;
    },

    degrees: function(radian) {
        return radian * 180 / Math.PI % 360;
    },

    withinBox: function(x, y, bbox) {
        bbox = bbox || {};
        return (x >= bbox.x && x <= (bbox.x + bbox.width) && y >= bbox.y && y <= (bbox.y + bbox.height));
    },

    parseGradient: function(gradient) {
        var me = this,
            type = gradient.type || 'linear',
            angle = gradient.angle || 0,
            radian = me.radian,
            stops = gradient.stops,
            stopsArr = [],
            stop,
            vector,
            max,
            stopObj;

        if (type == 'linear') {
            vector = [0, 0, Math.cos(angle * radian), Math.sin(angle * radian)];
            max = 1 / (Math.max(Math.abs(vector[2]), Math.abs(vector[3])) || 1);
            vector[2] *= max;
            vector[3] *= max;
            if (vector[2] < 0) {
                vector[0] = -vector[2];
                vector[2] = 0;
            }
            if (vector[3] < 0) {
                vector[1] = -vector[3];
                vector[3] = 0;
            }
        }

        for (stop in stops) {
            if (stops.hasOwnProperty(stop) && me.stopsRE.test(stop)) {
                stopObj = {
                    offset: parseInt(stop, 10),
                    color: Ext.draw.Color.toHex(stops[stop].color) || '#ffffff',
                    opacity: stops[stop].opacity || 1
                };
                stopsArr.push(stopObj);
            }
        }
        
        Ext.Array.sort(stopsArr, me.sorter);
        if (type == 'linear') {
            return {
                id: gradient.id,
                type: type,
                vector: vector,
                stops: stopsArr
            };
        }
        else {
            return {
                id: gradient.id,
                type: type,
                centerX: gradient.centerX,
                centerY: gradient.centerY,
                focalX: gradient.focalX,
                focalY: gradient.focalY,
                radius: gradient.radius,
                vector: vector,
                stops: stopsArr
            };
        }
    }
});


Ext.define('Ext.draw.Matrix', {

    

    requires: ['Ext.draw.Draw'],

    

    constructor: function(a, b, c, d, e, f) {
        if (a != null) {
            this.matrix = [[a, c, e], [b, d, f], [0, 0, 1]];
        }
        else {
            this.matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
        }
    },

    add: function(a, b, c, d, e, f) {
        var me = this,
            out = [[], [], []],
            matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
            x,
            y,
            z,
            res;

        for (x = 0; x < 3; x++) {
            for (y = 0; y < 3; y++) {
                res = 0;
                for (z = 0; z < 3; z++) {
                    res += me.matrix[x][z] * matrix[z][y];
                }
                out[x][y] = res;
            }
        }
        me.matrix = out;
    },

    prepend: function(a, b, c, d, e, f) {
        var me = this,
            out = [[], [], []],
            matrix = [[a, c, e], [b, d, f], [0, 0, 1]],
            x,
            y,
            z,
            res;

        for (x = 0; x < 3; x++) {
            for (y = 0; y < 3; y++) {
                res = 0;
                for (z = 0; z < 3; z++) {
                    res += matrix[x][z] * me.matrix[z][y];
                }
                out[x][y] = res;
            }
        }
        me.matrix = out;
    },

    invert: function() {
        var matrix = this.matrix,
            a = matrix[0][0],
            b = matrix[1][0],
            c = matrix[0][1],
            d = matrix[1][1],
            e = matrix[0][2],
            f = matrix[1][2],
            x = a * d - b * c;
        return new Ext.draw.Matrix(d / x, -b / x, -c / x, a / x, (c * f - d * e) / x, (b * e - a * f) / x);
    },

    clone: function() {
        var matrix = this.matrix,
            a = matrix[0][0],
            b = matrix[1][0],
            c = matrix[0][1],
            d = matrix[1][1],
            e = matrix[0][2],
            f = matrix[1][2];
        return new Ext.draw.Matrix(a, b, c, d, e, f);
    },

    translate: function(x, y) {
        this.prepend(1, 0, 0, 1, x, y);
    },

    scale: function(x, y, cx, cy) {
        var me = this;
        if (y == null) {
            y = x;
        }
        me.add(x, 0, 0, y, cx * (1 - x), cy * (1 - y));
    },

    rotate: function(a, x, y) {
        a = Ext.draw.Draw.rad(a);
        var me = this,
            cos = +Math.cos(a).toFixed(9),
            sin = +Math.sin(a).toFixed(9);
        me.add(cos, sin, -sin, cos, x - cos * x + sin * y, -(sin * x) + y - cos * y);
    },

    x: function(x, y) {
        var matrix = this.matrix;
        return x * matrix[0][0] + y * matrix[0][1] + matrix[0][2];
    },

    y: function(x, y) {
        var matrix = this.matrix;
        return x * matrix[1][0] + y * matrix[1][1] + matrix[1][2];
    },

    get: function(i, j) {
        return + this.matrix[i][j].toFixed(4);
    },

    toString: function() {
        var me = this;
        return [me.get(0, 0), me.get(0, 1), me.get(1, 0), me.get(1, 1), 0, 0].join();
    },

    toSvg: function() {
        var me = this;
        return "matrix(" + [me.get(0, 0), me.get(1, 0), me.get(0, 1), me.get(1, 1), me.get(0, 2), me.get(1, 2)].join() + ")";
    },

    toFilter: function(dx, dy) {
        var me = this;
        dx = dx || 0;
        dy = dy || 0;
        return "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', filterType='bilinear', M11=" + me.get(0, 0) +
            ", M12=" + me.get(0, 1) + ", M21=" + me.get(1, 0) + ", M22=" + me.get(1, 1) +
            ", Dx=" + (me.get(0, 2) + dx) + ", Dy=" + (me.get(1, 2) + dy) + ")";
    },

    offset: function() {
        var matrix = this.matrix;
        return [(matrix[0][2] || 0).toFixed(4), (matrix[1][2] || 0).toFixed(4)];
    },

    
    split: function () {
        function norm(a) {
            return a[0] * a[0] + a[1] * a[1];
        }
        function normalize(a) {
            var mag = Math.sqrt(norm(a));
            a[0] /= mag;
            a[1] /= mag;
        }
        var matrix = this.matrix,
            out = {
                translateX: matrix[0][2],
                translateY: matrix[1][2]
            },
            row;

        
        row = [[matrix[0][0], matrix[0][1]], [matrix[1][1], matrix[1][1]]];
        out.scaleX = Math.sqrt(norm(row[0]));
        normalize(row[0]);

        out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
        row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];

        out.scaleY = Math.sqrt(norm(row[1]));
        normalize(row[1]);
        out.shear /= out.scaleY;

        
        out.rotate = Math.asin(-row[0][1]);

        out.isSimple = !+out.shear.toFixed(9) && (out.scaleX.toFixed(9) == out.scaleY.toFixed(9) || !out.rotate);

        return out;
    }
});


Ext.define('Ext.draw.engine.ImageExporter', {
    singleton: true,

    
    defaultUrl: 'http://svg.sencha.io',

    
    supportedTypes: ['image/png', 'image/jpeg'],

    
    widthParam: 'width',

    
    heightParam: 'height',

    
    typeParam: 'type',

    
    svgParam: 'svg',

    formCls: Ext.baseCSSPrefix + 'hide-display',

    
    generate: function(surface, config) {
        config = config || {};
        var me = this,
            type = config.type,
            form;

        if (Ext.Array.indexOf(me.supportedTypes, type) === -1) {
            return false;
        }

        form = Ext.getBody().createChild({
            tag: 'form',
            method: 'POST',
            action: config.url || me.defaultUrl,
            cls: me.formCls,
            children: [{
                tag: 'input',
                type: 'hidden',
                name: config.widthParam || me.widthParam,
                value: config.width || surface.width
            }, {
                tag: 'input',
                type: 'hidden',
                name: config.heightParam || me.heightParam,
                value: config.height || surface.height
            }, {
                tag: 'input',
                type: 'hidden',
                name: config.typeParam || me.typeParam,
                value: type
            }, {
                tag: 'input',
                type: 'hidden',
                name: config.svgParam || me.svgParam
            }]
        });

        
        form.last(null, true).value = Ext.draw.engine.SvgExporter.generate(surface);

        form.dom.submit();
        form.remove();
        return true;
    }

});


Ext.define('Ext.draw.engine.SvgExporter', function(){
   var commaRe = /,/g,
       fontRegex = /(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)\s('*.*'*)/,
       rgbColorRe = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
       rgbaColorRe = /rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,([\d\.]+)\)/g,
       surface, len, width, height,

   init = function(s){
       surface = s;
       len = surface.length;
       width = surface.width;
       height = surface.height;
   },
   spriteProcessor = {
       path: function(sprite){

           var attr = sprite.attr,
               path = attr.path,
               pathString = '',
               props, p, pLen;

           if (Ext.isArray(path[0])) {
               pLen = path.length;
               for (p = 0; p < pLen; p++) {
                   pathString += path[p].join(' ');
               }
           } else if (Ext.isArray(path)) {
               pathString = path.join(' ');
           } else {
               pathString = path.replace(commaRe,' ');
           }

           props = toPropertyString({
               d: pathString,
               fill: attr.fill || 'none',
               stroke: attr.stroke,
               'fill-opacity': attr.opacity,
               'stroke-width': attr['stroke-width'],
               'stroke-opacity': attr['stroke-opacity'],
               "z-index": attr.zIndex,
               transform: sprite.matrix.toSvg()
           });

           return '<path ' + props + '/>';
       },
       text: function(sprite){

           
           

           var attr = sprite.attr,
               match = fontRegex.exec(attr.font),
               size = (match && match[1]) || "12",
               
               family = (match && match[3]) || 'Arial',
               text = attr.text,
               factor = (Ext.isFF3_0 || Ext.isFF3_5) ? 2 : 4,
               tspanString = '',
               props;

           sprite.getBBox();
           tspanString += '<tspan x="' + (attr.x || '') + '" dy="';
           tspanString += (size/factor)+'">';
           tspanString += Ext.htmlEncode(text) + '</tspan>';


           props = toPropertyString({
               x: attr.x,
               y: attr.y,
               'font-size': size,
               'font-family': family,
               'font-weight': attr['font-weight'],
               'text-anchor': attr['text-anchor'],
               
               fill: attr.fill || '#000',
               'fill-opacity': attr.opacity,
               transform: sprite.matrix.toSvg()
           });



           return '<text '+ props + '>' +  tspanString + '</text>';
       },
       rect: function(sprite){

           var attr = sprite.attr,
               props =  toPropertyString({
                   x: attr.x,
                   y: attr.y,
                   rx: attr.rx,
                   ry: attr.ry,
                   width: attr.width,
                   height: attr.height,
                   fill: attr.fill || 'none',
                   'fill-opacity': attr.opacity,
                   stroke: attr.stroke,
                   'stroke-opacity': attr['stroke-opacity'],
                   'stroke-width':attr['stroke-width'],
                   transform: sprite.matrix && sprite.matrix.toSvg()
               });

           return '<rect ' + props + '/>';
       },
       circle: function(sprite){

           var attr = sprite.attr,
               props = toPropertyString({
                   cx: attr.x,
                   cy: attr.y,
                   r: attr.radius,
                   fill: attr.translation.fill || attr.fill || 'none',
                   'fill-opacity': attr.opacity,
                   stroke: attr.stroke,
                   'stroke-opacity': attr['stroke-opacity'],
                   'stroke-width':attr['stroke-width'],
                   transform: sprite.matrix.toSvg()
               });

           return '<circle ' + props + ' />';
       },
       image: function(sprite){

           var attr = sprite.attr,
               props = toPropertyString({
                   x: attr.x - (attr.width/2 >> 0),
                   y: attr.y - (attr.height/2 >> 0),
                   width: attr.width,
                   height: attr.height,
                   'xlink:href': attr.src,
                   transform: sprite.matrix.toSvg()
               });

           return '<image ' + props + ' />';
       }
   },
   svgHeader = function(){
       var svg = '<?xml version="1.0" standalone="yes"?>';
       svg += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
       return svg;
   },
   svgContent = function(){
       var svg = '<svg width="'+width+'px" height="'+height+'px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">',
           defs = '', item, itemsLen, items, gradient,
           getSvgString, colorstops, stop,
           coll, keys, colls, k, kLen, key, collI, i, j, stopsLen, sortedItems, za, zb;

       items = surface.items.items;
       itemsLen = items.length;


       getSvgString = function(node){

           var childs = node.childNodes,
               childLength = childs.length,
               i = 0,
               attrLength,
               j,
               svgString = '', child, attr, tagName, attrItem;

               for(; i < childLength; i++){
                   child = childs[i];
                   attr = child.attributes;
                   tagName = child.tagName;

                   svgString += '<' +tagName;

                   for(j = 0, attrLength = attr.length; j < attrLength; j++){
                       attrItem = attr.item(j);
                       svgString += ' '+attrItem.name+'="'+attrItem.value+'"';
                   }

                   svgString += '>';

                   if(child.childNodes.length > 0){
                       svgString += getSvgString(child);
                   }

                   svgString += '</' + tagName + '>';

               }
           return svgString;
       };


       if(surface.getDefs){
           defs = getSvgString(surface.getDefs());
       }else{
           
           coll = surface.gradientsColl;
           if (coll) {
               keys  = coll.keys;
               colls = coll.items;
               k     = 0;
               kLen  = keys.length;
           }

           for (; k < kLen; k++) {
               key   = keys[k];
               collI = colls[k];

               gradient = surface.gradientsColl.getByKey(key);
               defs += '<linearGradient id="' + key + '" x1="0" y1="0" x2="1" y2="1">';

               var color = gradient.colors.replace(rgbColorRe, 'rgb($1|$2|$3)');
               color = color.replace(rgbaColorRe, 'rgba($1|$2|$3|$4)')
               colorstops = color.split(',');
               for(i=0, stopsLen = colorstops.length; i < stopsLen; i++){
                   stop = colorstops[i].split(' ');
                   color = Ext.draw.Color.fromString(stop[1].replace(/\|/g,','));
                   defs += '<stop offset="'+stop[0]+'" stop-color="' + color.toString() + '" stop-opacity="1"></stop>';
               }
               defs += '</linearGradient>';
           }
       }

       svg += '<defs>' + defs + '</defs>';

       
       svg += spriteProcessor.rect({
           attr: {
                   width: '100%',
                   height: '100%',
                   fill: '#fff',
                   stroke: 'none',
                   opacity: '0'
           }
       });

       
       sortedItems = new Array(itemsLen);
       for(i = 0; i < itemsLen; i++){
           sortedItems[i] = i;
       }
       sortedItems.sort(function (a, b) {
           za = items[a].attr.zIndex || 0;
           zb = items[b].attr.zIndex || 0;
           if (za == zb) {
               return a - b;
           }
           return za - zb;
       });

       for(i = 0; i < itemsLen; i++){
           item = items[sortedItems[i]];
           if(!item.attr.hidden){
               svg += spriteProcessor[item.type](item);
           }
       }

       svg += '</svg>';

       return svg;
   },
   toPropertyString = function(obj){
       var propString = '',
           key;

       for(key in obj){

           if(obj.hasOwnProperty(key) && obj[key] != null){
               propString += key +'="'+ obj[key]+'" ';
           }

       }

       return propString;
   };

   return {
       singleton: true,

       
       generate: function(surface, config){
           config = config || {};
           init(surface);
           return svgHeader() + svgContent();
       }
   };
});

Ext.define('Ext.fx.CubicBezier', {

    

    singleton: true,

    

    cubicBezierAtTime: function(t, p1x, p1y, p2x, p2y, duration) {
        var cx = 3 * p1x,
            bx = 3 * (p2x - p1x) - cx,
            ax = 1 - cx - bx,
            cy = 3 * p1y,
            by = 3 * (p2y - p1y) - cy,
            ay = 1 - cy - by;
        function sampleCurveX(t) {
            return ((ax * t + bx) * t + cx) * t;
        }
        function solve(x, epsilon) {
            var t = solveCurveX(x, epsilon);
            return ((ay * t + by) * t + cy) * t;
        }
        function solveCurveX(x, epsilon) {
            var t0, t1, t2, x2, d2, i;
            for (t2 = x, i = 0; i < 8; i++) {
                x2 = sampleCurveX(t2) - x;
                if (Math.abs(x2) < epsilon) {
                    return t2;
                }
                d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
                if (Math.abs(d2) < 1e-6) {
                    break;
                }
                t2 = t2 - x2 / d2;
            }
            t0 = 0;
            t1 = 1;
            t2 = x;
            if (t2 < t0) {
                return t0;
            }
            if (t2 > t1) {
                return t1;
            }
            while (t0 < t1) {
                x2 = sampleCurveX(t2);
                if (Math.abs(x2 - x) < epsilon) {
                    return t2;
                }
                if (x > x2) {
                    t0 = t2;
                } else {
                    t1 = t2;
                }
                t2 = (t1 - t0) / 2 + t0;
            }
            return t2;
        }
        return solve(t, 1 / (200 * duration));
    },

    cubicBezier: function(x1, y1, x2, y2) {
        var fn = function(pos) {
            return Ext.fx.CubicBezier.cubicBezierAtTime(pos, x1, y1, x2, y2, 1);
        };
        fn.toCSS3 = function() {
            return 'cubic-bezier(' + [x1, y1, x2, y2].join(',') + ')';
        };
        fn.reverse = function() {
            return Ext.fx.CubicBezier.cubicBezier(1 - x2, 1 - y2, 1 - x1, 1 - y1);
        };
        return fn;
    }
});

Ext.define('Ext.fx.PropertyHandler', {

    

    requires: ['Ext.draw.Draw'],

    statics: {
        defaultHandler: {
            pixelDefaultsRE: /width|height|top$|bottom$|left$|right$/i,
            unitRE: /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/,
            scrollRE: /^scroll/i,

            computeDelta: function(from, end, damper, initial, attr) {
                damper = (typeof damper == 'number') ? damper : 1;
                var unitRE = this.unitRE,
                    match = unitRE.exec(from),
                    start, units;
                if (match) {
                    from = match[1];
                    units = match[2];
                    if (!this.scrollRE.test(attr) && !units && this.pixelDefaultsRE.test(attr)) {
                        units = 'px';
                    }
                }
                from = +from || 0;

                match = unitRE.exec(end);
                if (match) {
                    end = match[1];
                    units = match[2] || units;
                }
                end = +end || 0;
                start = (initial != null) ? initial : from;
                return {
                    from: from,
                    delta: (end - start) * damper,
                    units: units
                };
            },

            get: function(from, end, damper, initialFrom, attr) {
                var ln = from.length,
                    out = [],
                    i, initial, res, j, len;
                for (i = 0; i < ln; i++) {
                    if (initialFrom) {
                        initial = initialFrom[i][1].from;
                    }
                    if (Ext.isArray(from[i][1]) && Ext.isArray(end)) {
                        res = [];
                        j = 0;
                        len = from[i][1].length;
                        for (; j < len; j++) {
                            res.push(this.computeDelta(from[i][1][j], end[j], damper, initial, attr));
                        }
                        out.push([from[i][0], res]);
                    }
                    else {
                        out.push([from[i][0], this.computeDelta(from[i][1], end, damper, initial, attr)]);
                    }
                }
                return out;
            },

            set: function(values, easing) {
                var ln = values.length,
                    out = [],
                    i, val, res, len, j;
                for (i = 0; i < ln; i++) {
                    val  = values[i][1];
                    if (Ext.isArray(val)) {
                        res = [];
                        j = 0;
                        len = val.length;
                        for (; j < len; j++) {
                            res.push(val[j].from + val[j].delta * easing + (val[j].units || 0));
                        }
                        out.push([values[i][0], res]);
                    } else {
                        out.push([values[i][0], val.from + val.delta * easing + (val.units || 0)]);
                    }
                }
                return out;
            }
        },
        stringHandler: {
            computeDelta: function(from, end, damper, initial, attr) {
                return {
                    from: from,
                    delta: end
                };
            },

            get: function(from, end, damper, initialFrom, attr) {
                var ln = from.length,
                    out = [],
                    i, initial, res, j, len;
                for (i = 0; i < ln; i++) {
                    out.push([from[i][0], this.computeDelta(from[i][1], end, damper, initial, attr)]);
                }
                return out;
            },

            set: function(values, easing) {
                var ln = values.length,
                    out = [],
                    i, val, res, len, j;
                for (i = 0; i < ln; i++) {
                    val  = values[i][1];
                    out.push([values[i][0], val.delta]);
                }
                return out;
            }
        },
        color: {
            rgbRE: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
            hexRE: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
            hex3RE: /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i,

            parseColor : function(color, damper) {
                damper = (typeof damper == 'number') ? damper : 1;
                var out    = false,
                    reList = [this.hexRE, this.rgbRE, this.hex3RE],
                    length = reList.length,
                    match, base, re, i;

                for (i = 0; i < length; i++) {
                    re = reList[i];

                    base = (i % 2 === 0) ? 16 : 10;
                    match = re.exec(color);
                    if (match && match.length === 4) {
                        if (i === 2) {
                            match[1] += match[1];
                            match[2] += match[2];
                            match[3] += match[3];
                        }
                        out = {
                            red: parseInt(match[1], base),
                            green: parseInt(match[2], base),
                            blue: parseInt(match[3], base)
                        };
                        break;
                    }
                }

                return out || color;
            },

            computeDelta: function(from, end, damper, initial) {
                from = this.parseColor(from);
                end = this.parseColor(end, damper);
                var start = initial ? initial : from,
                    tfrom = typeof start,
                    tend = typeof end;
                
                if (tfrom == 'string' ||  tfrom == 'undefined'
                  || tend == 'string' || tend == 'undefined') {
                    return end || start;
                }
                return {
                    from:  from,
                    delta: {
                        red: Math.round((end.red - start.red) * damper),
                        green: Math.round((end.green - start.green) * damper),
                        blue: Math.round((end.blue - start.blue) * damper)
                    }
                };
            },

            get: function(start, end, damper, initialFrom) {
                var ln = start.length,
                    out = [],
                    i, initial;
                for (i = 0; i < ln; i++) {
                    if (initialFrom) {
                        initial = initialFrom[i][1].from;
                    }
                    out.push([start[i][0], this.computeDelta(start[i][1], end, damper, initial)]);
                }
                return out;
            },

            set: function(values, easing) {
                var ln = values.length,
                    out = [],
                    i, val, parsedString, from, delta;
                for (i = 0; i < ln; i++) {
                    val = values[i][1];
                    if (val) {
                        from = val.from;
                        delta = val.delta;
                        
                        val = (typeof val == 'object' && 'red' in val)? 
                                'rgb(' + val.red + ', ' + val.green + ', ' + val.blue + ')' : val;
                        val = (typeof val == 'object' && val.length)? val[0] : val;
                        if (typeof val == 'undefined') {
                            return [];
                        }
                        parsedString = typeof val == 'string'? val :
                            'rgb(' + [
                                  (from.red + Math.round(delta.red * easing)) % 256,
                                  (from.green + Math.round(delta.green * easing)) % 256,
                                  (from.blue + Math.round(delta.blue * easing)) % 256
                              ].join(',') + ')';
                        out.push([
                            values[i][0],
                            parsedString
                        ]);
                    }
                }
                return out;
            }
        },
        object: {
            interpolate: function(prop, damper) {
                damper = (typeof damper == 'number') ? damper : 1;
                var out = {},
                    p;
                for(p in prop) {
                    out[p] = parseFloat(prop[p]) * damper;
                }
                return out;
            },

            computeDelta: function(from, end, damper, initial) {
                from = this.interpolate(from);
                end = this.interpolate(end, damper);
                var start = initial ? initial : from,
                    delta = {},
                    p;

                for(p in end) {
                    delta[p] = end[p] - start[p];
                }
                return {
                    from:  from,
                    delta: delta
                };
            },

            get: function(start, end, damper, initialFrom) {
                var ln = start.length,
                    out = [],
                    i, initial;
                for (i = 0; i < ln; i++) {
                    if (initialFrom) {
                        initial = initialFrom[i][1].from;
                    }
                    out.push([start[i][0], this.computeDelta(start[i][1], end, damper, initial)]);
                }
                return out;
            },

            set: function(values, easing) {
                var ln = values.length,
                    out = [],
                    outObject = {},
                    i, from, delta, val, p;
                for (i = 0; i < ln; i++) {
                    val  = values[i][1];
                    from = val.from;
                    delta = val.delta;
                    for (p in from) {
                        outObject[p] = from[p] + delta[p] * easing;
                    }
                    out.push([
                        values[i][0],
                        outObject
                    ]);
                }
                return out;
            }
        },

        path: {
            computeDelta: function(from, end, damper, initial) {
                damper = (typeof damper == 'number') ? damper : 1;
                var start;
                from = +from || 0;
                end = +end || 0;
                start = (initial != null) ? initial : from;
                return {
                    from: from,
                    delta: (end - start) * damper
                };
            },

            forcePath: function(path) {
                if (!Ext.isArray(path) && !Ext.isArray(path[0])) {
                    path = Ext.draw.Draw.parsePathString(path);
                }
                return path;
            },

            get: function(start, end, damper, initialFrom) {
                var endPath = this.forcePath(end),
                    out = [],
                    startLn = start.length,
                    startPathLn, pointsLn, i, deltaPath, initial, j, k, path, startPath;
                for (i = 0; i < startLn; i++) {
                    startPath = this.forcePath(start[i][1]);

                    deltaPath = Ext.draw.Draw.interpolatePaths(startPath, endPath);
                    startPath = deltaPath[0];
                    endPath = deltaPath[1];

                    startPathLn = startPath.length;
                    path = [];
                    for (j = 0; j < startPathLn; j++) {
                        deltaPath = [startPath[j][0]];
                        pointsLn = startPath[j].length;
                        for (k = 1; k < pointsLn; k++) {
                            initial = initialFrom && initialFrom[0][1][j][k].from;
                            deltaPath.push(this.computeDelta(startPath[j][k], endPath[j][k], damper, initial));
                        }
                        path.push(deltaPath);
                    }
                    out.push([start[i][0], path]);
                }
                return out;
            },

            set: function(values, easing) {
                var ln = values.length,
                    out = [],
                    i, j, k, newPath, calcPath, deltaPath, deltaPathLn, pointsLn;
                for (i = 0; i < ln; i++) {
                    deltaPath = values[i][1];
                    newPath = [];
                    deltaPathLn = deltaPath.length;
                    for (j = 0; j < deltaPathLn; j++) {
                        calcPath = [deltaPath[j][0]];
                        pointsLn = deltaPath[j].length;
                        for (k = 1; k < pointsLn; k++) {
                            calcPath.push(deltaPath[j][k].from + deltaPath[j][k].delta * easing);
                        }
                        newPath.push(calcPath.join(','));
                    }
                    out.push([values[i][0], newPath.join(',')]);
                }
                return out;
            }
        }
        
    }
}, function() {
    
    var props  = [
            'outlineColor',
            'backgroundColor',
            'borderColor',
            'borderTopColor',
            'borderRightColor',
            'borderBottomColor',
            'borderLeftColor',
            'fill',
            'stroke'
        ],
        length = props.length,
        i      = 0,
        prop;

    for (; i<length; i++) {
        prop = props[i];
        this[prop] = this.color;
    }
    
    
    props  = ['cursor'];
    length = props.length;
    i      = 0;

    for (; i<length; i++) {
        prop = props[i];
        this[prop] = this.stringHandler;
    }
});


Ext.define('Ext.fx.target.Target', {

    isAnimTarget: true,

    
    constructor: function(target) {
        this.target = target;
        this.id = this.getId();
    },
    
    getId: function() {
        return this.target.id;
    }
});


Ext.define('Ext.layout.ClassList', (function () {

    var splitWords = Ext.String.splitWords,
        toMap = Ext.Array.toMap;

    return {
        dirty: false,

        constructor: function (owner) {
            this.owner = owner;
            this.map = toMap(this.classes = splitWords(owner.el.className));
        },

        
        add: function (cls) {
            var me = this;

            if (!me.map[cls]) {
                me.map[cls] = true;
                me.classes.push(cls);
                if (!me.dirty) {
                    me.dirty = true;
                    me.owner.markDirty();
                }
            }
        },

        
        addMany: function (classes) {
            Ext.each(splitWords(classes), this.add, this);
        },

        contains: function (cls) {
            return this.map[cls];
        },

        flush: function () {
            this.owner.el.className = this.classes.join(' ');
            this.dirty = false;
        },

        
        remove: function (cls) {
            var me = this;

            if (me.map[cls]) {
                delete me.map[cls];
                me.classes = Ext.Array.filter(me.classes, function (c) {
                    return c != cls;
                });
                if (!me.dirty) {
                    me.dirty = true;
                    me.owner.markDirty();
                }
            }
        },

        
        removeMany: function (classes) {
            var me = this,
                remove = toMap(splitWords(classes));

            me.classes = Ext.Array.filter(me.classes, function (c) {
                if (!remove[c]) {
                    return true;
                }

                delete me.map[c];
                if (!me.dirty) {
                    me.dirty = true;
                    me.owner.markDirty();
                }
                return false;
            });
        }
    };
}()));


Ext.define('Ext.layout.ContextItem', {
    
    requires: ['Ext.layout.ClassList'],

    heightModel: null,
    widthModel: null,
    sizeModel: null,

    boxChildren: null,

    boxParent: null,

    children: [],

    dirty: null,

    
    dirtyCount: 0,

    hasRawContent: true,

    isContextItem: true,

    isTopLevel: false,

    consumersContentHeight: 0,
    consumersContentWidth: 0,
    consumersContainerHeight: 0,
    consumersContainerWidth: 0,
    consumersHeight: 0,
    consumersWidth: 0,

    ownerCtContext: null,

    remainingChildLayouts: 0,
    remainingComponentChildLayouts: 0,
    remainingContainerChildLayouts: 0,

    
    props: null,

    
    state: null,

    
    wrapsComponent: false,

    constructor: function (config) {
        var me = this,
            el, ownerCt, ownerCtContext, sizeModel, target;

        Ext.apply(me, config);

        el = me.el;
        me.id = el.id;
        me.lastBox = el.lastBox;

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        

        me.flushedProps = {};
        me.props = {};

        
        me.styles = {};

        target = me.target;
        if (target.isComponent) {
            me.wrapsComponent = true;

            
            
            ownerCt = target.ownerCt;
            if (ownerCt && (ownerCtContext = me.context.items[ownerCt.el.id])) {
                me.ownerCtContext = ownerCtContext;
            }

            
            
            me.sizeModel = sizeModel = target.getSizeModel(ownerCtContext &&
                ownerCtContext.widthModel.pairsByHeightOrdinal[ownerCtContext.heightModel.ordinal]);

            me.widthModel = sizeModel.width;
            me.heightModel = sizeModel.height;

            
            
            
            
            
        }
    },

    
    init: function (full, options) {
        var me = this,
            oldProps = me.props,
            oldDirty = me.dirty,
            ownerCtContext = me.ownerCtContext,
            ownerLayout = me.target.ownerLayout,
            firstTime = !me.state,
            ret = full || firstTime,
            children, i, n, ownerCt, sizeModel, target,
            oldHeightModel = me.heightModel,
            oldWidthModel = me.widthModel,
            newHeightModel, newWidthModel;

        me.dirty = me.invalid = false;
        me.props = {};

        if (me.boxChildren) {
            me.boxChildren.length = 0; 
        }

        if (!firstTime) {
            me.clearAllBlocks('blocks');
            me.clearAllBlocks('domBlocks');
        }

        
        if (!me.wrapsComponent) {
            return ret;
        }

        
        target = me.target;
        me.state = {}; 

        if (firstTime) {
            
            
            if (target.beforeLayout) {
                target.beforeLayout();
            }

            
            
            
            
            
            
            if (!ownerCtContext && (ownerCt = target.ownerCt)) {
                ownerCtContext = me.context.items[ownerCt.el.id];
            }

            if (ownerCtContext) {
                me.ownerCtContext = ownerCtContext;
                me.isBoxParent = target.ownerLayout.isItemBoxParent(me);
            } else {
                me.isTopLevel = true; 
            }

            me.frameBodyContext = me.getEl('frameBody');
        } else {
            ownerCtContext = me.ownerCtContext;

            
            me.isTopLevel = !ownerCtContext;

            
            
            children = me.children;
            for (i = 0, n = children.length; i < n; ++i) {
                children[i].init(true);
            }
        }

        
        
        
        me.hasRawContent = !(target.isContainer && target.items.items.length > 0);

        if (full) {
            
            
            me.widthModel = me.heightModel = null;
            sizeModel = target.getSizeModel(ownerCtContext && 
                ownerCtContext.widthModel.pairsByHeightOrdinal[ownerCtContext.heightModel.ordinal]);

            if (firstTime) {
                me.sizeModel = sizeModel;
            }

            me.widthModel = sizeModel.width;
            me.heightModel = sizeModel.height;
        } else if (oldProps) {
            
            
            me.recoverProp('x', oldProps, oldDirty);
            me.recoverProp('y', oldProps, oldDirty);

            
            if (me.widthModel.calculated) {
                me.recoverProp('width', oldProps, oldDirty);
            }
            if (me.heightModel.calculated) {
                me.recoverProp('height', oldProps, oldDirty);
            }
        }

        if (oldProps && ownerLayout && ownerLayout.manageMargins) {
            me.recoverProp('margin-top', oldProps, oldDirty);
            me.recoverProp('margin-right', oldProps, oldDirty);
            me.recoverProp('margin-bottom', oldProps, oldDirty);
            me.recoverProp('margin-left', oldProps, oldDirty);
        }

        
        
        if (options) {
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            newHeightModel = options.heightModel;
            newWidthModel = options.widthModel;
            if (newWidthModel && newHeightModel && oldWidthModel && oldHeightModel) {
                if (oldWidthModel.shrinkWrap && oldHeightModel.shrinkWrap) {
                    if (newWidthModel.constrainedMax && newHeightModel.constrainedMin) {
                        newHeightModel = null;
                    }
                }
            }

            
            if (newWidthModel) {
                me.widthModel = newWidthModel;
            }
            if (newHeightModel) {
                me.heightModel = newHeightModel;
            }

            if (options.state) {
                Ext.apply(me.state, options.state);
            }
        }

        return ret;
    },

    
    initContinue: function (full) {
        var me = this,
            ownerCtContext = me.ownerCtContext,
            widthModel = me.widthModel,
            boxParent;

        if (full) {
            if (ownerCtContext && widthModel.shrinkWrap) {
                boxParent = ownerCtContext.isBoxParent ? ownerCtContext : ownerCtContext.boxParent;
                if (boxParent) {
                    boxParent.addBoxChild(me);
                }
            } else if (widthModel.natural) {
                me.boxParent = ownerCtContext;
            }
        }

        return full;
    },

    
    initDone: function (full, componentChildrenDone, containerChildrenDone, containerLayoutDone) {
        var me = this,
            props = me.props,
            state = me.state;

        
        if (componentChildrenDone) {
            props.componentChildrenDone = true;
        }
        if (containerChildrenDone) {
            props.containerChildrenDone = true;
        }
        if (containerLayoutDone) {
            props.containerLayoutDone = true;
        }

        if (me.boxChildren && me.boxChildren.length && me.widthModel.shrinkWrap) {
            
            
            me.el.setWidth(10000);

            
            state.blocks = (state.blocks || 0) + 1;
        }
    },

    
    initAnimation: function() {
        var me = this,
            target = me.target,
            ownerCtContext = me.ownerCtContext;

        if (ownerCtContext && ownerCtContext.isTopLevel) {
            
            
            me.animatePolicy = target.ownerLayout.getAnimatePolicy(me);
        } else if (!ownerCtContext && target.isCollapsingOrExpanding && target.animCollapse) {
            
            
            
            me.animatePolicy = target.componentLayout.getAnimatePolicy(me);
        }

        if (me.animatePolicy) {
            me.context.queueAnimation(me);
        }
    },

    noFraming: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 },

    
    addCls: function(newCls) {
        this.getClassList().addMany(newCls);
    },

    
    removeCls: function(removeCls) {
        this.getClassList().removeMany(removeCls);
    },

    
    addBlock: function (name, layout, propName) {
        var me = this,
            collection = me[name] || (me[name] = {}),
            blockedLayouts = collection[propName] || (collection[propName] = {});

        if (!blockedLayouts[layout.id]) {
            blockedLayouts[layout.id] = layout;
            ++layout.blockCount;
            ++me.context.blockCount;
        }
    },

    addBoxChild: function (boxChildItem) {
        var me = this,
            children,
            widthModel = boxChildItem.widthModel;

        boxChildItem.boxParent = this;

        
        
        
        
        
        
        boxChildItem.measuresBox = widthModel.shrinkWrap ? boxChildItem.hasRawContent : widthModel.natural;

        if (boxChildItem.measuresBox) {
            children = me.boxChildren;

            if (children) {
                children.push(boxChildItem);
            } else {
                me.boxChildren = [ boxChildItem ];
            }
        }
    },

    
    addTrigger: function (propName, inDom) {
        var me = this,
            name = inDom ? 'domTriggers' : 'triggers',
            collection = me[name] || (me[name] = {}),
            context = me.context,
            layout = context.currentLayout,
            triggers = collection[propName] || (collection[propName] = {});

        if (!triggers[layout.id]) {
            triggers[layout.id] = layout;
            ++layout.triggerCount;

            triggers = context.triggers[inDom ? 'dom' : 'data'];
            (triggers[layout.id] || (triggers[layout.id] = [])).push({
                item: this,
                prop: propName
            });

            if (me.props[propName] !== undefined) {
                if (!inDom || !(me.dirty && (propName in me.dirty))) {
                    ++layout.firedTriggers;
                }
            }
        }
    },

    boxChildMeasured: function () {
        var me = this,
            state = me.state,
            count = (state.boxesMeasured = (state.boxesMeasured || 0) + 1);

        if (count == me.boxChildren.length) {
            
            
            state.clearBoxWidth = 1;
            ++me.context.progressCount;
            me.markDirty();
        }
    },

    borderNames: [ 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width'],
    marginNames: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ],
    paddingNames: [ 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' ],
    trblNames: [ 'top', 'right', 'bottom', 'left' ],

    cacheMissHandlers: {
        borderInfo: function (me) {
            var info = me.getStyles(me.borderNames, me.trblNames);

            info.width = info.left + info.right;
            info.height = info.top + info.bottom;

            return info;
        },

        marginInfo: function (me) {
            var info = me.getStyles(me.marginNames, me.trblNames);

            info.width = info.left + info.right;
            info.height = info.top + info.bottom;

            return info;
        },

        paddingInfo: function (me) {
            
            var item = me.frameBodyContext || me,
                info = item.getStyles(me.paddingNames, me.trblNames);

            info.width = info.left + info.right;
            info.height = info.top + info.bottom;

            return info;
        }
    },

    checkCache: function (entry) {
        return this.cacheMissHandlers[entry](this);
    },

    clearAllBlocks: function (name) {
        var collection = this[name],
            propName;

        if (collection) {
            for (propName in collection) {
                this.clearBlocks(name, propName);
            }
        }
    },

    
    clearBlocks: function (name, propName) {
        var collection = this[name],
            blockedLayouts = collection && collection[propName],
            context, layout, layoutId;

        if (blockedLayouts) {
            delete collection[propName];

            context = this.context;

            for (layoutId in blockedLayouts) {
                layout = blockedLayouts[layoutId];

                --context.blockCount;
                if (! --layout.blockCount && !layout.pending && !layout.done) {
                    context.queueLayout(layout);
                }
            }
        }
    },

    
    block: function (layout, propName) {
        this.addBlock('blocks', layout, propName);
    },

    
    domBlock: function (layout, propName) {
        this.addBlock('domBlocks', layout, propName);
    },

    
    fireTriggers: function (name, propName) {
        var collection = this[name],
            triggers = collection && collection[propName],
            context = this.context,
            layout, layoutId;

        if (triggers) {
            for (layoutId in triggers) {
                layout = triggers[layoutId];
                ++layout.firedTriggers;
                if (!layout.done && !layout.blockCount && !layout.pending) {
                    context.queueLayout(layout);
                }
            }
        }
    },

    
    flush: function () {
        var me = this,
            dirty = me.dirty,
            state = me.state,
            targetEl = me.el;

        me.dirtyCount = 0;

        
        if (me.classList && me.classList.dirty) {
            me.classList.flush();
        }

        
        if ('attributes' in me) {
            targetEl.set(me.attributes);
            delete me.attributes;
        }

        
        if ('innerHTML' in me) {
            targetEl.innerHTML = me.innerHTML;
            delete me.innerHTML;
        }

        if (state && state.clearBoxWidth) {
            state.clearBoxWidth = 0;
            me.el.setStyle('width', null);

            if (! --state.blocks) {
                me.context.queueItemLayouts(me);
            }
        }

        if (dirty) {
            delete me.dirty;
            me.writeProps(dirty, true);
        }
    },

    
    flushAnimations: function() {
        var me = this,
            animateFrom = me.lastBox,
            target, targetAnim, duration, animateProps, anim,
            changeCount, j, propsLen, propName, oldValue, newValue;

        
        if (animateFrom) {
            target = me.target;
            targetAnim = target.layout && target.layout.animate;
            if (targetAnim) {
                duration = Ext.isNumber(targetAnim) ? targetAnim : targetAnim.duration;
            }
            animateProps = Ext.Object.getKeys(me.animatePolicy);

            
            
            anim = Ext.apply({}, {
                from: {},
                to: {},
                duration: duration || Ext.fx.Anim.prototype.duration
            }, targetAnim);

            for (changeCount = 0, j = 0, propsLen = animateProps.length; j < propsLen; j++) {
                propName = animateProps[j];
                oldValue = animateFrom[propName];
                newValue = me.peek(propName);
                if (oldValue != newValue) {
                    propName = me.translateProps[propName]||propName;
                    anim.from[propName] = oldValue;
                    anim.to[propName] = newValue;
                    ++changeCount;
                }
            }

            
            if (changeCount) {
                
                if (me.isCollapsingOrExpanding === 1) {
                    target.componentLayout.undoLayout(me);
                }

                
                else {
                    me.writeProps(anim.from);
                }
                me.el.animate(anim);
                
                Ext.fx.Manager.getFxQueue(me.el.id)[0].on({
                    afteranimate: function() {
                        if (me.isCollapsingOrExpanding === 1) {
                            target.componentLayout.redoLayout(me);
                            target.afterCollapse(true);
                        } else if (me.isCollapsingOrExpanding === 2) {
                            target.afterExpand(true);
                        }
                    }
                });
            }
        }
    },

    
    getBorderInfo: function () {
        var me = this,
            info = me.borderInfo;

        if (!info) {
            me.borderInfo = info = me.checkCache('borderInfo');
        }

        return info;
    },

    
    getClassList: function () {
        return this.classList || (this.classList = new Ext.layout.ClassList(this));
    },

    
    getEl: function (nameOrEl, owner) {
        var me = this,
            src, el, elContext;

        if (nameOrEl) {
            if (nameOrEl.dom) {
                el = nameOrEl;
            } else {
                src = me.target;
                if (owner) {
                    src = owner;
                }

                el = src[nameOrEl];
                if (typeof el == 'function') { 
                    el = el.call(src);
                    if (el === me.el) {
                        return this; 
                    }
                }
            }

            if (el) {
                elContext = me.context.getEl(me, el);
            }
        }

        return elContext || null;
    },

    getFraming: function () {
        var me = this;
        if (!me.framingInfo) {
            me.framingInfo = me.target.frameSize || me.noFraming;
        }
        return me.framingInfo;
    },

    
    getFrameInfo: function () {
        var me = this,
            info = me.frameInfo,
            frame, border;

        if (!info) {
            frame = me.getFraming();
            border = me.getBorderInfo();
            
            me.frameInfo = info = {
                top   : frame.top    + border.top,
                right : frame.right  + border.right,
                bottom: frame.bottom + border.bottom,
                left  : frame.left   + border.left,
                width : frame.width  + border.width,
                height: frame.height + border.height
            };
        }

        return info;
    },

    
    getMarginInfo: function () {
        var me = this,
            info = me.marginInfo,
            comp, manageMargins, margins, ownerLayout, ownerLayoutId;

        if (!info) {
            if (!me.wrapsComponent) {
                info = me.checkCache('marginInfo');
            } else {
                comp = me.target;
                ownerLayout = comp.ownerLayout;
                ownerLayoutId = ownerLayout ? ownerLayout.id : null;
                manageMargins = ownerLayout && ownerLayout.manageMargins;

                
                
                
                
                
                
                
                
                

                
                
                
                

                info = comp.margin$;
                if (info && info.ownerId !== ownerLayoutId) {
                    
                    info = null;

                    
                    
                    
                }

                if (!info) { 
                    
                    info = me.parseMargins(comp.margin) || me.checkCache('marginInfo');

                    
                    if (manageMargins) {
                        margins = me.parseMargins(comp.margins, ownerLayout.defaultMargins);

                        if (margins) { 
                            
                            info = {
                                top:    info.top    + margins.top,
                                right:  info.right  + margins.right,
                                bottom: info.bottom + margins.bottom,
                                left:   info.left   + margins.left
                            };
                        }

                        me.setProp('margin-top', 0);
                        me.setProp('margin-right', 0);
                        me.setProp('margin-bottom', 0);
                        me.setProp('margin-left', 0);
                    }

                    
                    info.ownerId = ownerLayoutId;
                    comp.margin$ = info;
                }

                info.width  = info.left + info.right;
                info.height = info.top  + info.bottom;
            }

            me.marginInfo = info;
        }

        return info;
    },

    
    clearMarginCache: function() {
        delete this.marginInfo;
        delete this.target.margin$;
    },

    
    getPaddingInfo: function () {
        var me = this,
            info = me.paddingInfo;

        if (!info) {
            me.paddingInfo = info = me.checkCache('paddingInfo');
        }

        return info;
    },

    
    getProp: function (propName) {
        var me = this,
            result = me.props[propName];

        me.addTrigger(propName);
        return result;
    },

    
    getDomProp: function (propName) {
        var me = this,
            result = (me.dirty && (propName in me.dirty)) ? undefined : me.props[propName];

        me.addTrigger(propName, true);
        return result;
    },

    
    getStyle: function (styleName) {
        var me = this,
            styles = me.styles,
            info, value;

        if (styleName in styles) {
            value = styles[styleName];
        } else {
            info = me.styleInfo[styleName];
            value = me.el.getStyle(styleName);

            if (info && info.parseInt) {
                value = parseInt(value, 10) || 0;
            }

            styles[styleName] = value;
        }

        return value;
    },

    
    getStyles: function (styleNames, altNames) {
        var me = this,
            styleCache = me.styles,
            values = {},
            hits = 0,
            n = styleNames.length,
            i, missing, missingAltNames, name, info, styleInfo, styles, value;

        altNames = altNames || styleNames;

        
        
        for (i = 0; i < n; ++i) {
            name = styleNames[i];

            if (name in styleCache) {
                values[altNames[i]] = styleCache[name];
                ++hits;

                if (i && hits==1) { 
                    missing = styleNames.slice(0, i);
                    missingAltNames = altNames.slice(0, i);
                }
            } else if (hits) {
                (missing || (missing = [])).push(name);
                (missingAltNames || (missingAltNames = [])).push(altNames[i]);
            }
        }

        if (hits < n) {
            missing = missing || styleNames;
            missingAltNames = missingAltNames || altNames;
            styleInfo = me.styleInfo;

            styles = me.el.getStyle(missing);

            for (i = missing.length; i--; ) {
                name = missing[i];
                info = styleInfo[name];
                value = styles[name];

                if (info && info.parseInt) {
                    value = parseInt(value, 10) || 0;
                }

                values[missingAltNames[i]] = value;
                styleCache[name] = value;
            }
        }

        return values;
    },

    
    hasProp: function (propName) {
        var value = this.getProp(propName);
        return typeof value != 'undefined';
    },

    
    hasDomProp: function (propName) {
        var value = this.getDomProp(propName);
        return typeof value != 'undefined';
    },

    
    invalidate: function (options) {
        this.context.queueInvalidate(this, options);
    },

    markDirty: function () {
        if (++this.dirtyCount == 1) {
            
            this.context.queueFlush(this);
        }
    },

    onBoxMeasured: function () {
        var boxParent = this.boxParent,
            state = this.state;

        if (boxParent && boxParent.widthModel.shrinkWrap && !state.boxMeasured && this.measuresBox) {
            
            
            state.boxMeasured = 1; 
            boxParent.boxChildMeasured();
        }
    },

    parseMargins: function (margins, defaultMargins) {
        if (margins === true) {
            margins = 5;
        }

        var type = typeof margins,
            ret;

        if (type == 'string' || type == 'number') {
            ret = Ext.util.Format.parseBox(margins);
        } else if (margins || defaultMargins) {
            ret = { top: 0, right: 0, bottom: 0, left: 0 }; 

            if (defaultMargins) {
                Ext.apply(ret, this.parseMargins(defaultMargins)); 
            }

            Ext.apply(ret, margins); 
        }

        return ret;
    },

    peek: function (propName) {
        return this.props[propName];
    },

    
    recoverProp: function (propName, oldProps, oldDirty) {
        var me = this,
            props = me.props,
            dirty;

        if (propName in oldProps) {
            props[propName] = oldProps[propName];

            if (oldDirty && propName in oldDirty) {
                dirty = me.dirty || (me.dirty = {});
                dirty[propName] = oldDirty[propName];
            }
        }
    },

    redo: function(deep) {
        var me = this,
            items, len, i;

        me.revertProps(me.props);

        if (deep && me.wrapsComponent) {
            
            if (me.childItems) {
                for (i = 0, items = me.childItems, len = items.length; i < len; i++) {
                    items[i].redo(deep);
                }
            }

            
            for (i = 0, items = me.children, len = items.length; i < len; i++) {
                items[i].redo();
            }
        }
    },

    revertProps: function (props) {
        var name,
            flushed = this.flushedProps,
            reverted = {};

        for (name in props) {
            if (flushed.hasOwnProperty(name)) {
                reverted[name] = props[name];
            }
        }

        this.writeProps(reverted);
    },

    
    setAttribute: function(name, value) {
        var me = this;
        if (!me.attributes) {
            me.attributes = {};
        }
        me.attributes[name] = value;
        me.markDirty();
    },

    setBox: function (box) {
        var me = this;

        if ('left' in box) {
            me.setProp('x', box.left);
        }
        if ('top' in box) {
            me.setProp('y', box.top);
        }

        
        
        
        me.setSize(box.width, box.height);
    },

    
    setContentHeight: function (height, measured) {
        if (!measured && this.hasRawContent) {
            return 1;
        }

        return this.setProp('contentHeight', height);
    },

    
    setContentWidth: function (width, measured) {
        if (!measured && this.hasRawContent) {
            return 1;
        }

        return this.setProp('contentWidth', width);
    },

    
    setContentSize: function (width, height, measured) {
        return this.setContentWidth(width, measured) +
               this.setContentHeight(height, measured) == 2;
    },

    
    setProp: function (propName, value, dirty) {
        var me = this,
            valueType = typeof value,
            borderBox, info;

        if (valueType == 'undefined' || (valueType === 'number' && isNaN(value))) {
            return 0;
        }
        if (me.props[propName] === value) {
            return 1;
        }

        me.props[propName] = value;
        ++me.context.progressCount;

        if (dirty === false) {
            
            
            me.fireTriggers('domTriggers', propName);
            me.clearBlocks('domBlocks', propName);
        } else {
            info = me.styleInfo[propName];
            if (info) {
                if (!me.dirty) {
                    me.dirty = {};
                }

                if (propName == 'width' || propName == 'height') {
                    borderBox = me.isBorderBoxValue;
                    if (borderBox == null) {
                        me.isBorderBoxValue = borderBox = !!me.el.isBorderBox();
                    }

                    if (!borderBox) {
                        me.borderInfo || me.getBorderInfo();
                        me.paddingInfo || me.getPaddingInfo();
                    }
                }
                me.dirty[propName] = value;
                me.markDirty();
            }
        }

        
        me.fireTriggers('triggers', propName);
        me.clearBlocks('blocks', propName);
        return 1;
    },

    
    setHeight: function (height, dirty ) {
        var me = this,
            comp = me.target,
            frameBody, frameInfo, padding;

        if (height < 0) {
            height = 0;
        }
        if (!me.wrapsComponent) {
            if (!me.setProp('height', height, dirty)) {
                return NaN;
            }
        } else {
            height = Ext.Number.constrain(height, comp.minHeight || 0, comp.maxHeight);
            if (!me.setProp('height', height, dirty)) {
                return NaN;
            }

            frameBody = me.frameBodyContext;
            if (frameBody){
                frameInfo = me.getFrameInfo();
                frameBody.setHeight(height - frameInfo.height, dirty);
            }
        }

        return height;
    },

    
    setWidth: function (width, dirty ) {
        var me = this,
            comp = me.target,
            frameBody, frameInfo, padding;

        if (width < 0) {
            width = 0;
        }
        if (!me.wrapsComponent) {
            if (!me.setProp('width', width, dirty)) {
                return NaN;
            }
        } else {
            width = Ext.Number.constrain(width, comp.minWidth || 0, comp.maxWidth);
            if (!me.setProp('width', width, dirty)) {
                return NaN;
            }

            
            frameBody = me.frameBodyContext;
            if (frameBody) {
                frameInfo = me.getFrameInfo();
                frameBody.setWidth(width - frameInfo.width, dirty);
            }

            
        }

        return width;
    },

    setSize: function (width, height, dirty) {
        this.setWidth(width, dirty);
        this.setHeight(height, dirty);
    },

    translateProps: {
        x: 'left',
        y: 'top'
    },

    undo: function(deep) {
        var me = this,
            items, len, i;

        me.revertProps(me.lastBox);

        if (deep && me.wrapsComponent) {
            
            if (me.childItems) {
                for (i = 0, items = me.childItems, len = items.length; i < len; i++) {
                    items[i].undo(deep);
                }
            }

            
            for (i = 0, items = me.children, len = items.length; i < len; i++) {
                items[i].undo();
            }
        }
    },

    unsetProp: function (propName) {
        var dirty = this.dirty;

        delete this.props[propName];
        if (dirty) {
            delete dirty[propName];
        }
    },

    writeProps: function(dirtyProps, flushing) {
        if (!(dirtyProps && typeof dirtyProps == 'object')) {
            return;
        }

        var me = this,
            el = me.el,
            styles = {},
            styleCount = 0, 
            styleInfo = me.styleInfo,
            
            info,
            propName,
            numericValue,
            
            dirtyX = 'x' in dirtyProps,
            dirtyY = 'y' in dirtyProps,
            x = dirtyProps.x,
            y = dirtyProps.y,
            
            width = dirtyProps.width,
            height = dirtyProps.height,
            isBorderBox = me.isBorderBoxValue,
            target = me.target,
            max = Math.max,
            paddingWidth = 0,
            paddingHeight = 0,
            hasWidth, hasHeight, isAbsolute, scrollbarSize, style, targetEl;

        
        if ('displayed' in dirtyProps) {
            el.setDisplayed(dirtyProps.displayed);
        }

        
        for (propName in dirtyProps) {
            if (flushing) {
                me.fireTriggers('domTriggers', propName);
                me.clearBlocks('domBlocks', propName);
                me.flushedProps[propName] = 1;
            }

            info = styleInfo[propName];
            if (info && info.dom) {
                
                if (info.suffix && (numericValue = parseInt(dirtyProps[propName], 10))) {
                    styles[propName] = numericValue + info.suffix;
                }
                
                else {
                    styles[propName] = dirtyProps[propName];
                }
                ++styleCount;
            }
        }

        
        if (dirtyX || dirtyY) {
            if (target.isComponent) {
                
                target.setPosition(x||me.props.x, y||me.props.y);
            } else {
                
                if (dirtyX) {
                    styles.left = x + 'px';
                    ++styleCount;
                }
                if (dirtyY) {
                    styles.top = y + 'px';
                    ++styleCount;
                }
            }
        }

        
        if (!isBorderBox && (width > 0 || height > 0)) { 
            
            
            if(!me.frameBodyContext) {
                
                paddingWidth = me.paddingInfo.width;
                paddingHeight = me.paddingInfo.height;
            }
            if (width) {
                width = max(parseInt(width, 10) - (me.borderInfo.width + paddingWidth), 0);
                styles.width = width + 'px';
                ++styleCount;
            }
            if (height) {
                height = max(parseInt(height, 10) - (me.borderInfo.height + paddingHeight), 0);
                styles.height = height + 'px';
                ++styleCount;
            }
        }

        
        
        
        
        
        
        if (me.wrapsComponent && Ext.isIE9 && Ext.isStrict) {
            
            
            if ((hasWidth = width !== undefined && me.hasOverflowY) ||
                (hasHeight = height !== undefined && me.hasOverflowX)) {
                
                isAbsolute = me.isAbsolute;
                if (isAbsolute === undefined) {
                    isAbsolute = false;
                    targetEl = me.target.getTargetEl();
                    style = targetEl.getStyle('position');

                    if (style == 'absolute') {
                        style = targetEl.getStyle('box-sizing');
                        isAbsolute = (style == 'border-box');
                    }

                    me.isAbsolute = isAbsolute; 
                }

                if (isAbsolute) {
                    scrollbarSize = Ext.getScrollbarSize();

                    if (hasWidth) {
                        width = parseInt(width, 10) + scrollbarSize.width;
                        styles.width = width + 'px';
                        ++styleCount;
                    }
                    if (hasHeight) {
                        height = parseInt(height, 10) + scrollbarSize.height;
                        styles.height = height + 'px';
                        ++styleCount;
                    }
                }
            }
        }

        
        if (styleCount) {
            el.setStyle(styles);
        }
    }
}, function () {
    
    var px =    { dom: true, parseInt: true, suffix: 'px' },
        isDom = { dom: true },
        faux =  { dom: false };

    
    
    
    
    
    
    
    
    this.prototype.styleInfo = {
        childrenDone:           faux,
        componentChildrenDone:  faux,
        containerChildrenDone:  faux,
        containerLayoutDone:    faux,
        displayed:              faux,
        done:                   faux,
        x:                      faux,
        y:                      faux,

        
        columnWidthsDone:       faux,

        left:                   px,
        top:                    px,
        right:                  px,
        bottom:                 px,
        width:                  px,
        height:                 px,

        'border-top-width':     px,
        'border-right-width':   px,
        'border-bottom-width':  px,
        'border-left-width':    px,

        'margin-top':           px,
        'margin-right':         px,
        'margin-bottom':        px,
        'margin-left':          px,

        'padding-top':          px,
        'padding-right':        px,
        'padding-bottom':       px,
        'padding-left':         px,

        'line-height':          isDom,
        display:                isDom
    };
});


Ext.define('Ext.util.Bindable', {
    
    
    bindStore: function(store, initial){
        var me = this,
            oldStore = me.store;
        
        if (!initial && me.store) {
            
            me.onUnbindStore(oldStore, initial);

            if (store !== oldStore && oldStore.autoDestroy) {
                oldStore.destroyStore();
            } else {
                me.unbindStoreListeners(oldStore);
            }
        }
        if (store) {
            store = Ext.data.StoreManager.lookup(store);
            me.bindStoreListeners(store);
            me.onBindStore(store, initial);
        }
        me.store = store || null;
        return me;
    },
    
    
    getStore: function(){
        return this.store;
    },
    
    
    unbindStoreListeners: function(store) {
        
        var listeners = this.storeListeners;
        if (listeners) {
            store.un(listeners);
        }
    },
    
    
    bindStoreListeners: function(store) {
        
        var me = this,
            listeners = Ext.apply({}, me.getStoreListeners());
            
        if (!listeners.scope) {
            listeners.scope = me;
        }
        me.storeListeners = listeners;
        store.on(listeners);
    },
    
    
    getStoreListeners: Ext.emptyFn,
    
    
    onUnbindStore: Ext.emptyFn,
    
    
    onBindStore: Ext.emptyFn    
});


Ext.define('Ext.util.ElementContainer', {

    childEls: [
        
        
        
        
    ],

    constructor: function () {
        var me = this,
            childEls;

        
        
        if (me.hasOwnProperty('childEls')) {
            childEls = me.childEls;
            delete me.childEls;

            me.addChildEls.apply(me, childEls);
        }
    },

    destroy: function () {
        var me = this,
            childEls = me.getChildEls(),
            child, childName, i, k;

        for (i = childEls.length; i--; ) {
            childName = childEls[i];
            if (typeof childName != 'string') {
                childName = childName.name;
            }

            child = me[childName];
            if (child) {
                me[childName] = null; 
                child.remove();
            }
        }
    },

    
    addChildEls: function () {
        var me = this,
            args = arguments;

        if (me.hasOwnProperty('childEls')) {
            me.childEls.push.apply(me.childEls, args);
        } else {
            me.childEls = me.getChildEls().concat(Array.prototype.slice.call(args));
        }
        
        me.prune(me.childEls, false);
    },

    
    applyChildEls: function(el, id) {
        var me = this,
            childEls = me.getChildEls(),
            baseId, childName, i, selector, value;

        baseId = (id || me.id) + '-';
        for (i = childEls.length; i--; ) {
            childName = childEls[i];

            if (typeof childName == 'string') {
                
                
                value = el.getById(baseId + childName);
            } else {
                if ((selector = childName.select)) {
                    value = Ext.select(selector, true, el.dom); 
                } else if ((selector = childName.selectNode)) {
                    value = Ext.get(Ext.DomQuery.selectNode(selector, el.dom));
                } else {
                    
                    value = el.getById(childName.id || (baseId + childName.itemId));
                }

                childName = childName.name;
            }

            me[childName] = value;
        }
    },

    getChildEls: function () {
        var me = this,
            self;

        
        if (me.hasOwnProperty('childEls')) {
            return me.childEls;
        }

        
        
        self = me.self;
        return self.$childEls || me.getClassChildEls(self);
    },

    getClassChildEls: function (cls) {
        var me = this,
            result = cls.$childEls,
            childEls, i, length, forked, mixin, mixins, name, parts, proto, supr, superMixins;

        if (!result) {
            
            
            

            supr = cls.superclass;
            if (supr) {
                supr = supr.self;
                parts = [supr.$childEls || me.getClassChildEls(supr)]; 
                superMixins = supr.prototype.mixins || {};
            } else {
                parts = [];
                superMixins = {};
            }

            proto = cls.prototype;
            mixins = proto.mixins; 
            for (name in mixins) {
                if (mixins.hasOwnProperty(name) && !superMixins.hasOwnProperty(name)) {
                    mixin = mixins[name].self;
                    parts.push(mixin.$childEls || me.getClassChildEls(mixin));
                }
            }

            parts.push(proto.hasOwnProperty('childEls') && proto.childEls);

            for (i = 0, length = parts.length; i < length; ++i) {
                childEls = parts[i];
                if (childEls && childEls.length) {
                    if (!result) {
                        result = childEls;
                    } else {
                        if (!forked) {
                            forked = true;
                            result = result.slice(0);
                        }
                        result.push.apply(result, childEls);
                    }
                }
            }

            cls.$childEls = result = (result ? me.prune(result, !forked) : []);
        }

        return result;
    },

    prune: function (childEls, shared) {
        var index = childEls.length,
            map = {},
            name;

        while (index--) {
            name = childEls[index];
            if (typeof name != 'string') {
                name = name.name;
            }

            if (!map[name]) {
                map[name] = 1;
            } else {
                if (shared) {
                    shared = false;
                    childEls = childEls.slice(0);
                }
                Ext.Array.erase(childEls, index, 1);
            }
        }

        return childEls;
    },

    
    removeChildEls: function (testFn) {
        var me = this,
            old = me.getChildEls(),
            keepers = (me.childEls = []),
            n, i, cel;

        for (i = 0, n = old.length; i < n; ++i) {
            cel = old[i];
            if (!testFn(cel)) {
                keepers.push(cel);
            }
        }
    }
});


Ext.define('Ext.util.Filter', {

    

    
    
    
    
    
    
    anyMatch: false,
    
    
    exactMatch: false,
    
    
    caseSensitive: false,
    
    

    
    constructor: function(config) {
        var me = this;
        Ext.apply(me, config);
        
        
        
        me.filter = me.filter || me.filterFn;
        
        if (me.filter === undefined) {
            if (me.property === undefined || me.value === undefined) {
                
                
                
                
            } else {
                me.filter = me.createFilterFn();
            }
            
            me.filterFn = me.filter;
        }
    },
    
    
    createFilterFn: function() {
        var me       = this,
            matcher  = me.createValueMatcher(),
            property = me.property;
        
        return function(item) {
            var value = me.getRoot.call(me, item)[property];
            return matcher === null ? value === null : matcher.test(value);
        };
    },
    
    
    getRoot: function(item) {
        var root = this.root;
        return root === undefined ? item : item[root];
    },
    
    
    createValueMatcher : function() {
        var me            = this,
            value         = me.value,
            anyMatch      = me.anyMatch,
            exactMatch    = me.exactMatch,
            caseSensitive = me.caseSensitive,
            escapeRe      = Ext.String.escapeRegex;
            
        if (value === null) {
            return value;
        }
        
        if (!value.exec) { 
            value = String(value);

            if (anyMatch === true) {
                value = escapeRe(value);
            } else {
                value = '^' + escapeRe(value);
                if (exactMatch === true) {
                    value += '$';
                }
            }
            value = new RegExp(value, caseSensitive ? '' : 'i');
         }
         
         return value;
    }
});

Ext.define('Ext.util.Inflector', {

    

    singleton: true,

    

    
    plurals: [
        [(/(quiz)$/i),                "$1zes"  ],
        [(/^(ox)$/i),                 "$1en"   ],
        [(/([m|l])ouse$/i),           "$1ice"  ],
        [(/(matr|vert|ind)ix|ex$/i),  "$1ices" ],
        [(/(x|ch|ss|sh)$/i),          "$1es"   ],
        [(/([^aeiouy]|qu)y$/i),       "$1ies"  ],
        [(/(hive)$/i),                "$1s"    ],
        [(/(?:([^f])fe|([lr])f)$/i),  "$1$2ves"],
        [(/sis$/i),                   "ses"    ],
        [(/([ti])um$/i),              "$1a"    ],
        [(/(buffal|tomat|potat)o$/i), "$1oes"  ],
        [(/(bu)s$/i),                 "$1ses"  ],
        [(/(alias|status|sex)$/i),    "$1es"   ],
        [(/(octop|vir)us$/i),         "$1i"    ],
        [(/(ax|test)is$/i),           "$1es"   ],
        [(/^person$/),                "people" ],
        [(/^man$/),                   "men"    ],
        [(/^(child)$/),               "$1ren"  ],
        [(/s$/i),                     "s"      ],
        [(/$/),                       "s"      ]
    ],

    
    singulars: [
      [(/(quiz)zes$/i),                                                    "$1"     ],
      [(/(matr)ices$/i),                                                   "$1ix"   ],
      [(/(vert|ind)ices$/i),                                               "$1ex"   ],
      [(/^(ox)en/i),                                                       "$1"     ],
      [(/(alias|status)es$/i),                                             "$1"     ],
      [(/(octop|vir)i$/i),                                                 "$1us"   ],
      [(/(cris|ax|test)es$/i),                                             "$1is"   ],
      [(/(shoe)s$/i),                                                      "$1"     ],
      [(/(o)es$/i),                                                        "$1"     ],
      [(/(bus)es$/i),                                                      "$1"     ],
      [(/([m|l])ice$/i),                                                   "$1ouse" ],
      [(/(x|ch|ss|sh)es$/i),                                               "$1"     ],
      [(/(m)ovies$/i),                                                     "$1ovie" ],
      [(/(s)eries$/i),                                                     "$1eries"],
      [(/([^aeiouy]|qu)ies$/i),                                            "$1y"    ],
      [(/([lr])ves$/i),                                                    "$1f"    ],
      [(/(tive)s$/i),                                                      "$1"     ],
      [(/(hive)s$/i),                                                      "$1"     ],
      [(/([^f])ves$/i),                                                    "$1fe"   ],
      [(/(^analy)ses$/i),                                                  "$1sis"  ],
      [(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i), "$1$2sis"],
      [(/([ti])a$/i),                                                      "$1um"   ],
      [(/(n)ews$/i),                                                       "$1ews"  ],
      [(/people$/i),                                                       "person" ],
      [(/s$/i),                                                            ""       ]
    ],

    
     uncountable: [
        "sheep",
        "fish",
        "series",
        "species",
        "money",
        "rice",
        "information",
        "equipment",
        "grass",
        "mud",
        "offspring",
        "deer",
        "means"
    ],

    
    singular: function(matcher, replacer) {
        this.singulars.unshift([matcher, replacer]);
    },

    
    plural: function(matcher, replacer) {
        this.plurals.unshift([matcher, replacer]);
    },

    
    clearSingulars: function() {
        this.singulars = [];
    },

    
    clearPlurals: function() {
        this.plurals = [];
    },

    
    isTransnumeral: function(word) {
        return Ext.Array.indexOf(this.uncountable, word) != -1;
    },

    
    pluralize: function(word) {
        if (this.isTransnumeral(word)) {
            return word;
        }

        var plurals = this.plurals,
            length  = plurals.length,
            tuple, regex, i;

        for (i = 0; i < length; i++) {
            tuple = plurals[i];
            regex = tuple[0];

            if (regex == word || (regex.test && regex.test(word))) {
                return word.replace(regex, tuple[1]);
            }
        }

        return word;
    },

    
    singularize: function(word) {
        if (this.isTransnumeral(word)) {
            return word;
        }

        var singulars = this.singulars,
            length    = singulars.length,
            tuple, regex, i;

        for (i = 0; i < length; i++) {
            tuple = singulars[i];
            regex = tuple[0];

            if (regex == word || (regex.test && regex.test(word))) {
                return word.replace(regex, tuple[1]);
            }
        }

        return word;
    },

    
    classify: function(word) {
        return Ext.String.capitalize(this.singularize(word));
    },

    
    ordinalize: function(number) {
        var parsed = parseInt(number, 10),
            mod10  = parsed % 10,
            mod100 = parsed % 100;

        
        if (11 <= mod100 && mod100 <= 13) {
            return number + "th";
        } else {
            switch(mod10) {
                case 1 : return number + "st";
                case 2 : return number + "nd";
                case 3 : return number + "rd";
                default: return number + "th";
            }
        }
    }
}, function() {
    
    var irregulars = {
            alumnus: 'alumni',
            cactus : 'cacti',
            focus  : 'foci',
            nucleus: 'nuclei',
            radius: 'radii',
            stimulus: 'stimuli',
            ellipsis: 'ellipses',
            paralysis: 'paralyses',
            oasis: 'oases',
            appendix: 'appendices',
            index: 'indexes',
            beau: 'beaux',
            bureau: 'bureaux',
            tableau: 'tableaux',
            woman: 'women',
            child: 'children',
            man: 'men',
            corpus:	'corpora',
            criterion: 'criteria',
            curriculum:	'curricula',
            genus: 'genera',
            memorandum:	'memoranda',
            phenomenon:	'phenomena',
            foot: 'feet',
            goose: 'geese',
            tooth: 'teeth',
            antenna: 'antennae',
            formula: 'formulae',
            nebula: 'nebulae',
            vertebra: 'vertebrae',
            vita: 'vitae'
        },
        singular;

    for (singular in irregulars) {
        this.plural(singular, irregulars[singular]);
        this.singular(irregulars[singular], singular);
    }
});

Ext.define('Ext.util.Memento', (function () {

    function captureOne (src, target, prop, prefix) {
        src[prefix ? prefix + prop : prop] = target[prop];
    }

    function removeOne (src, target, prop) {
        delete src[prop];
    }

    function restoreOne (src, target, prop, prefix) {
        var name = prefix ? prefix + prop : prop,
            value = src[name];

        if (value || src.hasOwnProperty(name)) {
            restoreValue(target, prop, value);
        }
    }

    function restoreValue (target, prop, value) {
        if (Ext.isDefined(value)) {
            target[prop] = value;
        } else {
            delete target[prop];
        }
    }

    function doMany (doOne, src, target, props, prefix) {
        if (src) {
            if (Ext.isArray(props)) {
                var p, pLen = props.length;
                for (p = 0; p < pLen; p++) {
                    doOne(src, target, props[p], prefix);
                }
            } else {
                doOne(src, target, props, prefix);
            }
        }
    }

    return {
        
        data: null,

        
        target: null,

        
        constructor: function (target, props) {
            if (target) {
                this.target = target;
                if (props) {
                    this.capture(props);
                }
            }
        },

        
        capture: function (props, target, prefix) {
            var me = this;
            doMany(captureOne, me.data || (me.data = {}), target || me.target, props, prefix);
        },

        
        remove: function (props) {
            doMany(removeOne, this.data, null, props);
        },

        
        restore: function (props, clear, target, prefix) {
            doMany(restoreOne, this.data, target || this.target, props, prefix);
            if (clear !== false) {
                this.remove(props);
            }
        },

        
        restoreAll: function (clear, target) {
            var me   = this,
                t    = target || this.target,
                data = me.data,
                prop;

            for (prop in data) {
                if (data.hasOwnProperty(prop)) {
                    restoreValue(t, prop, data[prop]);
                }
            }

            if (clear !== false) {
                delete me.data;
            }
        }
    };
}()));


Ext.define('Ext.util.Observable', {

    

    requires: ['Ext.util.Event'],

    statics: {
        
        releaseCapture: function(o) {
            o.fireEvent = this.prototype.fireEvent;
        },

        
        capture: function(o, fn, scope) {
            o.fireEvent = Ext.Function.createInterceptor(o.fireEvent, fn, scope);
        },

        
        observe: function(cls, listeners) {
            if (cls) {
                if (!cls.isObservable) {
                    Ext.applyIf(cls, new this());
                    this.capture(cls.prototype, cls.fireEvent, cls);
                }
                if (Ext.isObject(listeners)) {
                    cls.on(listeners);
                }
            }
            return cls;
        },

        
        prepareClass: function (T, mixin) {
            
            

            
            

            if (!T.HasListeners) {
                
                
                
                var Observable = Ext.util.Observable,
                    HasListeners = function () {},
                    SuperHL = T.superclass.HasListeners || (mixin && mixin.HasListeners) ||
                              Observable.HasListeners;

                
                T.prototype.HasListeners = T.HasListeners = HasListeners;

                
                
                HasListeners.prototype = T.hasListeners = new SuperHL();
            }
        }
    },

    

    

    
    isObservable: true,

    
    eventsSuspended: 0,

    

    constructor: function(config) {
        var me = this;

        Ext.apply(me, config);

        
        if (!me.hasListeners) {
            me.hasListeners = new me.HasListeners();
        }

        me.events = me.events || {};
        if (me.listeners) {
            me.on(me.listeners);
            me.listeners = null; 
        }

        if (me.bubbleEvents) {
            me.enableBubble(me.bubbleEvents);
        }
    },

    onClassExtended: function (T) {
        if (!T.HasListeners) {
            
            
            Ext.util.Observable.prepareClass(T);
        }
    },

    
    eventOptionsRe : /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|element|vertical|horizontal|freezeEvent)$/,

    
    addManagedListener : function(item, ename, fn, scope, options) {
        var me = this,
            managedListeners = me.managedListeners = me.managedListeners || [],
            config;

        if (typeof ename !== 'string') {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.addManagedListener(item, ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
                    }
                }
            }
        }
        else {
            managedListeners.push({
                item: item,
                ename: ename,
                fn: fn,
                scope: scope,
                options: options
            });

            item.on(ename, fn, scope, options);
        }
    },

    
    removeManagedListener : function(item, ename, fn, scope) {
        var me = this,
            options,
            config,
            managedListeners,
            length,
            i;

        if (typeof ename !== 'string') {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.removeManagedListener(item, ename, config.fn || config, config.scope || options.scope);
                    }
                }
            }
        }

        managedListeners = me.managedListeners ? me.managedListeners.slice() : [];

        for (i = 0, length = managedListeners.length; i < length; i++) {
            me.removeManagedListenerItem(false, managedListeners[i], item, ename, fn, scope);
        }
    },

    
    fireEvent: function(eventName) {
        eventName = eventName.toLowerCase();
        var me = this,
            events = me.events,
            event = events && events[eventName],
            ret = true;

        
        
        if (event && me.hasListeners[eventName]) {
            ret = me.continueFireEvent(eventName, Ext.Array.slice(arguments, 1), event.bubble);
        }
        return ret;
    },

    
    continueFireEvent: function(eventName, args, bubbles) {
        var target = this,
            queue, event,
            ret = true;

        do {
            if (target.eventsSuspended) {
                if ((queue = target.eventQueue)) {
                    queue.push([eventName, args, bubbles]);
                }
                return ret;
            } else {
                event = target.events[eventName];
                
                
                if (event && event != true) {
                    if ((ret = event.fire.apply(event, args)) === false) {
                        break;
                    }
                }
            }
        } while (bubbles && (target = target.getBubbleParent()));
        return ret;
    },

    
    getBubbleParent: function(){
        var me = this, parent = me.getBubbleTarget && me.getBubbleTarget();
        if (parent && parent.isObservable) {
            return parent;
        }
        return null;
    },

    
    addListener: function(ename, fn, scope, options) {
        var me = this,
            config, event, hasListeners,
            prevListenerCount = 0;

        if (typeof ename !== 'string') {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.addListener(ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
                    }
                }
            }
        } else {
            ename = ename.toLowerCase();
            event = me.events[ename];
            if (event && event.isEvent) {
                prevListenerCount = event.listeners.length;
            } else {
                me.events[ename] = event = new Ext.util.Event(me, ename);
            }

            
            if (typeof fn === 'string') {
                fn = scope[fn] || me[fn];
            }
            event.addListener(fn, scope, options);

            
            
            if (event.listeners.length !== prevListenerCount) {
                hasListeners = me.hasListeners;
                if (hasListeners.hasOwnProperty(ename)) {
                    
                    ++hasListeners[ename];
                } else {
                    
                    
                    hasListeners[ename] = 1;
                }
            }
        }
    },

    
    removeListener: function(ename, fn, scope) {
        var me = this,
            config,
            event,
            options;

        if (typeof ename !== 'string') {
            options = ename;
            for (ename in options) {
                if (options.hasOwnProperty(ename)) {
                    config = options[ename];
                    if (!me.eventOptionsRe.test(ename)) {
                        me.removeListener(ename, config.fn || config, config.scope || options.scope);
                    }
                }
            }
        } else {
            ename = ename.toLowerCase();
            event = me.events[ename];
            if (event && event.isEvent) {
                if (event.removeListener(fn, scope) && !--me.hasListeners[ename]) {
                    
                    
                    
                    delete me.hasListeners[ename];
                }
            }
        }
    },

    
    clearListeners: function() {
        var events = this.events,
            event,
            key;

        for (key in events) {
            if (events.hasOwnProperty(key)) {
                event = events[key];
                if (event.isEvent) {
                    event.clearListeners();
                }
            }
        }

        this.clearManagedListeners();
    },


    
    clearManagedListeners : function() {
        var managedListeners = this.managedListeners || [],
            i = 0,
            len = managedListeners.length;

        for (; i < len; i++) {
            this.removeManagedListenerItem(true, managedListeners[i]);
        }

        this.managedListeners = [];
    },

    
    removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
        if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) {
            managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
            if (!isClear) {
                Ext.Array.remove(this.managedListeners, managedListener);
            }
        }
    },


    
    addEvents: function(o) {
        var me = this,
            events = me.events || (me.events = {}),
            arg, args, i;

        if (typeof o == 'string') {
            for (args = arguments, i = args.length; i--; ) {
                arg = args[i];
                if (!events[arg]) {
                    events[arg] = true;
                }
            }
        } else {
            Ext.applyIf(me.events, o);
        }
    },

    
    hasListener: function(ename) {
        return !!this.hasListeners[ename.toLowerCase()];
    },

    
    suspendEvents: function(queueSuspended) {
        this.eventsSuspended += 1;
        if (queueSuspended && !this.eventQueue) {
            this.eventQueue = [];
        }
    },

    
    resumeEvents: function() {
        var me = this,
            queued = me.eventQueue,
            qLen, q;

        if (me.eventsSuspended && ! --me.eventsSuspended) {
            delete me.eventQueue;

            if (queued) {
                qLen = queued.length;
                for (q = 0; q < qLen; q++) {
                    me.continueFireEvent.apply(me, queued[q]);
                }
            }
        }
    },

    
    relayEvents : function(origin, events, prefix) {
        var me = this,
            len = events.length,
            i = 0,
            oldName,
            newName;

        for (; i < len; i++) {
            oldName = events[i];
            newName = prefix ? prefix + oldName : oldName;

            
            me.mon(origin, oldName, me.createRelayer(newName));
        }
    },

    
    createRelayer: function(newName, beginEnd){
        var me = this;
        return function() {
            return me.fireEvent.apply(me, [newName].concat(Array.prototype.slice.apply(arguments, beginEnd || [0, -1])));
        };
    },

    
    enableBubble: function(eventNames) {
        if (eventNames) {
            var me = this,
                names = (typeof eventNames == 'string') ? arguments : eventNames,
                length = names.length,
                events = me.events,
                ename, event, i;

            for (i = 0; i < length; ++i) {
                ename = names[i].toLowerCase();
                event = events[ename];

                if (!event || typeof event == 'boolean') {
                    events[ename] = event = new Ext.util.Event(me, ename);
                }

                
                me.hasListeners[ename] = (me.hasListeners[ename]||0) + 1;

                event.bubble = true;
            }
        }
    }
}, function() {
    var Observable = this,
        proto = Observable.prototype,
        HasListeners = function () {},
        prepareMixin = function (T) {
            if (!T.HasListeners) {
                var proto = T.prototype;

                
                Observable.prepareClass(T, this);

                
                
                T.onExtended(function (U) {
                    Observable.prepareClass(U);
                });

                
                
                if (proto.onClassMixedIn) {
                    
                    Ext.override(T, {
                        onClassMixedIn: function (U) {
                            prepareMixin.call(this, U);
                            this.callParent(arguments);
                        }
                    });
                } else {
                    
                    proto.onClassMixedIn = function (U) {
                        prepareMixin.call(this, U);
                    };
                }
            }
        };

    HasListeners.prototype = {
        
    };

    proto.HasListeners = Observable.HasListeners = HasListeners;

    Observable.createAlias({
        
        on: 'addListener',
        
        un: 'removeListener',
        
        mon: 'addManagedListener',
        
        mun: 'removeManagedListener'
    });

    
    Observable.observeClass = Observable.observe;

    
    
    
    function getMethodEvent(method){
        var e = (this.methodEvents = this.methodEvents || {})[method],
            returnValue,
            v,
            cancel,
            obj = this,
            makeCall;

        if (!e) {
            this.methodEvents[method] = e = {};
            e.originalFn = this[method];
            e.methodName = method;
            e.before = [];
            e.after = [];

            makeCall = function(fn, scope, args){
                if((v = fn.apply(scope || obj, args)) !== undefined){
                    if (typeof v == 'object') {
                        if(v.returnValue !== undefined){
                            returnValue = v.returnValue;
                        }else{
                            returnValue = v;
                        }
                        cancel = !!v.cancel;
                    }
                    else
                        if (v === false) {
                            cancel = true;
                        }
                        else {
                            returnValue = v;
                        }
                }
            };

            this[method] = function(){
                var args = Array.prototype.slice.call(arguments, 0),
                    b, i, len;
                returnValue = v = undefined;
                cancel = false;

                for(i = 0, len = e.before.length; i < len; i++){
                    b = e.before[i];
                    makeCall(b.fn, b.scope, args);
                    if (cancel) {
                        return returnValue;
                    }
                }

                if((v = e.originalFn.apply(obj, args)) !== undefined){
                    returnValue = v;
                }

                for(i = 0, len = e.after.length; i < len; i++){
                    b = e.after[i];
                    makeCall(b.fn, b.scope, args);
                    if (cancel) {
                        return returnValue;
                    }
                }
                return returnValue;
            };
        }
        return e;
    }

    Ext.apply(proto, {
        onClassMixedIn: prepareMixin,

        
        
        
        beforeMethod : function(method, fn, scope){
            getMethodEvent.call(this, method).before.push({
                fn: fn,
                scope: scope
            });
        },

        
        afterMethod : function(method, fn, scope){
            getMethodEvent.call(this, method).after.push({
                fn: fn,
                scope: scope
            });
        },

        removeMethodListener: function(method, fn, scope){
            var e = this.getMethodEvent(method),
                i, len;
            for(i = 0, len = e.before.length; i < len; i++){
                if(e.before[i].fn == fn && e.before[i].scope == scope){
                    Ext.Array.erase(e.before, i, 1);
                    return;
                }
            }
            for(i = 0, len = e.after.length; i < len; i++){
                if(e.after[i].fn == fn && e.after[i].scope == scope){
                    Ext.Array.erase(e.after, i, 1);
                    return;
                }
            }
        },

        toggleEventLogging: function(toggle) {
            Ext.util.Observable[toggle ? 'capture' : 'releaseCapture'](this, function(en) {
                if (Ext.isDefined(Ext.global.console)) {
                    Ext.global.console.log(en, arguments);
                }
            });
        }
    });
});


Ext.define('Ext.util.Offset', {

    

    statics: {
        fromObject: function(obj) {
            return new this(obj.x, obj.y);
        }
    },

    

    constructor: function(x, y) {
        this.x = (x != null && !isNaN(x)) ? x : 0;
        this.y = (y != null && !isNaN(y)) ? y : 0;

        return this;
    },

    copy: function() {
        return new Ext.util.Offset(this.x, this.y);
    },

    copyFrom: function(p) {
        this.x = p.x;
        this.y = p.y;
    },

    toString: function() {
        return "Offset[" + this.x + "," + this.y + "]";
    },

    equals: function(offset) {

        return (this.x == offset.x && this.y == offset.y);
    },

    round: function(to) {
        if (!isNaN(to)) {
            var factor = Math.pow(10, to);
            this.x = Math.round(this.x * factor) / factor;
            this.y = Math.round(this.y * factor) / factor;
        } else {
            this.x = Math.round(this.x);
            this.y = Math.round(this.y);
        }
    },

    isZero: function() {
        return this.x == 0 && this.y == 0;
    }
});




Ext.define('Ext.util.ProtoElement', (function () {
    var splitWords = Ext.String.splitWords,
        toMap = Ext.Array.toMap;

    return {
        
        isProtoEl: true,
        
        
        clsProp: 'cls',

        
        styleProp: 'style',
        
        
        removedProp: 'removed',

        
        styleIsText: false,

        constructor: function (config) {
            var me = this;

            Ext.apply(me, config);

            me.classList = splitWords(me.cls);
            me.classMap = toMap(me.classList);
            delete me.cls;

            if (Ext.isFunction(me.style)) {
                me.styleFn = me.style;
                delete me.style;
            } else if (typeof me.style == 'string') {
                me.style = Ext.Element.parseStyles(me.style);
            } else if (me.style) {
                me.style = Ext.apply({}, me.style); 
            }
        },
        
        
        flush: function(){
            this.flushClassList = [];
            this.removedClasses = {};
            
            delete this.style;
        },

        
        addCls: function (cls) {
            var me = this,
                add = splitWords(cls),
                length = add.length,
                list = me.classList,
                map = me.classMap,
                flushList = me.flushClassList,
                i = 0,
                c;

            for (; i < length; ++i) {
                c = add[i];
                if (!map[c]) {
                    map[c] = true;
                    list.push(c);
                    if (flushList) {
                        flushList.push(c);
                        delete me.removedClasses[c];
                    }
                }
            }

            return me;
        },

        
        hasCls: function (cls) {
            return cls in this.classMap;
        },

        
        removeCls: function (cls) {
            var me = this,
                list = me.classList,
                newList = (me.classList = []),
                remove = toMap(splitWords(cls)),
                length = list.length,
                map = me.classMap,
                removedClasses = me.removedClasses,
                i, c;

            for (i = 0; i < length; ++i) {
                c = list[i];
                if (remove[c]) {
                    if (removedClasses) {
                        if (map[c]) {
                            removedClasses[c] = true;
                            Ext.Array.remove(me.flushClassList, c);
                        }
                    }
                    delete map[c];
                } else {
                    newList.push(c);
                }
            }

            return me;
        },

        
        setStyle: function (prop, value) {
            var me = this,
                style = me.style || (me.style = {});

            if (typeof prop == 'string') {
                if (arguments.length === 1) {
                    me.setStyle(Ext.Element.parseStyles(prop));
                } else {
                    style[prop] = value;
                }
            } else {
                Ext.apply(style, prop);
            }

            return me;
        },

        
        writeTo: function (to) {
            var me = this,
                classList = me.flushClassList || me.classList,
                removedClasses = me.removedClasses,
                style;

            if (me.styleFn) {
                style = Ext.apply({}, me.styleFn());
                Ext.apply(style, me.style);
            } else {
                style = me.style;
            }

            to[me.clsProp] = classList.join(' ');

            if (style) {
                to[me.styleProp] = me.styleIsText ? Ext.DomHelper.generateStyles(style) : style;
            }
            
            if (removedClasses) {
                removedClasses = Ext.Object.getKeys(removedClasses);
                if (removedClasses.length) {
                    to[me.removedProp] = removedClasses.join(' ');
                }
            }

            return to;
        }
    };
}()));


Ext.define('Ext.util.Queue', {

    constructor: function() {
        this.clear();
    },

    add : function(obj) {
        var me = this,
            key = me.getKey(obj);

        if (!me.map[key]) {
            ++me.length;
            me.items.push(obj);
            me.map[key] = obj;
        }

        return obj;
    },

    
    clear : function(){
        var me = this,
            items = me.items;

        me.items = [];
        me.map = {};
        me.length = 0;

        return items;
    },

    contains: function (obj) {
        var key = this.getKey(obj);

        return this.map.hasOwnProperty(key);
    },

    
    getCount : function(){
        return this.length;
    },

    getKey : function(obj){
         return obj.id;
    },

    
    remove : function(obj){
        var me = this,
            key = me.getKey(obj),
            items = me.items,
            index;

        if (me.map[key]) {
            index = Ext.Array.indexOf(items, obj);
            Ext.Array.erase(items, index, 1);
            delete me.map[key];
            --me.length;
        }

        return obj;
    }
});

Ext.define('Ext.util.Region', {

    

    requires: ['Ext.util.Offset'],

    statics: {
        
        getRegion: function(el) {
            return Ext.fly(el).getPageBox(true);
        },

        
        from: function(o) {
            return new this(o.top, o.right, o.bottom, o.left);
        }
    },

    

    
    constructor : function(t, r, b, l) {
        var me = this;
        me.y = me.top = me[1] = t;
        me.right = r;
        me.bottom = b;
        me.x = me.left = me[0] = l;
    },

    
    contains : function(region) {
        var me = this;
        return (region.x >= me.x &&
                region.right <= me.right &&
                region.y >= me.y &&
                region.bottom <= me.bottom);

    },

    
    intersect : function(region) {
        var me = this,
            t = Math.max(me.y, region.y),
            r = Math.min(me.right, region.right),
            b = Math.min(me.bottom, region.bottom),
            l = Math.max(me.x, region.x);

        if (b > t && r > l) {
            return new this.self(t, r, b, l);
        }
        else {
            return false;
        }
    },

    
    union : function(region) {
        var me = this,
            t = Math.min(me.y, region.y),
            r = Math.max(me.right, region.right),
            b = Math.max(me.bottom, region.bottom),
            l = Math.min(me.x, region.x);

        return new this.self(t, r, b, l);
    },

    
    constrainTo : function(r) {
        var me = this,
            constrain = Ext.Number.constrain;
        me.top = me.y = constrain(me.top, r.y, r.bottom);
        me.bottom = constrain(me.bottom, r.y, r.bottom);
        me.left = me.x = constrain(me.left, r.x, r.right);
        me.right = constrain(me.right, r.x, r.right);
        return me;
    },

    
    adjust : function(t, r, b, l) {
        var me = this;
        me.top = me.y += t;
        me.left = me.x += l;
        me.right += r;
        me.bottom += b;
        return me;
    },

    
    getOutOfBoundOffset: function(axis, p) {
        if (!Ext.isObject(axis)) {
            if (axis == 'x') {
                return this.getOutOfBoundOffsetX(p);
            } else {
                return this.getOutOfBoundOffsetY(p);
            }
        } else {
            p = axis;
            var d = new Ext.util.Offset();
            d.x = this.getOutOfBoundOffsetX(p.x);
            d.y = this.getOutOfBoundOffsetY(p.y);
            return d;
        }

    },

    
    getOutOfBoundOffsetX: function(p) {
        if (p <= this.x) {
            return this.x - p;
        } else if (p >= this.right) {
            return this.right - p;
        }

        return 0;
    },

    
    getOutOfBoundOffsetY: function(p) {
        if (p <= this.y) {
            return this.y - p;
        } else if (p >= this.bottom) {
            return this.bottom - p;
        }

        return 0;
    },

    
    isOutOfBound: function(axis, p) {
        if (!Ext.isObject(axis)) {
            if (axis == 'x') {
                return this.isOutOfBoundX(p);
            } else {
                return this.isOutOfBoundY(p);
            }
        } else {
            p = axis;
            return (this.isOutOfBoundX(p.x) || this.isOutOfBoundY(p.y));
        }
    },

    
    isOutOfBoundX: function(p) {
        return (p < this.x || p > this.right);
    },

    
    isOutOfBoundY: function(p) {
        return (p < this.y || p > this.bottom);
    },

    
    restrict: function(axis, p, factor) {
        if (Ext.isObject(axis)) {
            var newP;

            factor = p;
            p = axis;

            if (p.copy) {
                newP = p.copy();
            }
            else {
                newP = {
                    x: p.x,
                    y: p.y
                };
            }

            newP.x = this.restrictX(p.x, factor);
            newP.y = this.restrictY(p.y, factor);
            return newP;
        } else {
            if (axis == 'x') {
                return this.restrictX(p, factor);
            } else {
                return this.restrictY(p, factor);
            }
        }
    },

    
    restrictX : function(p, factor) {
        if (!factor) {
            factor = 1;
        }

        if (p <= this.x) {
            p -= (p - this.x) * factor;
        }
        else if (p >= this.right) {
            p -= (p - this.right) * factor;
        }
        return p;
    },

    
    restrictY : function(p, factor) {
        if (!factor) {
            factor = 1;
        }

        if (p <= this.y) {
            p -= (p - this.y) * factor;
        }
        else if (p >= this.bottom) {
            p -= (p - this.bottom) * factor;
        }
        return p;
    },

    
    getSize: function() {
        return {
            width: this.right - this.x,
            height: this.bottom - this.y
        };
    },

    
    copy: function() {
        return new this.self(this.y, this.right, this.bottom, this.x);
    },

    
    copyFrom: function(p) {
        var me = this;
        me.top = me.y = me[1] = p.y;
        me.right = p.right;
        me.bottom = p.bottom;
        me.left = me.x = me[0] = p.x;

        return this;
    },

    
    toString: function() {
        return "Region[" + this.top + "," + this.right + "," + this.bottom + "," + this.left + "]";
    },

    
    translateBy: function(x, y) {
        if (arguments.length == 1) {
            y = x.y;
            x = x.x;
        }
        var me = this;
        me.top = me.y += y;
        me.right += x;
        me.bottom += y;
        me.left = me.x += x;

        return me;
    },

    
    round: function() {
        var me = this;
        me.top = me.y = Math.round(me.y);
        me.right = Math.round(me.right);
        me.bottom = Math.round(me.bottom);
        me.left = me.x = Math.round(me.x);

        return me;
    },

    
    equals: function(region) {
        return (this.top == region.top && this.right == region.right && this.bottom == region.bottom && this.left == region.left);
    }
});


Ext.define('Ext.util.Renderable', {
    requires: [
        'Ext.dom.Element'
    ],

    frameCls: Ext.baseCSSPrefix + 'frame',

    frameIdRegex: /[\-]frame\d+[TMB][LCR]$/,

    frameElementCls: {
        tl: [],
        tc: [],
        tr: [],
        ml: [],
        mc: [],
        mr: [],
        bl: [],
        bc: [],
        br: []
    },

    frameElNames: ['TL','TC','TR','ML','MC','MR','BL','BC','BR'],

    frameTpl: [
        '{%this.renderDockedItems(out,values,0);%}',
        '<tpl if="top">',
            '<tpl if="left"><div id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl>" style="background-position: {tl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
                '<tpl if="right"><div id="{fgid}TR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl>" style="background-position: {tr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
                    '<div id="{fgid}TC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl>" style="background-position: {tc}; height: {frameWidth}px" role="presentation"></div>',
                '<tpl if="right"></div></tpl>',
            '<tpl if="left"></div></tpl>',
        '</tpl>',
        '<tpl if="left"><div id="{fgid}ML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></tpl>',
            '<tpl if="right"><div id="{fgid}MR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl>" style="background-position: {mr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
                '<div id="{fgid}MC" class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl>" role="presentation">',
                    '{%this.applyRenderTpl(out, values)%}',
                '</div>',
            '<tpl if="right"></div></tpl>',
        '<tpl if="left"></div></tpl>',
        '<tpl if="bottom">',
            '<tpl if="left"><div id="{fgid}BL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
                '<tpl if="right"><div id="{fgid}BR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl>" style="background-position: {br}; padding-right: {frameWidth}px" role="presentation"></tpl>',
                    '<div id="{fgid}BC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></div>',
                '<tpl if="right"></div></tpl>',
            '<tpl if="left"></div></tpl>',
        '</tpl>',
        '{%this.renderDockedItems(out,values,1);%}'
    ],

    frameTableTpl: [
        '{%this.renderDockedItems(out,values,0);%}',
        '<table><tbody>',
            '<tpl if="top">',
                '<tr>',
                    '<tpl if="left"><td id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl>" style="background-position: {tl}; padding-left:{frameWidth}px" role="presentation"></td></tpl>',
                    '<td id="{fgid}TC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl>" style="background-position: {tc}; height: {frameWidth}px" role="presentation"></td>',
                    '<tpl if="right"><td id="{fgid}TR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl>" style="background-position: {tr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
                '</tr>',
            '</tpl>',
            '<tr>',
                '<tpl if="left"><td id="{fgid}ML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
                '<td id="{fgid}MC" class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl>" style="background-position: 0 0;" role="presentation">',
                    '{%this.applyRenderTpl(out, values)%}',
                '</td>',
                '<tpl if="right"><td id="{fgid}MR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl>" style="background-position: {mr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
            '</tr>',
            '<tpl if="bottom">',
                '<tr>',
                    '<tpl if="left"><td id="{fgid}BL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
                    '<td id="{fgid}BC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></td>',
                    '<tpl if="right"><td id="{fgid}BR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl>" style="background-position: {br}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
                '</tr>',
            '</tpl>',
        '</tbody></table>',
        '{%this.renderDockedItems(out,values,1);%}'
    ],

    
    afterRender : function() {
        var me = this,
            data = {},
            protoEl = me.protoEl,
            target = me.getTargetEl(),
            item;

        me.finishRenderChildren();

        if (me.styleHtmlContent) {
            target.addCls(me.styleHtmlCls);
        }
        
        protoEl.writeTo(data);
        
        
        
        
        item = data.removed;
        if (item) {
            target.removeCls(item);
        }
        
        item = data.cls;
        if (item.length) {
            target.addCls(item);
        }
        
        item = data.style;
        if (data.style) {
            target.setStyle(item);
        }
        
        me.protoEl = null;

        
        if (!me.ownerCt) {
            me.updateLayout();
        }
    },

    afterFirstLayout : function(width, height) {
        var me = this,
            hasX = Ext.isDefined(me.x),
            hasY = Ext.isDefined(me.y),
            pos, xy;

        
        
        if (me.floating && (!hasX || !hasY)) {
            if (me.floatParent) {
                pos = me.floatParent.getTargetEl().getViewRegion();
                xy = me.el.getAlignToXY(me.floatParent.getTargetEl(), 'c-c');
                pos.left = xy[0] - pos.left;
                pos.top =  xy[1] - pos.top;
            } else {
                xy = me.el.getAlignToXY(me.container, 'c-c');
                pos = me.container.translatePoints(xy[0], xy[1]);
            }
            me.x = hasX ? me.x : pos.left;
            me.y = hasY ? me.y : pos.top;
            hasX = hasY = true;
        }

        if (hasX || hasY) {
            me.setPosition(me.x, me.y);
        }
        me.onBoxReady(width, height);
        if (me.hasListeners.boxready) {
            me.fireEvent('boxready', me, width, height);
        }
    },

    onBoxReady: Ext.emptyFn,

    
    applyRenderSelectors: function() {
        var me = this,
            selectors = me.renderSelectors,
            el = me.el,
            dom = el.dom,
            selector;

        me.applyChildEls(el);

        
        
        
        if (selectors) {
            for (selector in selectors) {
                if (selectors.hasOwnProperty(selector) && selectors[selector]) {
                    me[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], dom));
                }
            }
        }
    },

    beforeRender: function () {
        var me = this,
            target = me.getTargetEl(),
            layout = me.getComponentLayout();

        
        me.frame = me.frame || me.alwaysFramed;

        if (!layout.initialized) {
            layout.initLayout();
        }

        
        
        if (target) {
            target.setStyle(me.getOverflowStyle());
            me.overflowStyleSet = true;
        }

        me.setUI(me.ui);

        if (me.disabled) {
            
            me.disable(true);
        }
    },

    
    doApplyRenderTpl: function(out, values) {
        
        

        var me = values.$comp,
            tpl;

        
        if (!me.rendered) {
            tpl = me.initRenderTpl();
            tpl.applyOut(values.renderData, out);
        }
    },

    
    doAutoRender: function() {
        var me = this;
        if (!me.rendered) {
            if (me.floating) {
                me.render(document.body);
            } else {
                me.render(Ext.isBoolean(me.autoRender) ? Ext.getBody() : me.autoRender);
            }
        }
    },

    doRenderContent: function (out, renderData) {
        
        

        var me = renderData.$comp;

        if (me.html) {
            Ext.DomHelper.generateMarkup(me.html, out);
            delete me.html;
        }

        if (me.tpl) {
            
            if (!me.tpl.isTemplate) {
                me.tpl = new Ext.XTemplate(me.tpl);
            }

            if (me.data) {
                
                me.tpl.applyOut(me.data, out);
                delete me.data;
            }
        }
    },

    doRenderFramingDockedItems: function (out, renderData, after) {
        
        

        var me = renderData.$comp;

        
        
        if (!me.rendered && me.doRenderDockedItems) {
            
            
            renderData.renderData.$skipDockedItems = true;

            
            
            me.doRenderDockedItems.call(this, out, renderData, after);
        }
    },

    
    finishRender: function(containerIdx) {
        var me = this,
            tpl, data, contentEl, el, pre, hide;

        
        
        
        
        
        
        

        if (!me.el || me.$pid) {
            if (me.container) {
                el = me.container.getById(me.id, true);
            } else {
                el = Ext.getDom(me.id);
            }

            if (!me.el) {
                
                me.wrapPrimaryEl(el);
            } else {
                
                
                delete me.$pid;

                if (!me.el.dom) {
                    
                    me.wrapPrimaryEl(me.el);
                }
                el.parentNode.insertBefore(me.el.dom, el);
                Ext.removeNode(el); 
                
            }
        } else if (!me.rendering) {
            
            
            
            tpl = me.initRenderTpl();
            if (tpl) {
                data = me.initRenderData();
                tpl.insertFirst(me.getTargetEl(), data);
            }
        }
        

        if (!me.container) {
            
            me.container = Ext.get(me.el.dom.parentNode);
        }

        if (me.ctCls) {
            me.container.addCls(me.ctCls);
        }

        
        me.onRender(me.container, containerIdx);

        
        if (!me.overflowStyleSet) {
            me.getTargetEl().setStyle(me.getOverflowStyle());
        }

        
        
        me.el.setVisibilityMode(Ext.Element[me.hideMode.toUpperCase()]);

        if (me.overCls) {
            me.el.hover(me.addOverCls, me.removeOverCls, me);
        }

        if (me.hasListeners.render) {
            me.fireEvent('render', me);
        }

        if (me.contentEl) {
            pre = Ext.baseCSSPrefix;
            hide = pre + 'hide-';
            contentEl = Ext.get(me.contentEl);
            contentEl.removeCls([pre+'hidden', hide+'display', hide+'offsets', hide+'nosize']);
            me.getTargetEl().appendChild(contentEl.dom);
        }

        me.afterRender(); 
        if (me.hasListeners.afterrender) {
            me.fireEvent('afterrender', me);
        }
        me.initEvents();

        if (me.hidden) {
            
            
            
            me.el.hide();
        }
    },

    finishRenderChildren: function () {
        var layout = this.getComponentLayout();

        layout.finishRender();
    },

    getElConfig : function() {
        var me = this,
            autoEl = me.autoEl,
            frameInfo = me.getFrameInfo(),
            config = {
                tag: 'div',
                tpl: frameInfo ? me.initFramingTpl(frameInfo.table) : me.initRenderTpl()
            },
            i, frameElNames, len, suffix, frameGenId;

        me.initStyles(me.protoEl);
        me.protoEl.writeTo(config);
        me.protoEl.flush();

        if (Ext.isString(autoEl)) {
            config.tag = autoEl;
        } else {
            Ext.apply(config, autoEl); 
        }

        
        config.id = me.id;

        if (config.tpl) {
            
            if (frameInfo) {
                frameElNames = me.frameElNames;
                len = frameElNames.length;
                frameGenId = me.id + '-frame1';

                me.frameGenId = 1;
                config.tplData = Ext.apply({}, {
                    $comp:      me,
                    fgid:       frameGenId,
                    ui:         me.ui,
                    uiCls:      me.uiCls,
                    frameCls:   me.frameCls,
                    baseCls:    me.baseCls,
                    frameWidth: frameInfo.maxWidth,
                    top:        !!frameInfo.top,
                    left:       !!frameInfo.left,
                    right:      !!frameInfo.right,
                    bottom:     !!frameInfo.bottom,
                    renderData: me.initRenderData()
                }, me.getFramePositions(frameInfo));

                
                for (i = 0; i < len; i++) {
                    suffix = frameElNames[i];
                    me.addChildEls({ name: 'frame' + suffix, id: frameGenId + suffix });
                }

                
                me.addChildEls({
                    name: 'frameBody',
                    id: frameGenId + 'MC'
                });
            } else {
                config.tplData = me.initRenderData();
            }
        }

        return config;
    },

    
    
    initFramingTpl: function(table) {
        var tpl = table ? this.getTpl('frameTableTpl') : this.getTpl('frameTpl');

        if (tpl && !tpl.applyRenderTpl) {
            this.setupFramingTpl(tpl);
        }

        return tpl;
    },

    
    setupFramingTpl: function(frameTpl) {
        frameTpl.applyRenderTpl = this.doApplyRenderTpl;
        frameTpl.renderDockedItems = this.doRenderFramingDockedItems;
    },

    
    getInsertPosition: function(position) {
        
        if (position !== undefined) {
            if (Ext.isNumber(position)) {
                position = this.container.dom.childNodes[position];
            }
            else {
                position = Ext.getDom(position);
            }
        }

        return position;
    },

    getRenderTree: function() {
        var me = this;

        if (!me.hasListeners.beforerender || me.fireEvent('beforerender', me) !== false) {
            me.beforeRender();

            
            
            me.rendering = true;

            if (me.el) {
                
                
                
                return {
                    tag: 'div',
                    id: (me.$pid = Ext.id())
                };
            }

            return me.getElConfig();
        }

        return null;
    },

    initContainer: function(container) {
        var me = this;

        
        
        
        if (!container && me.el) {
            container = me.el.dom.parentNode;
            me.allowDomMove = false;
        }
        me.container = container.dom ? container : Ext.get(container);

        return me.container;
    },

    
    initRenderData: function() {
        var me = this;

        return Ext.apply({
            $comp: me,
            id: me.id,
            ui: me.ui,
            uiCls: me.uiCls,
            baseCls: me.baseCls,
            componentCls: me.componentCls,
            frame: me.frame
        }, me.renderData);
    },

    
    initRenderTpl: function() {
        var tpl = this.getTpl('renderTpl');

        if (tpl && !tpl.renderContent) {
            this.setupRenderTpl(tpl);
        }

        return tpl;
    },

    
    onRender: function(parentNode, containerIdx) {
        var me = this,
            x = me.x,
            y = me.y,
            lastBox, width, height,
            el = me.el,
            body = Ext.getBody().dom;

        
        if (Ext.scopeResetCSS && !me.ownerCt) {
            
            if (el.dom === body) {
                el.parent().addCls(Ext.resetCls);
            }
            
            else {
                
                if (me.floating && me.el.dom.parentNode === body) {
                    Ext.resetElement.appendChild(me.el);
                }
                
                else {
                    
                    me.resetEl = el.wrap(Ext.resetElementSpec, false, Ext.supports.CSS3LinearGradient ? undefined : '*');
                }
            }
        }

        me.applyRenderSelectors();

        
        
        delete me.rendering;

        me.rendered = true;

        
        lastBox = null;

        if (x !== undefined) {
            lastBox = lastBox || {};
            lastBox.x = x;
        }
        if (y !== undefined) {
            lastBox = lastBox || {};
            lastBox.y = y;
        }
        
        
        
        if (!me.getFrameInfo() && Ext.isBorderBox) {
            width = me.width;
            height = me.height;

            if (typeof width == 'number') {
                lastBox = lastBox || {};
                lastBox.width = width;
            }
            if (typeof height == 'number') {
                lastBox = lastBox || {};
                lastBox.height = height;
            }
        }

        me.lastBox = me.el.lastBox = lastBox;
    },

    
    render: function(container, position) {
        var me = this,
            el = me.el && (me.el = Ext.get(me.el)), 
            vetoed,
            tree,
            nextSibling;

        Ext.suspendLayouts();

        container = me.initContainer(container);

        nextSibling = me.getInsertPosition(position);

        if (!el) {
            tree = me.getRenderTree();
            if (me.ownerLayout && me.ownerLayout.transformItemRenderTree) {
                tree = me.ownerLayout.transformItemRenderTree(tree);
            }

            
            if (tree) {
                if (nextSibling) {
                    el = Ext.DomHelper.insertBefore(nextSibling, tree);
                } else {
                    el = Ext.DomHelper.append(container, tree);
                }

                me.wrapPrimaryEl(el);
            }
        } else {
            if (!me.hasListeners.beforerender || me.fireEvent('beforerender', me) !== false) {
                
                me.initStyles(el);
                if (me.allowDomMove !== false) {
                    
                    if (nextSibling) {
                        container.dom.insertBefore(el.dom, nextSibling);
                    } else {
                        container.dom.appendChild(el.dom);
                    }
                }
            } else {
                vetoed = true;
            }
        }

        if (el && !vetoed) {
            me.finishRender(position);
        }

        Ext.resumeLayouts(!container.isDetachedBody);
    },

    
    ensureAttachedToBody: function (runLayout) {
        var comp = this,
            body;

        while (comp.ownerCt) {
            comp = comp.ownerCt;
        }

        if (comp.container.isDetachedBody) {
            comp.container = body = Ext.resetElement;
            body.appendChild(comp.el.dom);
            if (runLayout) {
                comp.updateLayout();
            }
            if (typeof comp.x == 'number' || typeof comp.y == 'number') {
                comp.setPosition(comp.x, comp.y);
            }
        }
    },

    setupRenderTpl: function (renderTpl) {
        renderTpl.renderBody = renderTpl.renderContent = this.doRenderContent;
    },

    wrapPrimaryEl: function (dom) {
        this.el = Ext.get(dom, true);
    },

    
    initFrame : function() {
        if (Ext.supports.CSS3BorderRadius || !this.frame) {
            return;
        }

        var me = this,
            frameInfo = me.getFrameInfo(),
            frameWidth, frameTpl, frameGenId,
            i,
            frameElNames = me.frameElNames,
            len = frameElNames.length,
            suffix;

        if (frameInfo) {
            frameWidth = frameInfo.maxWidth;
            frameTpl = me.getFrameTpl(frameInfo.table);

            
            
            me.frameGenId = frameGenId = (me.frameGenId || 0) + 1;
            frameGenId = me.id + '-frame' + frameGenId;

            
            frameTpl.insertFirst(me.el, Ext.apply({
                $comp:      me,
                fgid:       frameGenId,
                ui:         me.ui,
                uiCls:      me.uiCls,
                frameCls:   me.frameCls,
                baseCls:    me.baseCls,
                frameWidth: frameWidth,
                top:        !!frameInfo.top,
                left:       !!frameInfo.left,
                right:      !!frameInfo.right,
                bottom:     !!frameInfo.bottom
            }, me.getFramePositions(frameInfo)));

            
            me.frameBody = me.el.down('.' + me.frameCls + '-mc');

            
            me.removeChildEls(function (c) {
                return c.id && me.frameIdRegex.test(c.id);
            });

            
            for (i = 0; i < len; i++) {
                suffix = frameElNames[i];
                me['frame' + suffix] = me.el.getById(frameGenId + suffix);
            }
        }
    },

    updateFrame: function() {
        if (Ext.supports.CSS3BorderRadius || !this.frame) {
            return;
        }

        var me = this,
            wasTable = this.frameSize && this.frameSize.table,
            oldFrameTL = this.frameTL,
            oldFrameBL = this.frameBL,
            oldFrameML = this.frameML,
            oldFrameMC = this.frameMC,
            newMCClassName;

        this.initFrame();

        if (oldFrameMC) {
            if (me.frame) {

                
                newMCClassName = this.frameMC.dom.className;

                
                
                oldFrameMC.insertAfter(this.frameMC);
                this.frameMC.remove();

                
                this.frameBody = this.frameMC = oldFrameMC;

                
                oldFrameMC.dom.className = newMCClassName;

                
                if (wasTable) {
                    me.el.query('> table')[1].remove();
                }
                else {
                    if (oldFrameTL) {
                        oldFrameTL.remove();
                    }
                    if (oldFrameBL) {
                        oldFrameBL.remove();
                    }
                    if (oldFrameML) {
                        oldFrameML.remove();
                    }
                }
            }
        }
        else if (me.frame) {
            this.applyRenderSelectors();
        }
    },

    
    getFrameInfo: function() {
        
        if (Ext.supports.CSS3BorderRadius || !this.frame) {
            return false;
        }

        var me = this,
            frameInfoCache = me.frameInfoCache,
            el = me.el || me.protoEl,
            cls = el.dom ? el.dom.className : el.classList.join(' '),
            frameInfo = frameInfoCache[cls],
            styleEl, left, top, info;

        if (frameInfo == null) {
            
            styleEl = Ext.fly(me.getStyleProxy(cls), 'frame-style-el');
            left = styleEl.getStyle('background-position-x');
            top = styleEl.getStyle('background-position-y');

            
            
            if (!left && !top) {
                info = styleEl.getStyle('background-position').split(' ');
                left = info[0];
                top = info[1];
            }

            frameInfo = me.calculateFrame(left, top);

            if (frameInfo) {
                
                el.setStyle('background-image', 'none');
            }


            frameInfoCache[cls] = frameInfo;
        }

        me.frame = !!frameInfo;
        me.frameSize = frameInfo;

        return frameInfo;
    },
    
    calculateFrame: function(left, top){
        
        
        
        if (!(parseInt(left, 10) >= 1000000 && parseInt(top, 10) >= 1000000)) {
            return false;
        }
        var max = Math.max,
            tl = parseInt(left.substr(3, 2), 10),
            tr = parseInt(left.substr(5, 2), 10),
            br = parseInt(top.substr(3, 2), 10),
            bl = parseInt(top.substr(5, 2), 10),
            frameInfo = {
                
                table: left.substr(0, 3) == '110',

                
                vertical: top.substr(0, 3) == '110',

                
                top:    max(tl, tr),
                right:  max(tr, br),
                bottom: max(bl, br),
                left:   max(tl, bl)
            };

        frameInfo.maxWidth = max(frameInfo.top, frameInfo.right, frameInfo.bottom, frameInfo.left);
        frameInfo.width = frameInfo.left + frameInfo.right;
        frameInfo.height = frameInfo.top + frameInfo.bottom;
        return frameInfo;
    },

    
    getStyleProxy: function(cls) {
        var result = this.styleProxyEl || (Ext.AbstractComponent.prototype.styleProxyEl = Ext.resetElement.createChild({
                style: {
                    position: 'absolute',
                    top: '-10000px'
                }
            }, null, true));

        result.className = cls;
        return result;
    },

    getFramePositions: function(frameInfo) {
        var me = this,
            frameWidth = frameInfo.maxWidth,
            dock = me.dock,
            positions, tc, bc, ml, mr;

        if (frameInfo.vertical) {
            tc = '0 -' + (frameWidth * 0) + 'px';
            bc = '0 -' + (frameWidth * 1) + 'px';

            if (dock && dock == "right") {
                tc = 'right -' + (frameWidth * 0) + 'px';
                bc = 'right -' + (frameWidth * 1) + 'px';
            }

            positions = {
                tl: '0 -' + (frameWidth * 0) + 'px',
                tr: '0 -' + (frameWidth * 1) + 'px',
                bl: '0 -' + (frameWidth * 2) + 'px',
                br: '0 -' + (frameWidth * 3) + 'px',

                ml: '-' + (frameWidth * 1) + 'px 0',
                mr: 'right 0',

                tc: tc,
                bc: bc
            };
        } else {
            ml = '-' + (frameWidth * 0) + 'px 0';
            mr = 'right 0';

            if (dock && dock == "bottom") {
                ml = 'left bottom';
                mr = 'right bottom';
            }

            positions = {
                tl: '0 -' + (frameWidth * 2) + 'px',
                tr: 'right -' + (frameWidth * 3) + 'px',
                bl: '0 -' + (frameWidth * 4) + 'px',
                br: 'right -' + (frameWidth * 5) + 'px',

                ml: ml,
                mr: mr,

                tc: '0 -' + (frameWidth * 0) + 'px',
                bc: '0 -' + (frameWidth * 1) + 'px'
            };
        }

        return positions;
    },

    
    getFrameTpl : function(table) {
        return this.getTpl(table ? 'frameTableTpl' : 'frameTpl');
    },

    
    frameInfoCache: {}
});


Ext.define('Ext.util.Sorter', {

    
    
    
    
    
    
    
    
    
    direction: "ASC",
    
    constructor: function(config) {
        var me = this;
        
        Ext.apply(me, config);
        
        
        me.updateSortFunction();
    },
    
    
    createSortFunction: function(sorterFn) {
        var me        = this,
            property  = me.property,
            direction = me.direction || "ASC",
            modifier  = direction.toUpperCase() == "DESC" ? -1 : 1;
        
        
        
        return function(o1, o2) {
            return modifier * sorterFn.call(me, o1, o2);
        };
    },
    
    
    defaultSorterFn: function(o1, o2) {
        var me = this,
            transform = me.transform,
            v1 = me.getRoot(o1)[me.property],
            v2 = me.getRoot(o2)[me.property];
            
        if (transform) {
            v1 = transform(v1);
            v2 = transform(v2);
        }

        return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
    },
    
    
    getRoot: function(item) {
        return this.root === undefined ? item : item[this.root];
    },
    
    
    setDirection: function(direction) {
        var me = this;
        me.direction = direction ? direction.toUpperCase() : direction;
        me.updateSortFunction();
    },
    
    
    toggle: function() {
        var me = this;
        me.direction = Ext.String.toggle(me.direction, "ASC", "DESC");
        me.updateSortFunction();
    },
    
    
    updateSortFunction: function(fn) {
        var me = this;
        fn = fn || me.sorterFn || me.defaultSorterFn;
        me.sort = me.createSortFunction(fn);
    }
});

Ext.define('Ext.Action', {

    

    

    
    
    
    
    
    
    

    
    constructor : function(config){
        this.initialConfig = config;
        this.itemId = config.itemId = (config.itemId || config.id || Ext.id());
        this.items = [];
    },

    
    isAction : true,

    
    setText : function(text){
        this.initialConfig.text = text;
        this.callEach('setText', [text]);
    },

    
    getText : function(){
        return this.initialConfig.text;
    },

    
    setIconCls : function(cls){
        this.initialConfig.iconCls = cls;
        this.callEach('setIconCls', [cls]);
    },

    
    getIconCls : function(){
        return this.initialConfig.iconCls;
    },

    
    setDisabled : function(v){
        this.initialConfig.disabled = v;
        this.callEach('setDisabled', [v]);
    },

    
    enable : function(){
        this.setDisabled(false);
    },

    
    disable : function(){
        this.setDisabled(true);
    },

    
    isDisabled : function(){
        return this.initialConfig.disabled;
    },

    
    setHidden : function(v){
        this.initialConfig.hidden = v;
        this.callEach('setVisible', [!v]);
    },

    
    show : function(){
        this.setHidden(false);
    },

    
    hide : function(){
        this.setHidden(true);
    },

    
    isHidden : function(){
        return this.initialConfig.hidden;
    },

    
    setHandler : function(fn, scope){
        this.initialConfig.handler = fn;
        this.initialConfig.scope = scope;
        this.callEach('setHandler', [fn, scope]);
    },

    
    each : function(fn, scope){
        Ext.each(this.items, fn, scope);
    },

    
    callEach : function(fnName, args){
        var items = this.items,
            i = 0,
            len = items.length,
            item;

        Ext.suspendLayouts();
        for(; i < len; i++){
            item = items[i];
            item[fnName].apply(item, args);
        }
        Ext.resumeLayouts(true);
    },

    
    addComponent : function(comp){
        this.items.push(comp);
        comp.on('destroy', this.removeComponent, this);
    },

    
    removeComponent : function(comp){
        Ext.Array.remove(this.items, comp);
    },

    
    execute : function(){
        this.initialConfig.handler.apply(this.initialConfig.scope || Ext.global, arguments);
    }
});


Ext.define('Ext.Layer', {
    extend: 'Ext.Element',
    uses: ['Ext.Shadow'],

    

    

    

    

    

    

    

    

    

    

    
    statics: {
        shims: []
    },
    
    isLayer: true,

    
    constructor: function(config, existingEl) {
        config = config || {};
        var me = this,
            dh = Ext.DomHelper,
            cp = config.parentEl,
            pel = cp ? Ext.getDom(cp) : document.body,
        hm = config.hideMode;

        if (existingEl) {
            me.dom = Ext.getDom(existingEl);
        }
        if (!me.dom) {
            me.dom = dh.append(pel, config.dh || {
                tag: 'div',
                cls: Ext.baseCSSPrefix + 'layer' 
            });
        } else {
            me.addCls(Ext.baseCSSPrefix + 'layer');
            if (!me.dom.parentNode) {
                pel.appendChild(me.dom);
            }
        }

        if (config.id) {
            me.id = me.dom.id = config.id;
        } else {
            me.id = Ext.id(me.dom);
        }

        Ext.Element.addToCache(me);

        if (config.cls) {
            me.addCls(config.cls);
        }
        me.constrain = config.constrain !== false;

        
        
        
        if (hm) {
            me.setVisibilityMode(Ext.Element[hm.toUpperCase()]);
            if (me.visibilityMode == Ext.Element.ASCLASS) {
                me.visibilityCls = config.visibilityCls;
            }
        } else if (config.useDisplay) {
            me.setVisibilityMode(Ext.Element.DISPLAY);
        } else {
            me.setVisibilityMode(Ext.Element.VISIBILITY);
        }

        if (config.shadow) {
            me.shadowOffset = config.shadowOffset || 4;
            me.shadow = new Ext.Shadow({
                offset: me.shadowOffset,
                mode: config.shadow
            });
            me.disableShadow();
        } else {
            me.shadowOffset = 0;
        }
        me.useShim = config.shim !== false && Ext.useShims;
        if (config.hidden === true) {
            me.hide();
        } else {
            me.show();
        }
    },

    getZIndex: function() {
        return parseInt((this.getShim() || this).getStyle('z-index'), 10);
    },

    getShim: function() {
        var me = this,
            shim, pn;

        if (!me.useShim) {
            return null;
        }
        if (!me.shim) {
            shim = me.self.shims.shift();
            if (!shim) {
                shim = me.createShim();
                shim.enableDisplayMode('block');
                shim.hide();
            }
            pn = me.dom.parentNode;
            if (shim.dom.parentNode != pn) {
                pn.insertBefore(shim.dom, me.dom);
            }
            me.shim = shim;
        }
        return me.shim;
    },

    hideShim: function() {
        var me = this;
        
        if (me.shim) {
            me.shim.setDisplayed(false);
            me.self.shims.push(me.shim);
            delete me.shim;
        }
    },

    disableShadow: function() {
        var me = this;
        
        if (me.shadow && !me.shadowDisabled) {
            me.shadowDisabled = true;
            me.shadow.hide();
            me.lastShadowOffset = me.shadowOffset;
            me.shadowOffset = 0;
        }
    },

    enableShadow: function(show) {
        var me = this;
        
        if (me.shadow && me.shadowDisabled) {
            me.shadowDisabled = false;
            me.shadowOffset = me.lastShadowOffset;
            delete me.lastShadowOffset;
            if (show) {
                me.sync(true);
            }
        }
    },

    
    sync: function(doShow) {
        var me = this,
            shadow = me.shadow,
            shadowPos, shimStyle, shadowSize,
            shim, l, t, w, h, shimIndex;

        if (!me.updating && me.isVisible() && (shadow || me.useShim)) {
            shim = me.getShim();
            l = me.getLocalX();
            t = me.getLocalY();
            w = me.dom.offsetWidth;
            h = me.dom.offsetHeight;

            if (shadow && !me.shadowDisabled) {
                if (doShow && !shadow.isVisible()) {
                    shadow.show(me);
                } else {
                    shadow.realign(l, t, w, h);
                }
                if (shim) {
                    
                    shimIndex = shim.getStyle('z-index');
                    if (shimIndex > me.zindex) {
                        me.shim.setStyle('z-index', me.zindex - 2);
                    }
                    shim.show();
                    
                    if (shadow.isVisible()) {
                        shadowPos = shadow.el.getXY();
                        shimStyle = shim.dom.style;
                        shadowSize = shadow.el.getSize();
                        if (Ext.supports.CSS3BoxShadow) {
                            shadowSize.height += 6;
                            shadowSize.width += 4;
                            shadowPos[0] -= 2;
                            shadowPos[1] -= 4;
                        }
                        shimStyle.left = (shadowPos[0]) + 'px';
                        shimStyle.top = (shadowPos[1]) + 'px';
                        shimStyle.width = (shadowSize.width) + 'px';
                        shimStyle.height = (shadowSize.height) + 'px';
                    } else {
                        shim.setSize(w, h);
                        shim.setLeftTop(l, t);
                    }
                }
            } else if (shim) {
                
                shimIndex = shim.getStyle('z-index');
                if (shimIndex > me.zindex) {
                    me.shim.setStyle('z-index', me.zindex - 2);
                }
                shim.show();
                shim.setSize(w, h);
                shim.setLeftTop(l, t);
            }
        }
        return me;
    },

    remove: function() {
        this.hideUnders();
        this.callParent();
    },

    
    beginUpdate: function() {
        this.updating = true;
    },

    
    endUpdate: function() {
        this.updating = false;
        this.sync(true);
    },

    
    hideUnders: function() {
        if (this.shadow) {
            this.shadow.hide();
        }
        this.hideShim();
    },

    
    constrainXY: function() {
        if (this.constrain) {
            var vw = Ext.Element.getViewWidth(),
                vh = Ext.Element.getViewHeight(),
                s = Ext.getDoc().getScroll(),
                xy = this.getXY(),
                x = xy[0],
                y = xy[1],
                so = this.shadowOffset,
                w = this.dom.offsetWidth + so,
                h = this.dom.offsetHeight + so,
                moved = false; 
            
            if ((x + w) > vw + s.left) {
                x = vw - w - so;
                moved = true;
            }
            if ((y + h) > vh + s.top) {
                y = vh - h - so;
                moved = true;
            }
            
            if (x < s.left) {
                x = s.left;
                moved = true;
            }
            if (y < s.top) {
                y = s.top;
                moved = true;
            }
            if (moved) {
                Ext.Layer.superclass.setXY.call(this, [x, y]);
                this.sync();
            }
        }
        return this;
    },

    getConstrainOffset: function() {
        return this.shadowOffset;
    },

    
    setVisible: function(visible, animate, duration, callback, easing) {
        var me = this,
            cb;

        
        cb = function() {
            if (visible) {
                me.sync(true);
            }
            if (callback) {
                callback();
            }
        };

        
        if (!visible) {
            me.hideUnders(true);
        }
        me.callParent([visible, animate, duration, callback, easing]);
        if (!animate) {
            cb();
        }
        return me;
    },

    
    beforeFx: function() {
        this.beforeAction();
        return this.callParent(arguments);
    },

    
    afterFx: function() {
        this.callParent(arguments);
        this.sync(this.isVisible());
    },

    
    beforeAction: function() {
        if (!this.updating && this.shadow) {
            this.shadow.hide();
        }
    },

    
    setLeft: function(left) {
        this.callParent(arguments);
        return this.sync();
    },

    setTop: function(top) {
        this.callParent(arguments);
        return this.sync();
    },

    setLeftTop: function(left, top) {
        this.callParent(arguments);
        return this.sync();
    },

    setXY: function(xy, animate, duration, callback, easing) {
        var me = this;
        
        
        callback = me.createCB(callback);

        me.fixDisplay();
        me.beforeAction();
        me.callParent([xy, animate, duration, callback, easing]);
        if (!animate) {
            callback();
        }
        return me;
    },

    
    createCB: function(callback) {
        var me = this,
            showShadow = me.shadow && me.shadow.isVisible();

        return function() {
            me.constrainXY();
            me.sync(showShadow);
            if (callback) {
                callback();
            }
        };
    },

    
    setX: function(x, animate, duration, callback, easing) {
        this.setXY([x, this.getY()], animate, duration, callback, easing);
        return this;
    },

    
    setY: function(y, animate, duration, callback, easing) {
        this.setXY([this.getX(), y], animate, duration, callback, easing);
        return this;
    },

    
    setSize: function(w, h, animate, duration, callback, easing) {
        var me = this;
        
        
        callback = me.createCB(callback);

        me.beforeAction();
        me.callParent([w, h, animate, duration, callback, easing]);
        if (!animate) {
            callback();
        }
        return me;
    },

    
    setWidth: function(w, animate, duration, callback, easing) {
        var me = this;
        
        
        callback = me.createCB(callback);

        me.beforeAction();
        me.callParent([w, animate, duration, callback, easing]);
        if (!animate) {
            callback();
        }
        return me;
    },

    
    setHeight: function(h, animate, duration, callback, easing) {
        var me = this;
        
        
        callback = me.createCB(callback);

        me.beforeAction();
        me.callParent([h, animate, duration, callback, easing]);
        if (!animate) {
            callback();
        }
        return me;
    },

    
    setBounds: function(x, y, width, height, animate, duration, callback, easing) {
        var me = this;
        
        
        callback = me.createCB(callback);

        me.beforeAction();
        if (!animate) {
            Ext.Layer.superclass.setXY.call(me, [x, y]);
            Ext.Layer.superclass.setSize.call(me, width, height);
            callback();
        } else {
            me.callParent([x, y, width, height, animate, duration, callback, easing]);
        }
        return me;
    },

    
    setZIndex: function(zindex) {
        var me = this;
        
        me.zindex = zindex;
        if (me.getShim()) {
            me.shim.setStyle('z-index', zindex++);
        }
        if (me.shadow) {
            me.shadow.setZIndex(zindex++);
        }
        return me.setStyle('z-index', zindex);
    },
    
    onOpacitySet: function(opacity){
        var shadow = this.shadow;
        if (shadow) {
            shadow.setOpacity(opacity);
        }
    }
});


Ext.define('Ext.ShadowPool', {
    singleton: true,
    requires: ['Ext.DomHelper'],

    markup: (function() {
        return Ext.String.format(
            '<div class="{0}{1}-shadow" role="presentation"></div>',
            Ext.baseCSSPrefix,
            Ext.isIE && !Ext.supports.CSS3BoxShadow ? 'ie' : 'css'
        );
    }()),

    shadows: [],

    pull: function() {
        var sh = this.shadows.shift();
        if (!sh) {
            sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, this.markup));
            sh.autoBoxAdjust = false;
        }
        return sh;
    },

    push: function(sh) {
        this.shadows.push(sh);
    },
    
    reset: function() {
        var shadows = [].concat(this.shadows),
            s,
            sLen    = shadows.length;

        for (s = 0; s < sLen; s++) {
            shadows[s].remove();
        }

        this.shadows = [];
    }
});

Ext.define('Ext.ZIndexManager', {
    alternateClassName: 'Ext.WindowGroup',

    statics: {
        zBase : 9000
    },

    constructor: function(container) {
        var me = this;

        me.list = {};
        me.zIndexStack = [];
        me.front = null;

        if (container) {

            
            if (container.isContainer) {
                container.on('resize', me._onContainerResize, me);
                me.zseed = Ext.Number.from(me.rendered ? container.getEl().getStyle('zIndex') : undefined, me.getNextZSeed());
                
                me.targetEl = container.getTargetEl();
                me.container = container;
            }
            
            else {
                Ext.EventManager.onWindowResize(me._onContainerResize, me);
                me.zseed = me.getNextZSeed();
                me.targetEl = Ext.get(container);
            }
        }
        
        
        else {
            Ext.EventManager.onWindowResize(me._onContainerResize, me);
            me.zseed = me.getNextZSeed();
            Ext.onDocumentReady(function() {
                me.targetEl = Ext.getBody();
            });
        }
    },

    getNextZSeed: function() {
        return (Ext.ZIndexManager.zBase += 10000);
    },

    setBase: function(baseZIndex) {
        this.zseed = baseZIndex;
        var result = this.assignZIndices();
        this._activateLast();
        return result;
    },

    
    assignZIndices: function() {
        var a = this.zIndexStack,
            len = a.length,
            i = 0,
            zIndex = this.zseed,
            comp;

        for (; i < len; i++) {
            comp = a[i];
            if (comp && !comp.hidden) {

                
                
                
                
                
                
                
                zIndex = comp.setZIndex(zIndex);
            }
        }

        
        this._activateLast();
        return zIndex;
    },

    
    _setActiveChild: function(comp, oldFront) {
        var front = this.front;
        if (comp !== front) {

            if (front && !front.destroying) {
                front.setActive(false, comp);
            }
            this.front = comp;
            if (comp && comp != oldFront) {
                comp.setActive(true);
                if (comp.modal) {
                    this._showModalMask(comp);
                }
            }
        }
    },
    
    onComponentHide: function(comp){
        comp.setActive(false);
        this._activateLast();
    },

    
    _activateLast: function() {
        var me = this,
            stack = me.zIndexStack,
            i = stack.length - 1,
            oldFront = me.front,
            comp;

        
        me.front = undefined;

        
        
        
        for (; i >= 0 && stack[i].hidden; --i);
        if ((comp = stack[i])) {
            me._setActiveChild(comp, oldFront);
            if (comp.modal) {
                return;
            }
        }

        
        
        for (; i >= 0; --i) {
            comp = stack[i];
            
            if (comp.isVisible() && comp.modal) {
                me._showModalMask(comp);
                return;
            }
        }

        
        
        me._hideModalMask();
    },

    _showModalMask: function(comp) {
        var me = this,
            zIndex = comp.el.getStyle('zIndex') - 4,
            maskTarget = comp.floatParent ? comp.floatParent.getTargetEl() : comp.container,
            viewSize = maskTarget.getBox();

        if (maskTarget.dom === document.body) {
            viewSize.height = Math.max(document.body.scrollHeight, Ext.dom.Element.getDocumentHeight());
            viewSize.width = Math.max(document.body.scrollWidth, viewSize.width);
        }
        if (!me.mask) {
            me.mask = Ext.getBody().createChild({
                cls: Ext.baseCSSPrefix + 'mask'
            });
            me.mask.setVisibilityMode(Ext.Element.DISPLAY);
            me.mask.on('click', me._onMaskClick, me);
        }
        me.mask.maskTarget = maskTarget;
        maskTarget.addCls(Ext.baseCSSPrefix + 'body-masked');
        me.mask.setStyle('zIndex', zIndex);

        
        
        me.mask.show();
        me.mask.setBox(viewSize);
    },

    _hideModalMask: function() {
        var mask = this.mask;
        if (mask && mask.isVisible()) {
            mask.maskTarget.removeCls(Ext.baseCSSPrefix + 'body-masked');
            mask.maskTarget = undefined;
            mask.hide();
        }
    },

    _onMaskClick: function() {
        if (this.front) {
            this.front.focus();
        }
    },

    _onContainerResize: function() {
        var mask = this.mask,
            maskTarget,
            viewSize;

        if (mask && mask.isVisible()) {

            
            
            mask.hide();
            maskTarget = mask.maskTarget;

            if (maskTarget.dom === document.body) {
                viewSize = {
                    height: Math.max(document.body.scrollHeight, Ext.dom.Element.getDocumentHeight()),
                    width: Math.max(document.body.scrollWidth, document.documentElement.clientWidth)
                };
            } else {
                viewSize = maskTarget.getViewSize(true);
            }
            mask.setSize(viewSize);
            mask.show();
        }
    },

    
    register : function(comp) {
        var me = this;
        
        if (comp.zIndexManager) {
            comp.zIndexManager.unregister(comp);
        }
        comp.zIndexManager = me;

        me.list[comp.id] = comp;
        me.zIndexStack.push(comp);
        comp.on('hide', me.onComponentHide, me);
    },

    
    unregister : function(comp) {
        var me = this,
            list = me.list;
        
        delete comp.zIndexManager;
        if (list && list[comp.id]) {
            delete list[comp.id];
            comp.un('hide', me.onComponentHide);
            Ext.Array.remove(me.zIndexStack, comp);

            
            me._activateLast();
        }
    },

    
    get : function(id) {
        return id.isComponent ? id : this.list[id];
    },

   
    bringToFront : function(comp) {
        var me = this,
            result = false,
            zIndexStack = me.zIndexStack;
        
        comp = me.get(comp);
        if (comp !== me.front) {
            Ext.Array.remove(zIndexStack, comp);
            if (comp.preventBringToFront) {
                
                zIndexStack.unshift(comp);
            } else {
                
                zIndexStack.push(comp);
            }

            me.assignZIndices();
            result = true;
            this.front = comp;
        }
        if (result && comp.modal) {
            me._showModalMask(comp);
        }
        return result;
    },

    
    sendToBack : function(comp) {
        var me = this;
        
        comp = me.get(comp);
        Ext.Array.remove(me.zIndexStack, comp);
        me.zIndexStack.unshift(comp);
        me.assignZIndices();
        this._activateLast();
        return comp;
    },

    
    hideAll : function() {
        var list = this.list,
            item,
            id;
            
        for (id in list) {
            if (list.hasOwnProperty(id)) {
                item = list[id];
                if (item.isComponent && item.isVisible()) {
                    item.hide();
                }
            }
        }
    },

    
    hide: function() {
        var me = this,
            mask = me.mask,
            i = 0,
            stack = me.zIndexStack,
            len = stack.length,
            comp;

        me.tempHidden = me.tempHidden||[];
        for (; i < len; i++) {
            comp = stack[i];
            if (comp.isVisible()) {
                me.tempHidden.push(comp);
                comp.el.hide();
            }
        }
        
        
        if (mask) {
            mask.hide();
        }
    },

    
    show: function() {
        var me = this,
            mask = me.mask,
            i = 0,
            tempHidden = me.tempHidden,
            len = tempHidden ? tempHidden.length : 0,
            comp;

        for (; i < len; i++) {
            comp = tempHidden[i];
            comp.el.show();
            comp.setPosition(comp.x, comp.y);
        }
        me.tempHidden.length = 0;

        
        if (mask) {
            mask.show();
            mask.alignTo(mask.maskTarget, 'tl-tl');
        }
    },

    
    getActive : function() {
        return this.front;
    },

    
    getBy : function(fn, scope) {
        var r = [],
            i = 0,
            stack = this.zIndexStack,
            len = stack.length,
            comp;

        for (; i < len; i++) {
            comp = stack[i];
            if (fn.call(scope||comp, comp) !== false) {
                r.push(comp);
            }
        }
        return r;
    },

    
    each : function(fn, scope) {
        var list = this.list,
            id,
            comp;
            
        for (id in list) {
            if (list.hasOwnProperty(id)) {
                comp = list[id];
                if (comp.isComponent && fn.call(scope || comp, comp) === false) {
                    return;
                }
            }
        }
    },

    
    eachBottomUp: function (fn, scope) {
        var stack = this.zIndexStack,
            i = 0,
            len = stack.length,
            comp;

        for (; i < len; i++) {
            comp = stack[i];
            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
                return;
            }
        }
    },

    
    eachTopDown: function (fn, scope) {
        var stack = this.zIndexStack,
            i = stack.length,
            comp;

        for (; i-- > 0; ) {
            comp = stack[i];
            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
                return;
            }
        }
    },

    destroy: function() {
        var me   = this,
            list = me.list,
            comp,
            id;

        for (id in list) {
            if (list.hasOwnProperty(id)) {
                comp = list[id];

                if (comp.isComponent) {
                    comp.destroy();
                }
            }
        }

        delete me.zIndexStack;
        delete me.list;
        delete me.container;
        delete me.targetEl;
    }
}, function() {
    
    Ext.WindowManager = Ext.WindowMgr = new this();
});





Ext.define('Ext.dd.DragDropManager', {
    singleton: true,

    requires: ['Ext.util.Region'],

    uses: ['Ext.tip.QuickTipManager'],

    
    alternateClassName: ['Ext.dd.DragDropMgr', 'Ext.dd.DDM'],

    
    ids: {},

    
    handleIds: {},

    
    dragCurrent: null,

    
    dragOvers: {},

    
    deltaX: 0,

    
    deltaY: 0,

    
    preventDefault: true,

    
    stopPropagation: true,

    
    initialized: false,

    
    locked: false,

    
    init: function() {
        this.initialized = true;
    },

    
    POINT: 0,

    
    INTERSECT: 1,

    
    mode: 0,

    
    notifyOccluded: false,

    
    _execOnAll: function(sMethod, args) {
        var i, j, oDD;
        for (i in this.ids) {
            for (j in this.ids[i]) {
                oDD = this.ids[i][j];
                if (! this.isTypeOfDD(oDD)) {
                    continue;
                }
                oDD[sMethod].apply(oDD, args);
            }
        }
    },

    
    _onLoad: function() {

        this.init();

        var Event = Ext.EventManager;
        Event.on(document, "mouseup",   this.handleMouseUp, this, true);
        Event.on(document, "mousemove", this.handleMouseMove, this, true);
        Event.on(window,   "unload",    this._onUnload, this, true);
        Event.on(window,   "resize",    this._onResize, this, true);
        

    },

    
    _onResize: function(e) {
        this._execOnAll("resetConstraints", []);
    },

    
    lock: function() { this.locked = true; },

    
    unlock: function() { this.locked = false; },

    
    isLocked: function() { return this.locked; },

    
    locationCache: {},

    
    useCache: true,

    
    clickPixelThresh: 3,

    
    clickTimeThresh: 350,

    
    dragThreshMet: false,

    
    clickTimeout: null,

    
    startX: 0,

    
    startY: 0,

    
    regDragDrop: function(oDD, sGroup) {
        if (!this.initialized) { this.init(); }

        if (!this.ids[sGroup]) {
            this.ids[sGroup] = {};
        }
        this.ids[sGroup][oDD.id] = oDD;
    },

    
    removeDDFromGroup: function(oDD, sGroup) {
        if (!this.ids[sGroup]) {
            this.ids[sGroup] = {};
        }

        var obj = this.ids[sGroup];
        if (obj && obj[oDD.id]) {
            delete obj[oDD.id];
        }
    },

    
    _remove: function(oDD) {
        for (var g in oDD.groups) {
            if (g && this.ids[g] && this.ids[g][oDD.id]) {
                delete this.ids[g][oDD.id];
            }
        }
        delete this.handleIds[oDD.id];
    },

    
    regHandle: function(sDDId, sHandleId) {
        if (!this.handleIds[sDDId]) {
            this.handleIds[sDDId] = {};
        }
        this.handleIds[sDDId][sHandleId] = sHandleId;
    },

    
    isDragDrop: function(id) {
        return ( this.getDDById(id) ) ? true : false;
    },

    
    getRelated: function(p_oDD, bTargetsOnly) {
        var oDDs = [],
            i, j, dd;
        for (i in p_oDD.groups) {
            for (j in this.ids[i]) {
                dd = this.ids[i][j];
                if (! this.isTypeOfDD(dd)) {
                    continue;
                }
                if (!bTargetsOnly || dd.isTarget) {
                    oDDs[oDDs.length] = dd;
                }
            }
        }

        return oDDs;
    },

    
    isLegalTarget: function (oDD, oTargetDD) {
        var targets = this.getRelated(oDD, true),
            i, len;
        for (i=0, len=targets.length;i<len;++i) {
            if (targets[i].id == oTargetDD.id) {
                return true;
            }
        }

        return false;
    },

    
    isTypeOfDD: function (oDD) {
        return (oDD && oDD.__ygDragDrop);
    },

    
    isHandle: function(sDDId, sHandleId) {
        return ( this.handleIds[sDDId] &&
                        this.handleIds[sDDId][sHandleId] );
    },

    
    getDDById: function(id) {
        var me = this,
            i, dd;
        for (i in this.ids) {
            dd = this.ids[i][id];
            if (dd instanceof Ext.dd.DDTarget) {
                return dd;
            }
        }
        return null;
    },

    
    handleMouseDown: function(e, oDD) {
        if(Ext.tip.QuickTipManager){
            Ext.tip.QuickTipManager.ddDisable();
        }
        if(this.dragCurrent){
            
            
            this.handleMouseUp(e);
        }

        this.currentTarget = e.getTarget();
        this.dragCurrent = oDD;

        var el = oDD.getEl();
        
        
        
        
        
        if (Ext.isIE && el.setCapture) {
            el.setCapture();
        }

        
        this.startX = e.getPageX();
        this.startY = e.getPageY();

        this.deltaX = this.startX - el.offsetLeft;
        this.deltaY = this.startY - el.offsetTop;

        this.dragThreshMet = false;

        this.clickTimeout = setTimeout(
                function() {
                    var DDM = Ext.dd.DragDropManager;
                    DDM.startDrag(DDM.startX, DDM.startY);
                },
                this.clickTimeThresh );
    },

    
    startDrag: function(x, y) {
        clearTimeout(this.clickTimeout);
        if (this.dragCurrent) {
            this.dragCurrent.b4StartDrag(x, y);
            this.dragCurrent.startDrag(x, y);
        }
        this.dragThreshMet = true;
    },

    
    handleMouseUp: function(e) {
        var current = this.dragCurrent;
        
        if(Ext.tip && Ext.tip.QuickTipManager){
            Ext.tip.QuickTipManager.ddEnable();
        }
        if (!current) {
            return;
        }
        
        
        if (Ext.isIE && document.releaseCapture) {
            document.releaseCapture();
        }

        clearTimeout(this.clickTimeout);

        if (this.dragThreshMet) {
            this.fireEvents(e, true);
        }

        this.stopDrag(e);

        this.stopEvent(e);
    },

    
    stopEvent: function(e){
        if(this.stopPropagation) {
            e.stopPropagation();
        }

        if (this.preventDefault) {
            e.preventDefault();
        }
    },

    
    stopDrag: function(e) {
        
        if (this.dragCurrent) {
            if (this.dragThreshMet) {
                this.dragCurrent.b4EndDrag(e);
                this.dragCurrent.endDrag(e);
            }

            this.dragCurrent.onMouseUp(e);
        }

        this.dragCurrent = null;
        this.dragOvers = {};
    },

    
    handleMouseMove: function(e) {
        var me = this,
            diffX,
            diffY;
            
        if (!me.dragCurrent) {
            return true;
        }

        if (!me.dragThreshMet) {
            diffX = Math.abs(me.startX - e.getPageX());
            diffY = Math.abs(me.startY - e.getPageY());
            if (diffX > me.clickPixelThresh ||
                        diffY > me.clickPixelThresh) {
                me.startDrag(me.startX, me.startY);
            }
        }

        if (me.dragThreshMet) {
            me.dragCurrent.b4Drag(e);
            me.dragCurrent.onDrag(e);
            if(!me.dragCurrent.moveOnly){
                me.fireEvents(e, false);
            }
        }

        me.stopEvent(e);

        return true;
    },

    
    fireEvents: function(e, isDrop) {
        var me = this,
            dragCurrent = me.dragCurrent,
            mousePoint = e.getPoint(),
            overTarget,
            overTargetEl,
            allTargets = [],
            oldOvers  = [],  
            outEvts   = [],
            overEvts  = [],
            dropEvts  = [],
            enterEvts = [],
            needsSort,
            i,
            len,
            sGroup;

        
        
        if (!dragCurrent || dragCurrent.isLocked()) {
            return;
        }

        
        
        for (i in me.dragOvers) {

            overTarget = me.dragOvers[i];

            if (! me.isTypeOfDD(overTarget)) {
                continue;
            }

            if (! this.isOverTarget(mousePoint, overTarget, me.mode)) {
                outEvts.push( overTarget );
            }

            oldOvers[i] = true;
            delete me.dragOvers[i];
        }

        
        
        
        for (sGroup in dragCurrent.groups) {

            if ("string" != typeof sGroup) {
                continue;
            }

            
            for (i in me.ids[sGroup]) {
                overTarget = me.ids[sGroup][i];

                
                
                
                
                
                
                if (me.isTypeOfDD(overTarget) &&
                        (overTargetEl = overTarget.getEl()) &&
                        (overTarget.isTarget) &&
                        (!overTarget.isLocked()) &&
                        (Ext.fly(overTargetEl).isVisible(true)) &&
                        ((overTarget != dragCurrent) || (dragCurrent.ignoreSelf === false))) {

                    
                    if ((overTarget.zIndex = me.getZIndex(overTargetEl)) !== -1) {
                        needsSort = true;
                    }
                    allTargets.push(overTarget);
                }
            }
        }

        
        if (needsSort) {
            Ext.Array.sort(allTargets, me.byZIndex);
        }

        
        
        for (i = 0, len = allTargets.length; i < len; i++) {
            overTarget = allTargets[i];

            
            if (me.isOverTarget(mousePoint, overTarget, me.mode)) {
                
                if (isDrop) {
                    dropEvts.push( overTarget );
                
                } else {

                    
                    if (!oldOvers[overTarget.id]) {
                        enterEvts.push( overTarget );
                    
                    } else {
                        overEvts.push( overTarget );
                    }
                    me.dragOvers[overTarget.id] = overTarget;
                }

                
                if (!me.notifyOccluded) {
                    break;
                }
            }
        }

        if (me.mode) {
            if (outEvts.length) {
                dragCurrent.b4DragOut(e, outEvts);
                dragCurrent.onDragOut(e, outEvts);
            }

            if (enterEvts.length) {
                dragCurrent.onDragEnter(e, enterEvts);
            }

            if (overEvts.length) {
                dragCurrent.b4DragOver(e, overEvts);
                dragCurrent.onDragOver(e, overEvts);
            }

            if (dropEvts.length) {
                dragCurrent.b4DragDrop(e, dropEvts);
                dragCurrent.onDragDrop(e, dropEvts);
            }

        } else {
            
            for (i=0, len=outEvts.length; i<len; ++i) {
                dragCurrent.b4DragOut(e, outEvts[i].id);
                dragCurrent.onDragOut(e, outEvts[i].id);
            }

            
            for (i=0,len=enterEvts.length; i<len; ++i) {
                
                dragCurrent.onDragEnter(e, enterEvts[i].id);
            }

            
            for (i=0,len=overEvts.length; i<len; ++i) {
                dragCurrent.b4DragOver(e, overEvts[i].id);
                dragCurrent.onDragOver(e, overEvts[i].id);
            }

            
            for (i=0, len=dropEvts.length; i<len; ++i) {
                dragCurrent.b4DragDrop(e, dropEvts[i].id);
                dragCurrent.onDragDrop(e, dropEvts[i].id);
            }

        }

        
        if (isDrop && !dropEvts.length) {
            dragCurrent.onInvalidDrop(e);
        }

    },

    
    getZIndex: function(element) {
        var body = document.body,
            z,
            zIndex = -1;

        element = Ext.getDom(element);
        while (element !== body) {
            if (!isNaN(z = Number(Ext.fly(element).getStyle('zIndex')))) {
                zIndex = z;
            }
            element = element.parentNode;
        }
        return zIndex;
    },

    
    byZIndex: function(d1, d2) {
        return d1.zIndex < d2.zIndex;
    },

    
    getBestMatch: function(dds) {
        var winner = null,
            len = dds.length,
            i, dd;
        
        
           
        
        


        if (len == 1) {
            winner = dds[0];
        } else {
            
            for (i=0; i<len; ++i) {
                dd = dds[i];
                
                
                
                if (dd.cursorIsOver) {
                    winner = dd;
                    break;
                
                } else {
                    if (!winner ||
                        winner.overlap.getArea() < dd.overlap.getArea()) {
                        winner = dd;
                    }
                }
            }
        }

        return winner;
    },

    
    refreshCache: function(groups) {
        var sGroup, i, oDD, loc;
        for (sGroup in groups) {
            if ("string" != typeof sGroup) {
                continue;
            }
            for (i in this.ids[sGroup]) {
                oDD = this.ids[sGroup][i];

                if (this.isTypeOfDD(oDD)) {
                
                    loc = this.getLocation(oDD);
                    if (loc) {
                        this.locationCache[oDD.id] = loc;
                    } else {
                        delete this.locationCache[oDD.id];
                        
                        
                        
                    }
                }
            }
        }
    },

    
    verifyEl: function(el) {
        if (el) {
            var parent;
            if(Ext.isIE){
                try{
                    parent = el.offsetParent;
                }catch(e){}
            }else{
                parent = el.offsetParent;
            }
            if (parent) {
                return true;
            }
        }

        return false;
    },

    
    getLocation: function(oDD) {
        if (! this.isTypeOfDD(oDD)) {
            return null;
        }

        
        
        if (oDD.getRegion) {
            return oDD.getRegion();
        }

        var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;

        try {
            pos= Ext.Element.getXY(el);
        } catch (e) { }

        if (!pos) {
            return null;
        }

        x1 = pos[0];
        x2 = x1 + el.offsetWidth;
        y1 = pos[1];
        y2 = y1 + el.offsetHeight;

        t = y1 - oDD.padding[0];
        r = x2 + oDD.padding[1];
        b = y2 + oDD.padding[2];
        l = x1 - oDD.padding[3];

        return new Ext.util.Region(t, r, b, l);
    },

    
    isOverTarget: function(pt, oTarget, intersect) {
        
        var loc = this.locationCache[oTarget.id],
            dc, pos, el, curRegion, overlap;
        if (!loc || !this.useCache) {
            loc = this.getLocation(oTarget);
            this.locationCache[oTarget.id] = loc;

        }

        if (!loc) {
            return false;
        }

        oTarget.cursorIsOver = loc.contains( pt );

        
        
        
        
        
        dc = this.dragCurrent;
        if (!dc || !dc.getTargetCoord ||
                (!intersect && !dc.constrainX && !dc.constrainY)) {
            return oTarget.cursorIsOver;
        }

        oTarget.overlap = null;

        
        
        
        
        pos = dc.getTargetCoord(pt.x, pt.y);

        el = dc.getDragEl();
        curRegion = new Ext.util.Region(pos.y,
                                               pos.x + el.offsetWidth,
                                               pos.y + el.offsetHeight,
                                               pos.x );

        overlap = curRegion.intersect(loc);

        if (overlap) {
            oTarget.overlap = overlap;
            return (intersect) ? true : oTarget.cursorIsOver;
        } else {
            return false;
        }
    },

    
    _onUnload: function(e, me) {
        Ext.dd.DragDropManager.unregAll();
    },

    
    unregAll: function() {

        if (this.dragCurrent) {
            this.stopDrag();
            this.dragCurrent = null;
        }

        this._execOnAll("unreg", []);

        for (var i in this.elementCache) {
            delete this.elementCache[i];
        }

        this.elementCache = {};
        this.ids = {};
    },

    
    elementCache: {},

    
    getElWrapper: function(id) {
        var oWrapper = this.elementCache[id];
        if (!oWrapper || !oWrapper.el) {
            oWrapper = this.elementCache[id] =
                new this.ElementWrapper(Ext.getDom(id));
        }
        return oWrapper;
    },

    
    getElement: function(id) {
        return Ext.getDom(id);
    },

    
    getCss: function(id) {
        var el = Ext.getDom(id);
        return (el) ? el.style : null;
    },

    
    ElementWrapper: function(el) {
        
        this.el = el || null;
        
        this.id = this.el && el.id;
        
        this.css = this.el && el.style;
    },

    
    

    
    getPosX: function(el) {
        return Ext.Element.getX(el);
    },

    
    getPosY: function(el) {
        return Ext.Element.getY(el);
    },

    
    swapNode: function(n1, n2) {
        if (n1.swapNode) {
            n1.swapNode(n2);
        } else {
            var p = n2.parentNode,
                s = n2.nextSibling;

            if (s == n1) {
                p.insertBefore(n1, n2);
            } else if (n2 == n1.nextSibling) {
                p.insertBefore(n2, n1);
            } else {
                n1.parentNode.replaceChild(n2, n1);
                p.insertBefore(n1, s);
            }
        }
    },

    
    getScroll: function () {
        var doc   = window.document,
            docEl = doc.documentElement,
            body  = doc.body,
            top   = 0,
            left  = 0;

        if (Ext.isGecko4) {
            top  = window.scrollYOffset;
            left = window.scrollXOffset;
        } else {
            if (docEl && (docEl.scrollTop || docEl.scrollLeft)) {
                top  = docEl.scrollTop;
                left = docEl.scrollLeft;
            } else if (body) {
                top  = body.scrollTop;
                left = body.scrollLeft;
            }
        }
        return {
            top: top,
            left: left
        };
    },

    
    getStyle: function(el, styleProp) {
        return Ext.fly(el).getStyle(styleProp);
    },

    
    getScrollTop: function () {
        return this.getScroll().top;
    },

    
    getScrollLeft: function () {
        return this.getScroll().left;
    },

    
    moveToEl: function (moveEl, targetEl) {
        var aCoord = Ext.Element.getXY(targetEl);
        Ext.Element.setXY(moveEl, aCoord);
    },

    
    numericSort: function(a, b) {
        return (a - b);
    },

    
    _timeoutCount: 0,

    
    _addListeners: function() {
        if ( document ) {
            this._onLoad();
        } else {
            if (this._timeoutCount <= 2000) {
                setTimeout(this._addListeners, 10);
                if (document && document.body) {
                    this._timeoutCount += 1;
                }
            }
        }
    },

    
    handleWasClicked: function(node, id) {
        if (this.isHandle(id, node.id)) {
            return true;
        } else {
            
            var p = node.parentNode;

            while (p) {
                if (this.isHandle(id, p.id)) {
                    return true;
                } else {
                    p = p.parentNode;
                }
            }
        }

        return false;
    }
}, function() {
    this._addListeners();
});


Ext.define('Ext.dd.DragTracker', {

    uses: ['Ext.util.Region'],

    mixins: {
        observable: 'Ext.util.Observable'
    },

    
    active: false,

    

    
    trackOver: false,

    

    

    
    tolerance: 5,

    
    autoStart: false,

    

    

    

    constructor : function(config){
        var me = this;
        Ext.apply(me, config);
        me.addEvents(
            
            'mouseover',

            
            'mouseout',

            
            'mousedown',

            
            'mouseup',

            
            'mousemove',

            
            'beforedragstart',

            
            'dragstart',

            
            'dragend',

            
            'drag'
        );

        me.dragRegion = new Ext.util.Region(0,0,0,0);

        if (me.el) {
            me.initEl(me.el);
        }

        
        me.mixins.observable.constructor.call(me);
        if (me.disabled) {
            me.disable();
        }

    },

    
    initEl: function(el) {
        var me = this;
        
        me.el = Ext.get(el);

        
        me.handle = Ext.get(me.delegate);

        
        me.delegate = me.handle ? undefined : me.delegate;

        if (!me.handle) {
            me.handle = me.el;
        }

        
        
        me.mon(me.handle, {
            mousedown: me.onMouseDown,
            delegate: me.delegate,
            scope: me
        });

        
        
        
        if (me.trackOver || me.overCls) {
            me.mon(me.handle, {
                mouseover: me.onMouseOver,
                mouseout: me.onMouseOut,
                delegate: me.delegate,
                scope: me
            });
        }
    },

    disable: function() {
        this.disabled = true;
    },

    enable: function() {
        this.disabled = false;
    },

    destroy : function() {
        this.clearListeners();
        delete this.el;
    },

    
    
    onMouseOver: function(e, target) {
        var me = this;
        if (!me.disabled) {
            if (Ext.EventManager.contains(e) || me.delegate) {
                me.mouseIsOut = false;
                if (me.overCls) {
                    me.el.addCls(me.overCls);
                }
                me.fireEvent('mouseover', me, e, me.delegate ? e.getTarget(me.delegate, target) : me.handle);
            }
        }
    },

    
    
    onMouseOut: function(e) {
        var me = this;
        
        if (me.mouseIsDown) {
            me.mouseIsOut = true;
        } else {
            if (me.overCls) {
                me.el.removeCls(me.overCls);
            }
            me.fireEvent('mouseout', me, e);
        }
    },

    onMouseDown: function(e, target){
        var me = this,
            el;
        
        
        if (me.disabled ||e.dragTracked) {
            return;
        }

        
        me.dragTarget = me.delegate ? target : me.handle.dom;
        me.startXY = me.lastXY = e.getXY();
        me.startRegion = Ext.fly(me.dragTarget).getRegion();

        if (me.fireEvent('mousedown', me, e) === false ||
            me.fireEvent('beforedragstart', me, e) === false ||
            me.onBeforeStart(e) === false) {
            return;
        }

        
        
        me.mouseIsDown = true;

        
        e.dragTracked = true;
        
        
        el = me.el.dom;
        if (Ext.isIE && el.setCapture) {
            el.setCapture();
        }

        if (me.preventDefault !== false) {
            e.preventDefault();
        }
        Ext.getDoc().on({
            scope: me,
            mouseup: me.onMouseUp,
            mousemove: me.onMouseMove,
            selectstart: me.stopSelect
        });
        if (me.autoStart) {
            me.timer =  Ext.defer(me.triggerStart, me.autoStart === true ? 1000 : me.autoStart, me, [e]);
        }
    },

    onMouseMove: function(e, target){
        var me = this,
            xy = e.getXY(),
            s = me.startXY;

        e.preventDefault();

        me.lastXY = xy;
        if (!me.active) {
            if (Math.max(Math.abs(s[0]-xy[0]), Math.abs(s[1]-xy[1])) > me.tolerance) {
                me.triggerStart(e);
            } else {
                return;
            }
        }

        
        if (me.fireEvent('mousemove', me, e) === false) {
            me.onMouseUp(e);
        } else {
            me.onDrag(e);
            me.fireEvent('drag', me, e);
        }
    },

    onMouseUp: function(e) {
        var me = this;
        
        
        me.mouseIsDown = false;

        
        if (me.mouseIsOut) {
            me.mouseIsOut = false;
            me.onMouseOut(e);
        }
        e.preventDefault();
        
        
        if (Ext.isIE && document.releaseCapture) {
            document.releaseCapture();
        }
        
        me.fireEvent('mouseup', me, e);
        me.endDrag(e);
    },

    
    endDrag: function(e) {
        var me = this,
            doc = Ext.getDoc(),
            wasActive = me.active;

        doc.un('mousemove', me.onMouseMove, me);
        doc.un('mouseup', me.onMouseUp, me);
        doc.un('selectstart', me.stopSelect, me);
        me.clearStart();
        me.active = false;
        if (wasActive) {
            me.onEnd(e);
            me.fireEvent('dragend', me, e);
        }
        
        delete me._constrainRegion;

        
        delete Ext.EventObject.dragTracked;
    },

    triggerStart: function(e) {
        var me = this;
        me.clearStart();
        me.active = true;
        me.onStart(e);
        me.fireEvent('dragstart', me, e);
    },

    clearStart : function() {
        var timer = this.timer;
        if (timer) {
            clearTimeout(timer);
            delete this.timer;
        }
    },

    stopSelect : function(e) {
        e.stopEvent();
        return false;
    },

    
    onBeforeStart : function(e) {

    },

    
    onStart : function(xy) {

    },

    
    onDrag : function(e) {

    },

    
    onEnd : function(e) {

    },

    
    getDragTarget : function(){
        return this.dragTarget;
    },

    
    getDragCt : function(){
        return this.el;
    },

    
    getConstrainRegion: function() {
        var me = this;
        
        if (me.constrainTo) {
            if (me.constrainTo instanceof Ext.util.Region) {
                return me.constrainTo;
            }
            if (!me._constrainRegion) {
                me._constrainRegion = Ext.fly(me.constrainTo).getViewRegion();
            }
        } else {
            if (!me._constrainRegion) {
                me._constrainRegion = me.getDragCt().getViewRegion();
            }
        }
        return me._constrainRegion;
    },

    getXY : function(constrain){
        return constrain ? this.constrainModes[constrain](this, this.lastXY) : this.lastXY;
    },

    
    getOffset : function(constrain){
        var xy = this.getXY(constrain),
            s = this.startXY;

        return [xy[0]-s[0], xy[1]-s[1]];
    },

    constrainModes: {
        
        point: function(me, xy) {
            var dr = me.dragRegion,
                constrainTo = me.getConstrainRegion();

            
            if (!constrainTo) {
                return xy;
            }

            dr.x = dr.left = dr[0] = dr.right = xy[0];
            dr.y = dr.top = dr[1] = dr.bottom = xy[1];
            dr.constrainTo(constrainTo);

            return [dr.left, dr.top];
        },

        
        dragTarget: function(me, xy) {
            var s = me.startXY,
                dr = me.startRegion.copy(),
                constrainTo = me.getConstrainRegion(),
                adjust;

            
            if (!constrainTo) {
                return xy;
            }

            
            
            
            dr.translateBy(xy[0]-s[0], xy[1]-s[1]);

            
            if (dr.right > constrainTo.right) {
                xy[0] += adjust = (constrainTo.right - dr.right);    
                dr.left += adjust;
            }
            if (dr.left < constrainTo.left) {
                xy[0] += (constrainTo.left - dr.left);      
            }

            
            if (dr.bottom > constrainTo.bottom) {
                xy[1] += adjust = (constrainTo.bottom - dr.bottom);  
                dr.top += adjust;
            }
            if (dr.top < constrainTo.top) {
                xy[1] += (constrainTo.top - dr.top);        
            }
            return xy;
        }
    }
});

Ext.define('Ext.dd.Registry', {
    singleton: true,
    constructor: function() {
        this.elements = {}; 
        this.handles = {}; 
        this.autoIdSeed = 0;
    },
    
    getId: function(el, autogen){
        if(typeof el == "string"){
            return el;
        }
        var id = el.id;
        if(!id && autogen !== false){
            id = "extdd-" + (++this.autoIdSeed);
            el.id = id;
        }
        return id;
    },
    
    
    register : function(el, data){
        data = data || {};
        if (typeof el == "string") {
            el = document.getElementById(el);
        }
        data.ddel = el;
        this.elements[this.getId(el)] = data;
        if (data.isHandle !== false) {
            this.handles[data.ddel.id] = data;
        }
        if (data.handles) {
            var hs = data.handles,
                i, len;
            for (i = 0, len = hs.length; i < len; i++) {
                this.handles[this.getId(hs[i])] = data;
            }
        }
    },

    
    unregister : function(el){
        var id = this.getId(el, false),
            data = this.elements[id],
            hs, i, len;
        if(data){
            delete this.elements[id];
            if(data.handles){
                hs = data.handles;
                for (i = 0, len = hs.length; i < len; i++) {
                    delete this.handles[this.getId(hs[i], false)];
                }
            }
        }
    },

    
    getHandle : function(id){
        if(typeof id != "string"){ 
            id = id.id;
        }
        return this.handles[id];
    },

    
    getHandleFromEvent : function(e){
        var t = e.getTarget();
        return t ? this.handles[t.id] : null;
    },

    
    getTarget : function(id){
        if(typeof id != "string"){ 
            id = id.id;
        }
        return this.elements[id];
    },

    
    getTargetFromEvent : function(e){
        var t = e.getTarget();
        return t ? this.elements[t.id] || this.handles[t.id] : null;
    }
});

Ext.define('Ext.dd.ScrollManager', {
    singleton: true,
    requires: [
        'Ext.dd.DragDropManager'
    ],

    constructor: function() {
        var ddm = Ext.dd.DragDropManager;
        ddm.fireEvents = Ext.Function.createSequence(ddm.fireEvents, this.onFire, this);
        ddm.stopDrag = Ext.Function.createSequence(ddm.stopDrag, this.onStop, this);
        this.doScroll = Ext.Function.bind(this.doScroll, this);
        this.ddmInstance = ddm;
        this.els = {};
        this.dragEl = null;
        this.proc = {};
    },

    onStop: function(e){
        var sm = Ext.dd.ScrollManager;
        sm.dragEl = null;
        sm.clearProc();
    },

    triggerRefresh: function() {
        if (this.ddmInstance.dragCurrent) {
            this.ddmInstance.refreshCache(this.ddmInstance.dragCurrent.groups);
        }
    },

    doScroll: function() {
        if (this.ddmInstance.dragCurrent) {
            var proc   = this.proc,
                procEl = proc.el,
                ddScrollConfig = proc.el.ddScrollConfig,
                inc = ddScrollConfig ? ddScrollConfig.increment : this.increment;

            if (!this.animate) {
                if (procEl.scroll(proc.dir, inc)) {
                    this.triggerRefresh();
                }
            } else {
                procEl.scroll(proc.dir, inc, true, this.animDuration, this.triggerRefresh);
            }
        }
    },

    clearProc: function() {
        var proc = this.proc;
        if (proc.id) {
            clearInterval(proc.id);
        }
        proc.id = 0;
        proc.el = null;
        proc.dir = "";
    },

    startProc: function(el, dir) {
        this.clearProc();
        this.proc.el = el;
        this.proc.dir = dir;
        var group = el.ddScrollConfig ? el.ddScrollConfig.ddGroup : undefined,
            freq  = (el.ddScrollConfig && el.ddScrollConfig.frequency)
                  ? el.ddScrollConfig.frequency
                  : this.frequency;

        if (group === undefined || this.ddmInstance.dragCurrent.ddGroup == group) {
            this.proc.id = setInterval(this.doScroll, freq);
        }
    },

    onFire: function(e, isDrop) {
        if (isDrop || !this.ddmInstance.dragCurrent) {
            return;
        }
        if (!this.dragEl || this.dragEl != this.ddmInstance.dragCurrent) {
            this.dragEl = this.ddmInstance.dragCurrent;
            
            this.refreshCache();
        }

        var xy = e.getXY(),
            pt = e.getPoint(),
            proc = this.proc,
            els = this.els,
            id, el, r, c;

        for (id in els) {
            el = els[id];
            r = el._region;
            c = el.ddScrollConfig ? el.ddScrollConfig : this;
            if (r && r.contains(pt) && el.isScrollable()) {
                if (r.bottom - pt.y <= c.vthresh) {
                    if(proc.el != el){
                        this.startProc(el, "down");
                    }
                    return;
                }else if (r.right - pt.x <= c.hthresh) {
                    if (proc.el != el) {
                        this.startProc(el, "left");
                    }
                    return;
                } else if(pt.y - r.top <= c.vthresh) {
                    if (proc.el != el) {
                        this.startProc(el, "up");
                    }
                    return;
                } else if(pt.x - r.left <= c.hthresh) {
                    if (proc.el != el) {
                        this.startProc(el, "right");
                    }
                    return;
                }
            }
        }
        this.clearProc();
    },

    
    register : function(el){
        if (Ext.isArray(el)) {
            for(var i = 0, len = el.length; i < len; i++) {
                    this.register(el[i]);
            }
        } else {
            el = Ext.get(el);
            this.els[el.id] = el;
        }
    },

    
    unregister : function(el){
        if(Ext.isArray(el)){
            for (var i = 0, len = el.length; i < len; i++) {
                this.unregister(el[i]);
            }
        }else{
            el = Ext.get(el);
            delete this.els[el.id];
        }
    },

    
    vthresh : 25,

    
    hthresh : 25,

    
    increment : 100,

    
    frequency : 500,

    
    animate: true,

    
    animDuration: 0.4,

    
    ddGroup: undefined,

    
    refreshCache : function(){
        var els = this.els,
            id;
        for (id in els) {
            if(typeof els[id] == 'object'){ 
                els[id]._region = els[id].getRegion();
            }
        }
    }
});


Ext.define('Ext.form.FieldAncestor', {

    


    
    initFieldAncestor: function() {
        var me = this,
            onSubtreeChange = me.onFieldAncestorSubtreeChange;

        me.addEvents(
            
            'fieldvaliditychange',

            
            'fielderrorchange'
        );

        
        me.on('add', onSubtreeChange, me);
        me.on('remove', onSubtreeChange, me);

        me.initFieldDefaults();
    },

    
    initFieldDefaults: function() {
        if (!this.fieldDefaults) {
            this.fieldDefaults = {};
        }
    },

    
    onFieldAncestorSubtreeChange: function(parent, child) {
        var me = this,
            isAdding = !!child.ownerCt;

        function handleCmp(cmp) {
            var isLabelable = cmp.isFieldLabelable,
                isField = cmp.isFormField;
            if (isLabelable || isField) {
                if (isLabelable) {
                    me['onLabelable' + (isAdding ? 'Added' : 'Removed')](cmp);
                }
                if (isField) {
                    me['onField' + (isAdding ? 'Added' : 'Removed')](cmp);
                }
            }
            else if (cmp.isContainer) {
                Ext.Array.forEach(cmp.getRefItems(), handleCmp);
            }
        }
        handleCmp(child);
    },

    
    onLabelableAdded: function(labelable) {
        var me = this;

        
        me.mon(labelable, 'errorchange', me.handleFieldErrorChange, me, {buffer: 10});

        labelable.setFieldDefaults(me.fieldDefaults);
    },

    
    onFieldAdded: function(field) {
        var me = this;
        me.mon(field, 'validitychange', me.handleFieldValidityChange, me);
    },

    
    onLabelableRemoved: function(labelable) {
        var me = this;
        me.mun(labelable, 'errorchange', me.handleFieldErrorChange, me);
    },

    
    onFieldRemoved: function(field) {
        var me = this;
        me.mun(field, 'validitychange', me.handleFieldValidityChange, me);
    },

    
    handleFieldValidityChange: function(field, isValid) {
        var me = this;
        me.fireEvent('fieldvaliditychange', me, field, isValid);
        me.onFieldValidityChange(field, isValid);
    },

    
    handleFieldErrorChange: function(labelable, activeError) {
        var me = this;
        me.fireEvent('fielderrorchange', me, labelable, activeError);
        me.onFieldErrorChange(labelable, activeError);
    },

    
    onFieldValidityChange: Ext.emptyFn,

    
    onFieldErrorChange: Ext.emptyFn

});

Ext.define('Ext.form.action.Action', {
    alternateClassName: 'Ext.form.Action',

    

    

    

    

    

    

    

    

    

    

    

    

    
    submitEmptyText : true,

    

    

    

    

    
    constructor: function(config) {
        if (config) {
            Ext.apply(this, config);
        }

        
        var params = config.params;
        if (Ext.isString(params)) {
            this.params = Ext.Object.fromQueryString(params);
        }
    },

    
    run: Ext.emptyFn,

    

    

    
    onFailure : function(response){
        this.response = response;
        this.failureType = Ext.form.action.Action.CONNECT_FAILURE;
        this.form.afterAction(this, false);
    },

    
    processResponse : function(response){
        this.response = response;
        if (!response.responseText && !response.responseXML) {
            return true;
        }
        return (this.result = this.handleResponse(response));
    },

    
    getUrl: function() {
        return this.url || this.form.url;
    },

    
    getMethod: function() {
        return (this.method || this.form.method || 'POST').toUpperCase();
    },

    
    getParams: function() {
        return Ext.apply({}, this.params, this.form.baseParams);
    },

    
    createCallback: function() {
        var me = this,
            undef,
            form = me.form;
        return {
            success: me.onSuccess,
            failure: me.onFailure,
            scope: me,
            timeout: (this.timeout * 1000) || (form.timeout * 1000),
            upload: form.fileUpload ? me.onSuccess : undef
        };
    },

    statics: {
        
        CLIENT_INVALID: 'client',

        
        SERVER_INVALID: 'server',

        
        CONNECT_FAILURE: 'connect',

        
        LOAD_FAILURE: 'load'


    }
});


Ext.define('Ext.form.action.Submit', {
    extend:'Ext.form.action.Action',
    alternateClassName: 'Ext.form.Action.Submit',
    alias: 'formaction.submit',

    type: 'submit',

    

    
    run : function(){
        var form = this.form;
        if (this.clientValidation === false || form.isValid()) {
            this.doSubmit();
        } else {
            
            this.failureType = Ext.form.action.Action.CLIENT_INVALID;
            form.afterAction(this, false);
        }
    },

    
    doSubmit: function() {
        var formEl,
            ajaxOptions = Ext.apply(this.createCallback(), {
                url: this.getUrl(),
                method: this.getMethod(),
                headers: this.headers
            });

        
        
        if (this.form.hasUpload()) {
            formEl = ajaxOptions.form = this.buildForm();
            ajaxOptions.isUpload = true;
        } else {
            ajaxOptions.params = this.getParams();
        }

        Ext.Ajax.request(ajaxOptions);

        if (formEl) {
            Ext.removeNode(formEl);
        }
    },

    
    getParams: function() {
        var nope = false,
            configParams = this.callParent(),
            fieldParams = this.form.getValues(nope, nope, this.submitEmptyText !== nope);
        return Ext.apply({}, fieldParams, configParams);
    },

    
    buildForm: function() {
        var fieldsSpec = [],
            formSpec,
            formEl,
            basicForm = this.form,
            params = this.getParams(),
            uploadFields = [],
            fields = basicForm.getFields().items,
            f,
            fLen   = fields.length,
            field, key, value, v, vLen,
            u, uLen;

        for (f = 0; f < fLen; f++) {
            field = fields[f];

            if (field.isFileUpload()) {
                uploadFields.push(field);
            }
        }

        function addField(name, val) {
            fieldsSpec.push({
                tag: 'input',
                type: 'hidden',
                name: name,
                value: Ext.String.htmlEncode(val)
            });
        }

        for (key in params) {
            if (params.hasOwnProperty(key)) {
                value = params[key];

                if (Ext.isArray(value)) {
                    vLen = value.length;
                    for (v = 0; v < vLen; v++) {
                        addField(key, value[v]);
                    }
                } else {
                    addField(key, value);
                }
            }
        }

        formSpec = {
            tag: 'form',
            action: this.getUrl(),
            method: this.getMethod(),
            target: this.target || '_self',
            style: 'display:none',
            cn: fieldsSpec
        };

        
        if (uploadFields.length) {
            formSpec.encoding = formSpec.enctype = 'multipart/form-data';
        }

        
        formEl = Ext.DomHelper.append(Ext.getBody(), formSpec);

        
        
        
        uLen = uploadFields.length;

        for (u = 0; u < uLen; u++) {
            field = uploadFields[u];
            if (field.rendered) { 
                formEl.appendChild(field.extractFileInput());
            }
        }

        return formEl;
    },



    
    onSuccess: function(response) {
        var form = this.form,
            success = true,
            result = this.processResponse(response);
        if (result !== true && !result.success) {
            if (result.errors) {
                form.markInvalid(result.errors);
            }
            this.failureType = Ext.form.action.Action.SERVER_INVALID;
            success = false;
        }
        form.afterAction(this, success);
    },

    
    handleResponse: function(response) {
        var form = this.form,
            errorReader = form.errorReader,
            rs, errors, i, len, records;
        if (errorReader) {
            rs = errorReader.read(response);
            records = rs.records;
            errors = [];
            if (records) {
                for(i = 0, len = records.length; i < len; i++) {
                    errors[i] = records[i].data;
                }
            }
            if (errors.length < 1) {
                errors = null;
            }
            return {
                success : rs.success,
                errors : errors
            };
        }
        return Ext.decode(response.responseText);
    }
});


Ext.define('Ext.form.field.Field', {
    
    isFormField : true,

    

    

    
    disabled : false,

    
    submitValue: true,

    
    validateOnChange: true,

    
    suspendCheckChange: 0,

    
    initField: function() {
        this.addEvents(
            
            'change',
            
            'validitychange',
            
            'dirtychange'
        );

        this.initValue();
    },

    
    initValue: function() {
        var me = this;

        me.value = me.transformOriginalValue(me.value);
        
        me.originalValue = me.lastValue = me.value;

        
        me.suspendCheckChange++;
        me.setValue(me.value);
        me.suspendCheckChange--;
    },
    
    
    transformOriginalValue: function(value){
        return value;
    },

    
    getName: function() {
        return this.name;
    },

    
    getValue: function() {
        return this.value;
    },

    
    setValue: function(value) {
        var me = this;
        me.value = value;
        me.checkChange();
        return me;
    },

    
    isEqual: function(value1, value2) {
        return String(value1) === String(value2);
    },

    
    isEqualAsString: function(value1, value2){
        return String(Ext.value(value1, '')) === String(Ext.value(value2, ''));
    },

    
    getSubmitData: function() {
        var me = this,
            data = null;
        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
            data = {};
            data[me.getName()] = '' + me.getValue();
        }
        return data;
    },

    
    getModelData: function() {
        var me = this,
            data = null;
        if (!me.disabled && !me.isFileUpload()) {
            data = {};
            data[me.getName()] = me.getValue();
        }
        return data;
    },

    
    reset : function(){
        var me = this;

        me.beforeReset();
        me.setValue(me.originalValue);
        me.clearInvalid();
        
        delete me.wasValid;
    },
    
    
    beforeReset: Ext.emptyFn,

    
    resetOriginalValue: function() {
        this.originalValue = this.getValue();
        this.checkDirty();
    },

    
    checkChange: function() {
        if (!this.suspendCheckChange) {
            var me = this,
                newVal = me.getValue(),
                oldVal = me.lastValue;
            if (!me.isEqual(newVal, oldVal) && !me.isDestroyed) {
                me.lastValue = newVal;
                me.fireEvent('change', me, newVal, oldVal);
                me.onChange(newVal, oldVal);
            }
        }
    },

    
    onChange: function(newVal, oldVal) {
        if (this.validateOnChange) {
            this.validate();
        }
        this.checkDirty();
    },

    
    isDirty : function() {
        var me = this;
        return !me.disabled && !me.isEqual(me.getValue(), me.originalValue);
    },

    
    checkDirty: function() {
        var me = this,
            isDirty = me.isDirty();
        if (isDirty !== me.wasDirty) {
            me.fireEvent('dirtychange', me, isDirty);
            me.onDirtyChange(isDirty);
            me.wasDirty = isDirty;
        }
    },

    
    onDirtyChange: Ext.emptyFn,

    
    getErrors: function(value) {
        return [];
    },

    
    isValid : function() {
        var me = this;
        return me.disabled || Ext.isEmpty(me.getErrors());
    },

    
    validate : function() {
        var me = this,
            isValid = me.isValid();
        if (isValid !== me.wasValid) {
            me.wasValid = isValid;
            me.fireEvent('validitychange', me, isValid);
        }
        return isValid;
    },

    
    batchChanges: function(fn) {
        try {
            this.suspendCheckChange++;
            fn();
        } catch(e){
            throw e;
        } finally {
            this.suspendCheckChange--;
        }
        this.checkChange();
    },

    
    isFileUpload: function() {
        return false;
    },

    
    extractFileInput: function() {
        return null;
    },

    
    markInvalid: Ext.emptyFn,

    
    clearInvalid: Ext.emptyFn

});


Ext.define('Ext.form.field.VTypes', (function(){
    
    var alpha = /^[a-zA-Z_]+$/,
        alphanum = /^[a-zA-Z0-9_]+$/,
        email = /^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,6}$/,
        url = /(((^https?)|(^ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;

    
    return {
        singleton: true,
        alternateClassName: 'Ext.form.VTypes',

        
        'email' : function(v){
            return email.test(v);
        },
        
        
        'emailText' : 'This field should be an e-mail address in the format "user@example.com"',
        
        
        'emailMask' : /[a-z0-9_\.\-@\+]/i,

        
        'url' : function(v){
            return url.test(v);
        },
        
        
        'urlText' : 'This field should be a URL in the format "http:/'+'/www.example.com"',
        

        
        'alpha' : function(v){
            return alpha.test(v);
        },
        
        
        'alphaText' : 'This field should only contain letters and _',
        
        
        'alphaMask' : /[a-z_]/i,

        
        'alphanum' : function(v){
            return alphanum.test(v);
        },
        
        
        'alphanumText' : 'This field should only contain letters, numbers and _',
        
        
        'alphanumMask' : /[a-z0-9_]/i
    };
}()));


Ext.define('Ext.grid.LockingView', {

    mixins: {
        observable: 'Ext.util.Observable'
    },

    eventRelayRe: /^(beforeitem|beforecontainer|item|container|cell)/,

    constructor: function(config){
        var me = this,
            eventNames = [],
            eventRe = me.eventRelayRe,
            locked = config.locked.getView(),
            normal = config.normal.getView(),
            events,
            event;

        Ext.apply(me, {
            lockedView: locked,
            normalView: normal,
            lockedGrid: config.locked,
            normalGrid: config.normal,
            panel: config.panel
        });
        me.mixins.observable.constructor.call(me, config);

        
        events = locked.events;
        for (event in events) {
            if (events.hasOwnProperty(event) && eventRe.test(event)) {
                eventNames.push(event);
            }
        }
        me.relayEvents(locked, eventNames);
        me.relayEvents(normal, eventNames);

        normal.on({
            scope: me,
            itemmouseleave: me.onItemMouseLeave,
            itemmouseenter: me.onItemMouseEnter
        });

        locked.on({
            scope: me,
            itemmouseleave: me.onItemMouseLeave,
            itemmouseenter: me.onItemMouseEnter
        });
    },

    getGridColumns: function() {
        var cols = this.lockedGrid.headerCt.getGridColumns();
        return cols.concat(this.normalGrid.headerCt.getGridColumns());
    },

    getEl: function(column){
        return this.getViewForColumn(column).getEl();
    },

    getViewForColumn: function(column) {
        var view = this.lockedView,
            inLocked;

        view.headerCt.cascade(function(col){
            if (col === column) {
                inLocked = true;
                return false;
            }
        });

        return inLocked ? view : this.normalView;
    },

    onItemMouseEnter: function(view, record){
        var me = this,
            locked = me.lockedView,
            other = me.normalView,
            item;

        if (view.trackOver) {
            if (view !== locked) {
                other = locked;
            }
            item = other.getNode(record);
            other.highlightItem(item);
        }
    },

    onItemMouseLeave: function(view, record){
        var me = this,
            locked = me.lockedView,
            other = me.normalView;

        if (view.trackOver) {
            if (view !== locked) {
                other = locked;
            }
            other.clearHighlight();
        }
    },

    relayFn: function(name, args){
        args = args || [];

        var view = this.lockedView;
        view[name].apply(view, args || []);
        view = this.normalView;
        view[name].apply(view, args || []);
    },

    getSelectionModel: function(){
        return this.panel.getSelectionModel();
    },

    getStore: function(){
        return this.panel.store;
    },

    getNode: function(nodeInfo){
        
        return this.normalView.getNode(nodeInfo);
    },

    getCell: function(record, column){
        var view = this.getViewForColumn(column),
            row;

        row = view.getNode(record);
        return Ext.fly(row).down(column.getCellSelector());
    },

    getRecord: function(node){
        var result = this.lockedView.getRecord(node);
        if (!node) {
            result = this.normalView.getRecord(node);
        }
        return result;
    },

    addElListener: function(eventName, fn, scope){
        this.relayFn('addElListener', arguments);
    },

    refreshNode: function(){
        this.relayFn('refreshNode', arguments);
    },

    refresh: function(){
        this.relayFn('refresh', arguments);
    },

    bindStore: function(){
        this.relayFn('bindStore', arguments);
    },

    addRowCls: function(){
        this.relayFn('addRowCls', arguments);
    },

    removeRowCls: function(){
        this.relayFn('removeRowCls', arguments);
    }

});

Ext.define('Ext.grid.PagingScroller', {

    
    percentageFromEdge: 0.35,

    
    numFromEdge: 2,

    
    trailingBufferZone: 5,

    
    leadingBufferZone: 15,

    
    scrollToLoadBuffer: 200,

    
    viewSize: 0,
    
    rowHeight: 21,
    
    tableStart: 0,
    tableEnd: 0,

    constructor: function(config) {
        var me = this;
        me.variableRowHeight = config.variableRowHeight;
        me.bindView(config.view);
        Ext.apply(me, config);
        me.callParent(arguments);
    },

    bindView: function(view) {
        var me = this,
            viewListeners = {
                scroll: {
                    fn: me.onViewScroll,
                    element: 'el',
                    scope: me
                },
                render: me.onViewRender,
                resize: me.onViewResize,
                boxready: {
                    fn: me.onViewResize,
                    scope: me,
                    single: true
                },

                
                
                
                beforerefresh: me.beforeViewRefresh,

                refresh: me.onViewRefresh,
                scope: me
            },
            storeListeners = {
                guaranteedrange: me.onGuaranteedRange,
                scope: me
            },
            gridListeners = {
                reconfigure: me.onGridReconfigure,
                scope: me
            }, partner;

        
        if (me.view) {
            if (me.view.el) {
                me.view.el.un('scroll', me.onViewScroll, me); 
            }
            
            partner = view.lockingPartner;
            if (partner) {
                partner.un('refresh', me.onLockRefresh, me);
            }
            
            me.view.un(viewListeners);
            me.store.un(storeListeners);
            if (me.grid) {
                me.grid.un(gridListeners);
            }
            delete me.view.refreshSize; 
        }

        me.view = view;
        me.grid = me.view.up('tablepanel');
        me.store = view.store;
        if (view.rendered) {
            me.viewSize = me.store.viewSize = Math.ceil(view.getHeight() / me.rowHeight) + me.trailingBufferZone + (me.numFromEdge * 2) + me.leadingBufferZone;
        }
        
        partner = view.lockingPartner;
        if (partner) {
            partner.on('refresh', me.onLockRefresh, me);
        }

        me.view.mon(me.store.pageMap, {
            scope: me,
            clear: me.onCacheClear
        });

        
        
        
        me.view.refreshSize = Ext.Function.createInterceptor(me.view.refreshSize, me.beforeViewrefreshSize, me);

        
        me.position = 0;

        
        if (me.grid) {
            me.grid.on(gridListeners);
        } else {
            me.view.on({
                added: function() {
                    me.grid = me.view.up('tablepanel');
                    me.grid.on(gridListeners);
                },
                single: true
            });
        }

        me.view.on(me.viewListeners = viewListeners);
        me.store.on(storeListeners);
    },

    onCacheClear: function() {
        var me = this;

        
        if (me.view.rendered && !me.store.isDestroyed) {
            
            
            me.ignoreNextScrollEvent = me.view.el.dom.scrollTop !== 0;

            me.view.el.dom.scrollTop = 0;
            delete me.lastScrollDirection;
            delete me.scrollOffset;
            delete me.scrollProportion;
        }
    },

    onGridReconfigure: function (grid) {
        this.bindView(grid.view);
    },

    
    onViewRender: function() {
        var me = this,
            view = me.view,
            el = me.view.el,
            stretcher;

        me.stretcher = me.createStretcher(view);
        
        view = view.lockingPartner;
        if (view) {
            stretcher = me.stretcher;
            me.stretcher = new Ext.CompositeElement(stretcher);
            me.stretcher.add(me.createStretcher(view));
        }
    },
    
    createStretcher: function(view) {
        var el = view.el;
        el.setStyle('position', 'relative');
        
        return el.createChild({
            style:{
                position: 'absolute',
                width: '1px',
                height: 0,
                top: 0,
                left: 0
            }
        }, el.dom.firstChild);
    },
    
    onViewResize: function(view, width, height) {
        var me = this,
            newViewSize;

        newViewSize = Math.ceil(height / me.rowHeight) + me.trailingBufferZone + (me.numFromEdge * 2) + me.leadingBufferZone;
        if (newViewSize > me.viewSize) {
            me.viewSize = me.store.viewSize = newViewSize;
            me.handleViewScroll(me.lastScrollDirection || 1);
        }
    },

    
    beforeViewRefresh: function() {
        var me = this,
            view = me.view,
            rows,
            direction;

        
        me.focusOnRefresh = Ext.Element.getActiveElement === view.el.dom;

        
        if (me.variableRowHeight) {
            direction = me.lastScrollDirection;
            me.commonRecordIndex = undefined;
            
            
            
            
            if (direction && (me.previousStart !== undefined) && (me.scrollProportion === undefined) && (rows = view.getNodes()).length) {

                
                if (direction === 1) {

                    
                    if (me.tableStart <= me.previousEnd) {
                        me.commonRecordIndex = rows.length - 1;

                    }
                }
                
                else if (direction === -1) {

                    
                    if (me.tableEnd >= me.previousStart) {
                        me.commonRecordIndex = 0;
                    }
                }
                
                me.scrollOffset = -view.el.getOffsetsTo(rows[me.commonRecordIndex])[1];

                
                me.commonRecordIndex -= (me.tableStart - me.previousStart);
            } else {
                me.scrollOffset = undefined;
            }
        }
    },

    onLockRefresh: function(view) {
        view.table.dom.style.position = 'absolute';
    },

    
    
    onViewRefresh: function() {
        var me = this,
            store = me.store,
            newScrollHeight,
            view = me.view,
            viewEl = view.el,
            viewDom = viewEl.dom,
            rows,
            newScrollOffset,
            scrollDelta,
            table = view.table.dom,
            tableTop,
            scrollTop;

        
        if (me.focusOnRefresh) {
            viewEl.focus();
            me.focusOnRefresh = false;
        }

        
        me.disabled = true;

        
        
        
        
        
        if (store.getCount() === store.getTotalCount() || (store.isFiltered() && !store.remoteFilter)) {
            me.stretcher.setHeight(0);
            me.position = viewDom.scrollTop = 0;

            
            
            me.setTablePosition('absolute');

            
            return;
        }

        me.stretcher.setHeight(newScrollHeight = me.getScrollHeight());

        scrollTop = viewDom.scrollTop;

        
        me.isScrollRefresh = (scrollTop > 0);

        
        
        if (me.scrollProportion !== undefined) {
            me.setTablePosition('absolute');
            me.setTableTop((me.scrollProportion ? (newScrollHeight * me.scrollProportion) - (table.offsetHeight * me.scrollProportion) : 0) + 'px');
        } else {
            me.setTablePosition('absolute');
            me.setTableTop((tableTop = (me.tableStart||0) * me.rowHeight) + 'px');

            
            if (me.scrollOffset) {
                rows = view.getNodes();
                newScrollOffset = -viewEl.getOffsetsTo(rows[me.commonRecordIndex])[1];
                scrollDelta = newScrollOffset - me.scrollOffset;
                me.position = (viewDom.scrollTop += scrollDelta);
            }

            
            
            
            
            
            
            else if ((tableTop > scrollTop) || ((tableTop + table.offsetHeight) < scrollTop + viewDom.clientHeight)) {
                me.lastScrollDirection = -1;
                me.position = viewDom.scrollTop = tableTop;
            }
        }

        
        me.disabled = false;
    },
    
    setTablePosition: function(position) {
        this.setViewTableStyle(this.view, 'position', position);
    },
    
    setTableTop: function(top){
        this.setViewTableStyle(this.view, 'top', top);
    },
    
    setViewTableStyle: function(view, prop, value) {
        view.el.child('table', true).style[prop] = value;
        view = view.lockingPartner;
        
        if (view) {
            view.el.child('table', true).style[prop] = value;
        }
    },

    beforeViewrefreshSize: function() {
        
        if (this.isScrollRefresh) {
            
            this.view.table.attach(this.view.el.child('table', true));
            return (this.isScrollRefresh = false);
        }
    },

    onGuaranteedRange: function(range, start, end) {
        var me = this,
            ds = me.store;

        
        if (range.length && me.visibleStart < range[0].index) {
            return;
        }

        
        
        me.previousStart = me.tableStart;
        me.previousEnd = me.tableEnd;

        me.tableStart = start;
        me.tableEnd = end;
        ds.loadRecords(range, {
            start: start
        });
    },

    onViewScroll: function(e, t) {
        var me = this,
            view = me.view,
            lastPosition = me.position;

        me.position = view.el.dom.scrollTop;

        
        
        if (me.ignoreNextScrollEvent) {
            me.ignoreNextScrollEvent = false;
            return;
        }

        
        
        if (!me.disabled) {
            me.lastScrollDirection = me.position > lastPosition ? 1 : -1;
            
            if (lastPosition !== me.position) {
                me.handleViewScroll(me.lastScrollDirection);
            }
        }
    },

    handleViewScroll: function(direction) {
        var me                = this,
            store             = me.store,
            view              = me.view,
            viewSize          = me.viewSize,
            totalCount        = store.getTotalCount(),
            highestStartPoint = totalCount - viewSize,
            visibleStart      = me.getFirstVisibleRowIndex(),
            visibleEnd        = me.getLastVisibleRowIndex(),
            el                = view.el.dom,
            requestStart,
            requestEnd;

        
        if (totalCount >= viewSize) {

            
            
            
            
            me.scrollProportion = undefined;

            
            if (direction == -1) {

                
                if (me.tableStart) {
                    if (visibleStart !== undefined) {
                        if (visibleStart < (me.tableStart + me.numFromEdge)) {
                            requestStart = Math.max(0, visibleEnd + me.trailingBufferZone - viewSize);
                        }
                    }

                    
                    
                    else {
                        
                        me.scrollProportion = el.scrollTop / (el.scrollHeight - el.clientHeight);
                        requestStart = Math.max(0, totalCount * me.scrollProportion - (viewSize / 2) - me.numFromEdge - ((me.leadingBufferZone + me.trailingBufferZone) / 2));
                    }
                }
            }
            
            else {
                if (visibleStart !== undefined) {
                    if (visibleEnd > (me.tableEnd - me.numFromEdge)) {
                        requestStart = Math.max(0, visibleStart - me.trailingBufferZone);
                    }
                }

                
                
                else {
                    
                    me.scrollProportion = el.scrollTop / (el.scrollHeight - el.clientHeight);
                    requestStart = totalCount * me.scrollProportion - (viewSize / 2) - me.numFromEdge - ((me.leadingBufferZone + me.trailingBufferZone) / 2);
                }
            }

            
            if (requestStart !== undefined) {
                
                if (requestStart > highestStartPoint) {
                    requestStart = highestStartPoint & ~1;
                    requestEnd = totalCount - 1;
                }
                
                else {
                    requestStart = requestStart & ~1;
                    requestEnd = requestStart + viewSize - 1;
                }

                
                if (store.rangeCached(requestStart, requestEnd)) {
                    me.cancelLoad();
                    store.guaranteeRange(requestStart, requestEnd);
                }

                
                
                else {
                    me.attemptLoad(requestStart, requestEnd);
                }
            }
        }
    },

    getFirstVisibleRowIndex: function() {
        var me = this,
            view = me.view,
            scrollTop = view.el.dom.scrollTop,
            rows,
            count,
            i,
            rowBottom;

        if (me.variableRowHeight) {
            rows = view.getNodes();
            count = rows.length;
            if (!count) {
                return;
            }
            rowBottom = Ext.fly(rows[0]).getOffsetsTo(view.el)[1];
            for (i = 0; i < count; i++) {
                rowBottom += rows[i].offsetHeight;

                
                if (rowBottom > view.el.dom.clientHeight) {
                    return;
                }

                
                
                if (rowBottom > 0) {
                    return view.getRecord(rows[i]).index;
                }
            }
        } else {
            return Math.floor(scrollTop / me.rowHeight);
        }
    },

    getLastVisibleRowIndex: function() {
        var me = this,
            store = me.store,
            view = me.view,
            clientHeight = view.el.dom.clientHeight,
            rows,
            count,
            i,
            rowTop;

        if (me.variableRowHeight) {
            rows = view.getNodes();
            if (!rows.length) {
                return;
            }
            count = store.getCount() - 1;
            rowTop = Ext.fly(rows[count]).getOffsetsTo(view.el)[1] + rows[count].offsetHeight;
            for (i = count; i >= 0; i--) {
                rowTop -= rows[i].offsetHeight;

                
                if (rowTop < 0) {
                    return;
                }

                
                
                if (rowTop < clientHeight) {
                    return view.getRecord(rows[i]).index;
                }
            }
        } else {
            return me.getFirstVisibleRowIndex() + Math.ceil(clientHeight / me.rowHeight) + 1;
        }
    },

    getScrollHeight: function() {
        var me = this,
            view   = me.view,
            table,
            firstRow,
            store  = me.store,
            deltaHeight = 0,
            doCalcHeight = !me.hasOwnProperty('rowHeight');

        if (me.variableRowHeight) {
            table = me.view.table.dom;
            if (doCalcHeight) {
                me.initialTableHeight = table.offsetHeight;
                me.rowHeight = me.initialTableHeight / me.store.getCount();
            } else {
                deltaHeight = table.offsetHeight - me.initialTableHeight;

                
                if (store.getCount() > me.viewSize) {
                    deltaHeight -= me.rowHeight;
                }
            }
        } else if (doCalcHeight) {
            firstRow = view.el.down(view.getItemSelector());
            if (firstRow) {
                me.rowHeight = firstRow.getHeight(false, true);
            }
        }

        return Math.floor(store.getTotalCount() * me.rowHeight) + deltaHeight;
    },

    attemptLoad: function(start, end) {
        var me = this;
        if (me.scrollToLoadBuffer) {
            if (!me.loadTask) {
                me.loadTask = new Ext.util.DelayedTask(me.doAttemptLoad, me, []);
            }
            me.loadTask.delay(me.scrollToLoadBuffer, me.doAttemptLoad, me, [start, end]);
        } else {
            me.store.guaranteeRange(start, end);
        }
    },

    cancelLoad: function() {
        if (this.loadTask) {
            this.loadTask.cancel();
        }
    },

    doAttemptLoad:  function(start, end) {
        this.store.guaranteeRange(start, end);
    },

    destroy: function() {
        var me = this,
            scrollListener = me.viewListeners.scroll;

        me.store.un({
            guaranteedrange: me.onGuaranteedRange,
            scope: me
        });
        me.view.un(me.viewListeners);
        if (me.view.rendered) {
            me.stretcher.remove();
            me.view.el.un('scroll', scrollListener.fn, scrollListener.scope);
        }
    }
});



Ext.define('Ext.grid.feature.Feature', {
    extend: 'Ext.util.Observable',
    alias: 'feature.feature',

    
    isFeature: true,

    
    disabled: false,

    
    hasFeatureEvent: true,

    
    eventPrefix: null,

    
    eventSelector: null,

    
    view: null,

    
    grid: null,

    
    collectData: false,
    
    constructor: function(config) {
        this.initialConfig = config;
        this.callParent(arguments);
    },

    clone: function() {
        return new this.self(this.initialConfig);
    },

    init: Ext.emptyFn,

    getFeatureTpl: function() {
        return '';
    },

    
    getFireEventArgs: function(eventName, view, featureTarget, e) {
        return [eventName, view, featureTarget, e];
    },

    
    attachEvents: function() {

    },

    getFragmentTpl: Ext.emptyFn,

    
    mutateMetaRowTpl: Ext.emptyFn,

    
    getMetaRowTplFragments: function() {
        return {};
    },

    getTableFragments: function() {
        return {};
    },

    
    getAdditionalData: function(data, idx, record, orig) {
        return {};
    },

    
    enable: function() {
        this.disabled = false;
    },

    
    disable: function() {
        this.disabled = true;
    }

});

Ext.define('Ext.grid.feature.Grouping', {
    extend: 'Ext.grid.feature.Feature',
    alias: 'feature.grouping',

    eventPrefix: 'group',
    eventSelector: '.' + Ext.baseCSSPrefix + 'grid-group-hd',
    bodySelector: '.' + Ext.baseCSSPrefix + 'grid-group-body',

    constructor: function() {
        var me = this;

        me.collapsedState = {};
        me.callParent(arguments);
    },
    
    

    

    

    

    

    
    groupHeaderTpl: '{columnName}: {name}',
    
    
    depthToIndent: 17,

    collapsedCls: Ext.baseCSSPrefix + 'grid-group-collapsed',
    hdCollapsedCls: Ext.baseCSSPrefix + 'grid-group-hd-collapsed',
    hdCollapsibleCls: Ext.baseCSSPrefix + 'grid-group-hd-collapsible',

    
    
    groupByText : 'Group by this field',
    
    
    
    showGroupsText : 'Show in groups',
    

    
    hideGroupedHeader : false,

    
    startCollapsed : false,

    
    enableGroupingMenu : true,

    
    enableNoGroups : true,

    
    collapsible: true,

    enable: function() {
        var me    = this,
            view  = me.view,
            store = view.store,
            groupToggleMenuItem;

        me.lastGroupField = me.getGroupField();

        if (me.lastGroupIndex) {
            me.block();
            store.group(me.lastGroupIndex);
            me.unblock();
        }
        me.callParent();
        groupToggleMenuItem = me.view.headerCt.getMenu().down('#groupToggleMenuItem');
        groupToggleMenuItem.setChecked(true, true);
        me.refreshIf();
    },

    disable: function() {
        var me    = this,
            view  = me.view,
            store = view.store,
            remote = store.remoteGroup,
            groupToggleMenuItem,
            lastGroup;

        lastGroup = store.groupers.first();
        if (lastGroup) {
            me.lastGroupIndex = lastGroup.property;
            me.block();
            store.clearGrouping();
            me.unblock();
        }

        me.callParent();
        groupToggleMenuItem = me.view.headerCt.getMenu().down('#groupToggleMenuItem');
        groupToggleMenuItem.setChecked(true, true);
        groupToggleMenuItem.setChecked(false, true);
        me.refreshIf();
    },

    refreshIf: function() {
        var ownerCt = this.grid.ownerCt,
            view = this.view;
            
        if (!view.store.remoteGroup && !this.blockRefresh) {

            
            if (ownerCt && ownerCt.lockable) {
                ownerCt.view.refresh();
            } else {
                view.refresh();
            }
        }
    },

    getFeatureTpl: function(values, parent, x, xcount) {
        return [
            '<tpl if="typeof rows !== \'undefined\'">',
                
                '<tr id="{groupHeaderId}" class="' + Ext.baseCSSPrefix + 'grid-group-hd {hdCollapsedCls} {collapsibleClass}"><td class="' + Ext.baseCSSPrefix + 'grid-cell" colspan="' + parent.columns.length + '" {[this.indentByDepth(values)]}><div class="' + Ext.baseCSSPrefix + 'grid-cell-inner"><div class="' + Ext.baseCSSPrefix + 'grid-group-title">{collapsed}{[this.renderGroupHeaderTpl(values, parent)]}</div></div></td></tr>',
                
                '<tr id="{groupBodyId}" class="' + Ext.baseCSSPrefix + 'grid-group-body {collapsedCls}"><td colspan="' + parent.columns.length + '">{[this.recurse(values)]}</td></tr>',
            '</tpl>'
        ].join('');
    },

    getFragmentTpl: function() {
        var me = this;
        return {
            indentByDepth: me.indentByDepth,
            depthToIndent: me.depthToIndent,
            renderGroupHeaderTpl: function(values, parent) {
                return Ext.XTemplate.getTpl(me, 'groupHeaderTpl').apply(values, parent);
            }
        };
    },

    indentByDepth: function(values) {
        return 'style="padding-left:'+ ((values.depth || 0) * this.depthToIndent) + 'px;"';
    },

    
    
    destroy: function() {
        delete this.view;
        delete this.prunedHeader;
    },

    
    attachEvents: function() {
        var me = this,
            view = me.view;

        view.on({
            scope: me,
            groupclick: me.onGroupClick,
            rowfocus: me.onRowFocus
        });

        view.mon(view.store, {
            scope: me,
            groupchange: me.onGroupChange,
            remove: me.onRemove,
            add: me.onAdd,
            update: me.onUpdate
        });

        if (me.enableGroupingMenu) {
            me.injectGroupingMenu();
        }

        me.pruneGroupedHeader();

        me.lastGroupField = me.getGroupField();
        me.block();
        me.onGroupChange();
        me.unblock();
    },

    
    onAdd: function(store, records){
        var me = this,
            view = me.view,
            groupField = me.getGroupField(),
            i = 0,
            len = records.length,
            activeGroups,
            addedGroups,
            groups,
            needsRefresh,
            group;

        if (view.rendered) {
            addedGroups = {};
            activeGroups = {};

            for (; i < len; ++i) {
                group = records[i].get(groupField);
                if (addedGroups[group] === undefined) {
                    addedGroups[group] = 0;
                }
                addedGroups[group] += 1;
            }
            groups = store.getGroups();
            for (i = 0, len = groups.length; i < len; ++i) {
                group = groups[i];
                activeGroups[group.name] = group.children.length;
            }

            for (group in addedGroups) {
                if (addedGroups[group] === activeGroups[group]) {
                    needsRefresh = true;
                    break;
                }
            }
            
            if (needsRefresh) {
                view.refresh();
            }
        }
    },

    onUpdate: function(store, record, type, changedFields){
        var view = this.view;
        if (view.rendered && !changedFields || Ext.Array.contains(changedFields, this.getGroupField())) {
            view.refresh();
        }
    },

    onRemove: function(store, record) {
        var me = this,
            groupField = me.getGroupField(),
            removedGroup = record.get(groupField),
            view = me.view;

        if (view.rendered) {
            
            if (store.findExact(groupField, removedGroup) === -1) {
                me.view.refresh(); 
            }
        }
    },

    injectGroupingMenu: function() {
        var me       = this,
            headerCt = me.view.headerCt;

        headerCt.showMenuBy = me.showMenuBy;
        headerCt.getMenuItems = me.getMenuItems();
    },

    showMenuBy: function(t, header) {
        var menu = this.getMenu(),
            groupMenuItem  = menu.down('#groupMenuItem'),
            groupableMth = header.groupable === false ?  'disable' : 'enable';
            
        groupMenuItem[groupableMth]();
        Ext.grid.header.Container.prototype.showMenuBy.apply(this, arguments);
    },

    getMenuItems: function() {
        var me                 = this,
            groupByText        = me.groupByText,
            disabled           = me.disabled || !me.getGroupField(),
            showGroupsText     = me.showGroupsText,
            enableNoGroups     = me.enableNoGroups,
            getMenuItems       = me.view.headerCt.getMenuItems;

        
        return function() {

            
            
            var o = getMenuItems.call(this);
            o.push('-', {
                iconCls: Ext.baseCSSPrefix + 'group-by-icon',
                itemId: 'groupMenuItem',
                text: groupByText,
                handler: me.onGroupMenuItemClick,
                scope: me
            });
            if (enableNoGroups) {
                o.push({
                    itemId: 'groupToggleMenuItem',
                    text: showGroupsText,
                    checked: !disabled,
                    checkHandler: me.onGroupToggleMenuItemClick,
                    scope: me
                });
            }
            return o;
        };
    },

    
    onGroupMenuItemClick: function(menuItem, e) {
        var me = this,
            menu = menuItem.parentMenu,
            hdr  = menu.activeHeader,
            view = me.view,
            store = view.store;

        delete me.lastGroupIndex;
        me.block();
        me.enable();
        store.group(hdr.dataIndex);
        me.pruneGroupedHeader();
        me.unblock();
        me.refreshIf();
    },

    block: function(){
        this.blockRefresh = this.view.blockRefresh = true;
    },

    unblock: function(){
        this.blockRefresh = this.view.blockRefresh = false;
    },

    
    onGroupToggleMenuItemClick: function(menuItem, checked) {
        this[checked ? 'enable' : 'disable']();
    },

    
    pruneGroupedHeader: function() {
        var me = this,
            header = me.getGroupedHeader();

        if (me.hideGroupedHeader && header) {
            if (me.prunedHeader) {
                me.prunedHeader.show();
            }
            me.prunedHeader = header;
            header.hide();
        }
    },

    getGroupedHeader: function(){
        var groupField = this.getGroupField(),
            headerCt = this.view.headerCt;

        return groupField ? headerCt.down('[dataIndex=' + groupField + ']') : null;
    },

    getGroupField: function(){
        var group = this.view.store.groupers.first();
        if (group) {
            return group.property;
        }
        return ''; 
    },

    
    onRowFocus: function(rowIdx) {
        var node    = this.view.getNode(rowIdx),
            groupBd = Ext.fly(node).up('.' + this.collapsedCls);

        if (groupBd) {
            
            
            this.expand(groupBd);
        }
    },

    
    isExpanded: function(groupName) {
        return (this.collapsedState[groupName] === false);
    },

    
    expand: function(groupName, focus,  preventSizeCalculation) {
        var me = this,
            view = me.view,
            groupHeader,
            groupBody,
            lockingPartner = me.lockingPartner;

        
        if (Ext.isString(groupName)) {
            groupBody = Ext.fly(me.getGroupBodyId(groupName), '_grouping');
        }
        
        else {
            groupBody = Ext.fly(groupName, '_grouping')
            groupName = me.getGroupName(groupBody);
        }
        groupHeader = Ext.get(me.getGroupHeaderId(groupName));

        
        if (me.collapsedState[groupName]) {
            groupBody.removeCls(me.collapsedCls);
            groupBody.prev().removeCls(me.hdCollapsedCls);

            if (preventSizeCalculation !== true) {
                view.refreshSize();
            }
            view.fireEvent('groupexpand', view, groupHeader, groupName);
            me.collapsedState[groupName] = false;

            
            if (lockingPartner) {
                lockingPartner.expand(groupName, focus, preventSizeCalculation);
            }
            if (focus) {
                groupBody.scrollIntoView(view.el, null, true);
            }
        }
    },

    
    expandAll: function(){
        var me   = this,
            view = me.view,
            els  = view.el.select(me.eventSelector).elements,
            e,
            eLen = els.length;

        for (e = 0; e < eLen; e++) {
            me.expand(Ext.fly(els[e]).next(), false, true);
        }

        view.refreshSize();
    },

    
    collapse: function(groupName, focus,  preventSizeCalculation) {
        var me = this,
            view = me.view,
            groupHeader,
            groupBody,
            lockingPartner = me.lockingPartner;

        
        if (Ext.isString(groupName)) {
            groupBody = Ext.fly(me.getGroupBodyId(groupName), '_grouping');
        }
        
        else {
            groupBody = Ext.fly(groupName, '_grouping')
            groupName = me.getGroupName(groupBody);
        }
        groupHeader = Ext.get(me.getGroupHeaderId(groupName));
 
        
        if (!me.collapsedState[groupName]) {
            groupBody.addCls(me.collapsedCls);
            groupBody.prev().addCls(me.hdCollapsedCls);

            if (preventSizeCalculation !== true) {
                view.refreshSize();
            }
            view.fireEvent('groupcollapse', view, groupHeader, groupName);
            me.collapsedState[groupName] = true;

            
            if (lockingPartner) {
                lockingPartner.collapse(groupName, focus, preventSizeCalculation);
            }
            if (focus) {
                groupHeader.scrollIntoView(view.el, null, true);
            }
        }
    },

    
    collapseAll: function() {
        var me     = this,
            view   = me.view,
            els    = view.el.select(me.eventSelector).elements,
            e,
            eLen   = els.length;

        for (e = 0; e < eLen; e++) {
            me.collapse(Ext.fly(els[e]).next(), false, true);
        }

        view.refreshSize();
    },

    onGroupChange: function(){
        var me = this,
            field = me.getGroupField(),
            menuItem,
            visibleGridColumns,
            groupingByLastVisibleColumn;

        if (me.hideGroupedHeader) {
            if (me.lastGroupField) {
                menuItem = me.getMenuItem(me.lastGroupField);
                if (menuItem) {
                    menuItem.setChecked(true);
                }
            }
            if (field) {
                visibleGridColumns = me.view.headerCt.getVisibleGridColumns();

                
                
                groupingByLastVisibleColumn = ((visibleGridColumns.length === 1) && (visibleGridColumns[0].dataIndex == field));
                menuItem = me.getMenuItem(field);
                if (menuItem && !groupingByLastVisibleColumn) {
                    menuItem.setChecked(false);
                }
            }
        }
        me.refreshIf();
        me.lastGroupField = field;
    },

    
    getMenuItem: function(dataIndex){
        var view = this.view,
            header = view.headerCt.down('gridcolumn[dataIndex=' + dataIndex + ']'),
            menu = view.headerCt.getMenu();

        return header ? menu.down('menuitem[headerId='+ header.id +']') : null;
    },

    
    onGroupClick: function(view, rowElement, groupName, e) {
        var me = this;

        if (me.collapsible) {
            if (me.collapsedState[groupName]) {
                me.expand(groupName);
            } else {
                me.collapse(groupName);
            }
        }
    },

    
    getMetaRowTplFragments: function() {
        return {
            isRow: this.isRow,
            closeRow: this.closeRow
        };
    },

    
    
    isRow: function() {
        return '<tpl if="typeof rows === \'undefined\'">';
    },

    
    
    closeRow: function() {
        return '</tpl>';
    },

    
    mutateMetaRowTpl: function(metaRowTpl) {
        metaRowTpl.unshift('{[this.isRow()]}');
        metaRowTpl.push('{[this.closeRow()]}');
    },

    
    
    getAdditionalData: function(data, idx, record, orig) {
        var view = this.view,
            hCt  = view.headerCt,
            col  = hCt.items.getAt(0),
            o = {},
            tdAttrKey;

        
        
        
        if (col) {
            tdAttrKey = col.id + '-tdAttr';
            o[tdAttrKey] = this.indentByDepth(data) + " " + (orig[tdAttrKey] ? orig[tdAttrKey] : '');
            o.collapsed = 'true';
            o.data = record.getData();
        }
        return o;
    },

    
    getGroupRows: function(group, records, preppedRecords, fullWidth) {
        var me = this,
            children = group.children,
            rows = group.rows = [],
            view = me.view,
            header = me.getGroupedHeader(),
            groupField = me.getGroupField(),
            index = -1,
            r,
            rLen = records.length,
            record;
            
        
        if (view.store.buffered) {
            me.collapsible = false;
        }
            
        group.viewId = view.id;

        for (r = 0; r < rLen; r++) {
            record = records[r];

            if (record.get(groupField) == group.name) {
                index = r;
            }
            if (Ext.Array.indexOf(children, record) != -1) {
                rows.push(Ext.apply(preppedRecords[r], {
                    depth : 1
                }));
            }
        }

        group.groupField = groupField,
        group.groupHeaderId = me.getGroupHeaderId(group.name);
        group.groupBodyId = me.getGroupBodyId(group.name);
        group.fullWidth = fullWidth;
        group.columnName = header ? header.text : groupField;
        group.groupValue = group.name;

        
        
        if (header && index > -1) {
            group.name = group.renderedValue = preppedRecords[index][header.id];
        }
        if (me.collapsedState[group.name]) {
            group.collapsedCls = me.collapsedCls;
            group.hdCollapsedCls = me.hdCollapsedCls;
        } else {
            group.collapsedCls = group.hdCollapsedCls = '';
        }

        
        if (me.collapsible) {
            group.collapsibleClass = me.hdCollapsibleCls;
        } else {
            group.collapsibleClass = '';
        }

        return group;
    },

    
    getGroupHeaderId: function(groupName) {
        return this.view.id + '-hd-' + groupName;
    },

    
    getGroupBodyId: function(groupName) {
        return this.view.id + '-bd-' + groupName;
    },

    
    getGroupName: function(element) {
        var me = this,
            targetEl;
                
        
        targetEl = Ext.fly(element).findParent(me.eventSelector);
        if (targetEl) {
            return targetEl.id.split(this.view.id + '-hd-')[1];
        }

        
        targetEl = Ext.fly(element).findParent(me.bodySelector);
        if (targetEl) {
            return targetEl.id.split(this.view.id + '-bd-')[1];
        }
    },

    
    collectData: function(records, preppedRecords, startIndex, fullWidth, o) {
        var me    = this,
            store = me.view.store,
            collapsedState = me.collapsedState,
            collapseGroups,
            g,
            groups, gLen, group;

        if (me.startCollapsed) {
            
            
            
            me.startCollapsed = false;
            collapseGroups = true;
        }

        if (!me.disabled && store.isGrouped()) {
            o.rows = groups = store.getGroups();
            gLen   = groups.length;

            for (g = 0; g < gLen; g++) {
                group = groups[g];
                
                if (collapseGroups) {
                    collapsedState[group.name] = true;
                }

                me.getGroupRows(group, records, preppedRecords, fullWidth);
            }
        }
        return o;
    },

    
    
    
    
    getFireEventArgs: function(type, view, targetEl, e) {
        return [type, view, targetEl, this.getGroupName(targetEl), e];
    }
});


Ext.define('Ext.grid.feature.RowBody', {
    extend: 'Ext.grid.feature.Feature',
    alias: 'feature.rowbody',
    rowBodyHiddenCls: Ext.baseCSSPrefix + 'grid-row-body-hidden',
    rowBodyTrCls: Ext.baseCSSPrefix + 'grid-rowbody-tr',
    rowBodyTdCls: Ext.baseCSSPrefix + 'grid-cell-rowbody',
    rowBodyDivCls: Ext.baseCSSPrefix + 'grid-rowbody',

    eventPrefix: 'rowbody',
    eventSelector: '.' + Ext.baseCSSPrefix + 'grid-rowbody-tr',
    
    getRowBody: function(values) {
        return [
            '<tr class="' + this.rowBodyTrCls + ' {rowBodyCls}">',
                '<td class="' + this.rowBodyTdCls + '" colspan="{rowBodyColspan}">',
                    '<div class="' + this.rowBodyDivCls + '">{rowBody}</div>',
                '</td>',
            '</tr>'
        ].join('');
    },
    
    
    getMetaRowTplFragments: function() {
        return {
            getRowBody: this.getRowBody,
            rowBodyTrCls: this.rowBodyTrCls,
            rowBodyTdCls: this.rowBodyTdCls,
            rowBodyDivCls: this.rowBodyDivCls
        };
    },

    mutateMetaRowTpl: function(metaRowTpl) {
        metaRowTpl.push('{[this.getRowBody(values)]}');
    },

    
    getAdditionalData: function(data, idx, record, orig) {
        var headerCt = this.view.headerCt,
            colspan  = headerCt.getColumnCount();

        return {
            rowBody: "",
            rowBodyCls: this.rowBodyCls,
            rowBodyColspan: colspan
        };
    }
});

Ext.define('Ext.grid.feature.RowWrap', {
    extend: 'Ext.grid.feature.Feature',
    alias: 'feature.rowwrap',

    
    hasFeatureEvent: false,

    init: function() {
        if (!this.disabled) {
            this.enable();
        }
    },

    getRowSelector: function(){
        return 'tr:has(> ' + this.view.cellSelector + ')';
    },

    enable: function(){
        var me = this,
            view = me.view;

        me.callParent();
        
        me.savedRowSelector = view.rowSelector;
        view.rowSelector = me.getRowSelector();

        
        
        
        view.getComponentLayout().getColumnSelector = me.getColumnSelector;
    },

    disable: function(){
        var me = this,
            view = me.view,
            saved = me.savedRowSelector;

        me.callParent();
        if (saved) {
            view.rowSelector = saved;
        }
        delete me.savedRowSelector;
    },

    mutateMetaRowTpl: function(metaRowTpl) {  
        var prefix = Ext.baseCSSPrefix;      
        
        
        metaRowTpl[0] = metaRowTpl[0].replace(prefix + 'grid-row', '');
        metaRowTpl[0] = metaRowTpl[0].replace("{[this.embedRowCls()]}", "");
        
        metaRowTpl.unshift('<table class="' + prefix + 'grid-table ' + prefix + 'grid-table-resizer" style="width: {[this.embedFullWidth()]}px;">');
        
        metaRowTpl.unshift('<tr class="' + prefix + 'grid-row {[this.embedRowCls()]}"><td colspan="{[this.embedColSpan()]}"><div class="' + prefix + 'grid-rowwrap-div">');

        
        metaRowTpl.push('</table>');
        
        metaRowTpl.push('</div></td></tr>');
    },

    embedColSpan: function() {
        return '{colspan}';
    },

    embedFullWidth: function() {
        return '{fullWidth}';
    },

    getAdditionalData: function(data, idx, record, orig) {
        var headerCt = this.view.headerCt,
            colspan  = headerCt.getColumnCount(),
            fullWidth = headerCt.getFullWidth(),
            items    = headerCt.query('gridcolumn'),
            itemsLn  = items.length,
            i = 0,
            o = {
                colspan: colspan,
                fullWidth: fullWidth
            },
            id,
            tdClsKey,
            colResizerCls;

        for (; i < itemsLn; i++) {
            id = items[i].id;
            tdClsKey = id + '-tdCls';
            colResizerCls = Ext.baseCSSPrefix + 'grid-col-resizer-'+id;
            
            
            
            o[tdClsKey] = colResizerCls + " " + (orig[tdClsKey] ? orig[tdClsKey] : '');
            
            o[id+'-tdAttr'] = " style=\"width: " + (items[i].hidden ? 0 : items[i].getDesiredWidth()) + "px;\" ";
            if (orig[id+'-tdAttr']) {
                o[id+'-tdAttr'] += orig[id+'-tdAttr'];
            }
        }

        return o;
    },

    getMetaRowTplFragments: function() {
        return {
            embedFullWidth: this.embedFullWidth,
            embedColSpan: this.embedColSpan
        };
    },

    getColumnSelector: function(header) {
        var s = Ext.baseCSSPrefix + 'grid-col-resizer-' + header.id;
        return 'th.' + s + ',td.' + s;
    }
});

Ext.define('Ext.grid.plugin.DragDrop', {
    extend: 'Ext.AbstractPlugin',
    alias: 'plugin.gridviewdragdrop',

    uses: [
        'Ext.view.DragZone',
        'Ext.grid.ViewDropZone'
    ],

    

    
    
    
    dragText : '{0} selected row{1}',
    

    
    ddGroup : "GridDD",

    

    

    
    enableDrop: true,

    
    enableDrag: true,

    init : function(view) {
        view.on('render', this.onViewRender, this, {single: true});
    },

    
    destroy: function() {
        Ext.destroy(this.dragZone, this.dropZone);
    },

    enable: function() {
        var me = this;
        if (me.dragZone) {
            me.dragZone.unlock();
        }
        if (me.dropZone) {
            me.dropZone.unlock();
        }
        me.callParent();
    },

    disable: function() {
        var me = this;
        if (me.dragZone) {
            me.dragZone.lock();
        }
        if (me.dropZone) {
            me.dropZone.lock();
        }
        me.callParent();
    },

    onViewRender : function(view) {
        var me = this;

        if (me.enableDrag) {
            me.dragZone = new Ext.view.DragZone({
                view: view,
                ddGroup: me.dragGroup || me.ddGroup,
                dragText: me.dragText
            });
        }

        if (me.enableDrop) {
            me.dropZone = new Ext.grid.ViewDropZone({
                view: view,
                ddGroup: me.dropGroup || me.ddGroup
            });
        }
    }
});

Ext.define('Ext.grid.plugin.HeaderResizer', {
    extend: 'Ext.AbstractPlugin',
    requires: ['Ext.dd.DragTracker', 'Ext.util.Region'],
    alias: 'plugin.gridheaderresizer',

    disabled: false,

    config: {
        
        dynamic: false
    },

    colHeaderCls: Ext.baseCSSPrefix + 'column-header',

    minColWidth: 40,
    maxColWidth: 1000,
    wResizeCursor: 'col-resize',
    eResizeCursor: 'col-resize',
    
    
    
    

    init: function(headerCt) {
        this.headerCt = headerCt;
        headerCt.on('render', this.afterHeaderRender, this, {single: true});
    },

    
    destroy: function() {
        if (this.tracker) {
            this.tracker.destroy();
        }
    },

    afterHeaderRender: function() {
        var headerCt = this.headerCt,
            el = headerCt.el;

        headerCt.mon(el, 'mousemove', this.onHeaderCtMouseMove, this);

        this.tracker = new Ext.dd.DragTracker({
            disabled: this.disabled,
            onBeforeStart: Ext.Function.bind(this.onBeforeStart, this),
            onStart: Ext.Function.bind(this.onStart, this),
            onDrag: Ext.Function.bind(this.onDrag, this),
            onEnd: Ext.Function.bind(this.onEnd, this),
            tolerance: 3,
            autoStart: 300,
            el: el
        });
    },

    
    
    
    onHeaderCtMouseMove: function(e, t) {
        var me = this,
            prevSiblings,
            headerEl, overHeader, resizeHeader, resizeHeaderOwnerGrid, ownerGrid;

        if (me.headerCt.dragging) {
            if (me.activeHd) {
                me.activeHd.el.dom.style.cursor = '';
                delete me.activeHd;
            }
        } else {
            headerEl = e.getTarget('.' + me.colHeaderCls, 3, true);

            if (headerEl){
                overHeader = Ext.getCmp(headerEl.id);

                
                if (overHeader.isOnLeftEdge(e)) {
                    resizeHeader = overHeader.previousNode('gridcolumn:not([hidden]):not([isGroupHeader])')
                    
                    if (resizeHeader) {

                        ownerGrid = me.headerCt.up('tablepanel');
                        resizeHeaderOwnerGrid = resizeHeader.up('tablepanel');

                        
                        
                        
                        if (!((resizeHeaderOwnerGrid === ownerGrid) || ((ownerGrid.ownerCt.isXType('tablepanel')) && ownerGrid.ownerCt.view.lockedGrid === resizeHeaderOwnerGrid))) {
                            resizeHeader = null;
                        }
                    }
                }
                
                else if (overHeader.isOnRightEdge(e)) {
                    resizeHeader = overHeader;
                }
                
                else {
                    resizeHeader = null;
                }

                
                if (resizeHeader) {
                    
                    
                    
                    if (resizeHeader.isGroupHeader) {
                        prevSiblings = resizeHeader.getGridColumns();
                        resizeHeader = prevSiblings[prevSiblings.length - 1];
                    }

                    
                    
                    if (resizeHeader && !(resizeHeader.fixed || (resizeHeader.resizable === false) || me.disabled)) {
                        me.activeHd = resizeHeader;
                        overHeader.el.dom.style.cursor = me.eResizeCursor;
                    }
                
                } else {
                    overHeader.el.dom.style.cursor = '';
                    delete me.activeHd;
                }
            }
        }
    },

    
    onBeforeStart : function(e){
        var t = e.getTarget();
        
        this.dragHd = this.activeHd;

        if (!!this.dragHd && !Ext.fly(t).hasCls(Ext.baseCSSPrefix + 'column-header-trigger') && !this.headerCt.dragging) {
            
            this.tracker.constrainTo = this.getConstrainRegion();
            return true;
        } else {
            this.headerCt.dragging = false;
            return false;
        }
    },

    
    getConstrainRegion: function() {
        var me       = this,
            dragHdEl = me.dragHd.el,
            region   = Ext.util.Region.getRegion(dragHdEl),
            nextHd;

        
        
        if (me.headerCt.forceFit) {
            nextHd = me.dragHd.nextNode('gridcolumn:not([hidden]):not([isGroupHeader])');
        }

         return region.adjust(
            0,
            me.headerCt.forceFit ? (nextHd ? nextHd.getWidth() - me.minColWidth : 0) : me.maxColWidth - dragHdEl.getWidth(),
            0,
            me.minColWidth
        );
    },

    
    
    onStart: function(e){
        var me       = this,
            dragHd   = me.dragHd,
            dragHdEl = dragHd.el,
            width    = dragHdEl.getWidth(),
            headerCt = me.headerCt,
            t        = e.getTarget(),
            xy, gridSection, dragHct, firstSection, lhsMarker, rhsMarker, el, offsetLeft, offsetTop, topLeft, markerHeight, top;

        if (me.dragHd && !Ext.fly(t).hasCls(Ext.baseCSSPrefix + 'column-header-trigger')) {
            headerCt.dragging = true;
        }

        me.origWidth = width;

        
        if (!me.dynamic) {
            xy           = dragHdEl.getXY();
            gridSection  = headerCt.up('[scrollerOwner]');
            dragHct      = me.dragHd.up(':not([isGroupHeader])');
            firstSection = dragHct.up();
            lhsMarker    = gridSection.getLhsMarker();
            rhsMarker    = gridSection.getRhsMarker();
            el           = rhsMarker.parent();
            offsetLeft   = el.getLocalX();
            offsetTop    = el.getLocalY();
            topLeft      = el.translatePoints(xy);
            markerHeight = firstSection.body.getHeight() + headerCt.getHeight();
            top = topLeft.top - offsetTop;

            lhsMarker.setTop(top);
            rhsMarker.setTop(top);
            lhsMarker.setHeight(markerHeight);
            rhsMarker.setHeight(markerHeight);
            lhsMarker.setLeft(topLeft.left - offsetLeft);
            rhsMarker.setLeft(topLeft.left + width - offsetLeft);
        }
    },

    
    onDrag: function(e){
        if (!this.dynamic) {
            var xy          = this.tracker.getXY('point'),
                gridSection = this.headerCt.up('[scrollerOwner]'),
                rhsMarker   = gridSection.getRhsMarker(),
                el          = rhsMarker.parent(),
                topLeft     = el.translatePoints(xy),
                offsetLeft  = el.getLocalX();

            rhsMarker.setLeft(topLeft.left - offsetLeft);
        
        } else {
            this.doResize();
        }
    },

    onEnd: function(e){
        this.headerCt.dragging = false;
        if (this.dragHd) {
            if (!this.dynamic) {
                var dragHd      = this.dragHd,
                    gridSection = this.headerCt.up('[scrollerOwner]'),
                    lhsMarker   = gridSection.getLhsMarker(),
                    rhsMarker   = gridSection.getRhsMarker(),
                    offscreen   = -9999;

                
                lhsMarker.setLeft(offscreen);
                rhsMarker.setLeft(offscreen);
            }
            this.doResize();
        }
    },

    doResize: function() {
        if (this.dragHd) {
            var dragHd = this.dragHd,
                nextHd,
                offset = this.tracker.getOffset('point');

            
            if (dragHd.flex) {
                delete dragHd.flex;
            }

            Ext.suspendLayouts();

            
            dragHd.setWidth(this.origWidth + offset[0]);
 
            
            
            if (this.headerCt.forceFit) {
                nextHd = dragHd.nextNode('gridcolumn:not([hidden]):not([isGroupHeader])');
                if (nextHd) {
                    delete nextHd.flex;
                    nextHd.setWidth(nextHd.getWidth() - offset[0]);
                }
            }

            
            Ext.resumeLayouts(true);
        }
    },

    disable: function() {
        this.disabled = true;
        if (this.tracker) {
            this.tracker.disable();
        }
    },

    enable: function() {
        this.disabled = false;
        if (this.tracker) {
            this.tracker.enable();
        }
    }
});

Ext.define('Ext.layout.container.boxOverflow.None', {
    alternateClassName: 'Ext.layout.boxOverflow.None',
    
    constructor: function(layout, config) {
        this.layout = layout;
        Ext.apply(this, config);
    },

    handleOverflow: Ext.emptyFn,

    clearOverflow: Ext.emptyFn,

    beginLayout: Ext.emptyFn,
    beginLayoutCycle: Ext.emptyFn,
    finishedLayout: Ext.emptyFn,

    completeLayout: function (ownerContext) {
        var me = this,
            plan = ownerContext.state.boxPlan,
            overflow;

        if (plan && plan.tooNarrow) {
            overflow = me.handleOverflow(ownerContext);

            if (overflow) {
                if (overflow.reservedSpace) {
                    me.layout.publishInnerCtSize(ownerContext, overflow.reservedSpace);
                }

                
                
                
                
                
                
                
                
                
                
            }
        } else {
            me.clearOverflow();
        }
    },

    onRemove: Ext.emptyFn,

    
    getItem: function(item) {
        return this.layout.owner.getComponent(item);
    },
    
    getOwnerType: function(owner){
        var type;
        if (owner.isToolbar) {
            type = 'toolbar';
        } else if (owner.isTabBar) {
            type = 'tabbar';
        } else if (owner.isMenu) {
            type = 'menu';
        } else {
            type = owner.getXType();
        }
        
        return type;
    },

    getPrefixConfig: Ext.emptyFn,
    getSuffixConfig: Ext.emptyFn,
    getOverflowCls: function() {
        return '';
    }
});

Ext.define('Ext.panel.Proxy', {

    alternateClassName: 'Ext.dd.PanelProxy',
    
    
    moveOnDrag: true,

    
    constructor: function(panel, config){
        var me = this;
        
        
        me.panel = panel;
        me.id = me.panel.id +'-ddproxy';
        Ext.apply(me, config);
    },

    
    insertProxy: true,

    
    setStatus: Ext.emptyFn,
    reset: Ext.emptyFn,
    update: Ext.emptyFn,
    stop: Ext.emptyFn,
    sync: Ext.emptyFn,

    
    getEl: function(){
        return this.ghost.el;
    },

    
    getGhost: function(){
        return this.ghost;
    },

    
    getProxy: function(){
        return this.proxy;
    },

    
    hide : function(){
        var me = this;
        
        if (me.ghost) {
            if (me.proxy) {
                me.proxy.remove();
                delete me.proxy;
            }

            
            me.panel.unghost(null, me.moveOnDrag);
            delete me.ghost;
        }
    },

    
    show: function(){
        var me = this,
            panelSize;
            
        if (!me.ghost) {
            panelSize = me.panel.getSize();
            me.panel.el.setVisibilityMode(Ext.Element.DISPLAY);
            me.ghost = me.panel.ghost();
            if (me.insertProxy) {
                
                
                me.proxy = me.panel.el.insertSibling({cls: Ext.baseCSSPrefix + 'panel-dd-spacer'});
                me.proxy.setSize(panelSize);
            }
        }
    },

    
    repair: function(xy, callback, scope) {
        this.hide();
        Ext.callback(callback, scope || this);
    },

    
    moveProxy : function(parentNode, before){
        if (this.proxy) {
            parentNode.insertBefore(this.proxy.dom, before);
        }
    }
});


Ext.define('Ext.resizer.Resizer', {
    mixins: {
        observable: 'Ext.util.Observable'
    },
    uses: ['Ext.resizer.ResizeTracker', 'Ext.Component'],

    alternateClassName: 'Ext.Resizable',

    handleCls: Ext.baseCSSPrefix + 'resizable-handle',
    pinnedCls: Ext.baseCSSPrefix + 'resizable-pinned',
    overCls:   Ext.baseCSSPrefix + 'resizable-over',
    wrapCls:   Ext.baseCSSPrefix + 'resizable-wrap',

    
    dynamic: true,

    
    handles: 's e se',

    
    height : null,

    
    width : null,

    
    heightIncrement : 0,

    
    widthIncrement : 0,

    
    minHeight : 20,

    
    minWidth : 20,

    
    maxHeight : 10000,

    
    maxWidth : 10000,

    
    pinned: false,

    
    preserveRatio: false,

    
    transparent: false,

    

    possiblePositions: {
        n:  'north',
        s:  'south',
        e:  'east',
        w:  'west',
        se: 'southeast',
        sw: 'southwest',
        nw: 'northwest',
        ne: 'northeast'
    },

    

    

    constructor: function(config) {
        var me = this,
            target,
            targetEl,
            tag,
            handles = me.handles,
            handleCls,
            possibles,
            len,
            i = 0,
            pos, 
            handleEls = [],
            eastWestStyle, style,
            box;

        me.addEvents(
            
            'beforeresize',
            
            'resizedrag',
            
            'resize'
        );

        if (Ext.isString(config) || Ext.isElement(config) || config.dom) {
            target = config;
            config = arguments[1] || {};
            config.target = target;
        }
        
        me.mixins.observable.constructor.call(me, config);

        
        
        target = me.target;
        if (target) {
            if (target.isComponent) {
                me.el = target.getEl();
                if (target.minWidth) {
                    me.minWidth = target.minWidth;
                }
                if (target.minHeight) {
                    me.minHeight = target.minHeight;
                }
                if (target.maxWidth) {
                    me.maxWidth = target.maxWidth;
                }
                if (target.maxHeight) {
                    me.maxHeight = target.maxHeight;
                }
                if (target.floating) {
                    if (!me.hasOwnProperty('handles')) {
                        me.handles = 'n ne e se s sw w nw';
                    }
                }
            } else {
                me.el = me.target = Ext.get(target);
            }
        }
        
        else {
            me.target = me.el = Ext.get(me.el);
        }

        
        
        
        tag = me.el.dom.tagName.toUpperCase();
        if (tag == 'TEXTAREA' || tag == 'IMG' || tag == 'TABLE') {
            
            me.originalTarget = me.target;
            targetEl = me.el;
            box = targetEl.getBox();
            me.target = me.el = me.el.wrap({
                cls: me.wrapCls,
                id: me.el.id + '-rzwrap',
                style: targetEl.getStyles('margin-top', 'margin-bottom')
            });

            
            me.el.setPositioning(targetEl.getPositioning());
            targetEl.clearPositioning();
            me.el.setBox(box);

            
            targetEl.setStyle('position', 'absolute');
        }

        
        
        me.el.position();
        if (me.pinned) {
            me.el.addCls(me.pinnedCls);
        }

        
        me.resizeTracker = new Ext.resizer.ResizeTracker({
            disabled: me.disabled,
            target: me.target,
            constrainTo: me.constrainTo,
            overCls: me.overCls,
            throttle: me.throttle,
            originalTarget: me.originalTarget,
            delegate: '.' + me.handleCls,
            dynamic: me.dynamic,
            preserveRatio: me.preserveRatio,
            heightIncrement: me.heightIncrement,
            widthIncrement: me.widthIncrement,
            minHeight: me.minHeight,
            maxHeight: me.maxHeight,
            minWidth: me.minWidth,
            maxWidth: me.maxWidth
        });

        
        me.resizeTracker.on({
            mousedown: me.onBeforeResize,
            drag: me.onResize,
            dragend: me.onResizeEnd,
            scope: me
        });

        if (me.handles == 'all') {
            me.handles = 'n s e w ne nw se sw';
        }

        handles = me.handles = me.handles.split(/ |\s*?[,;]\s*?/);
        possibles = me.possiblePositions;
        len = handles.length;
        handleCls = me.handleCls + ' ' + (me.target.isComponent ? (me.target.baseCls + '-handle ') : '') + me.handleCls + '-';

        
        eastWestStyle = Ext.isIE6 ? ' style="height:' + me.el.getHeight() + 'px"' : '';

        for (; i < len; i++){
            
            if (handles[i] && possibles[handles[i]]) {
                pos = possibles[handles[i]];
                if (pos === 'east' || pos === 'west') {
                    style = eastWestStyle;
                } else {
                    style = '';
                }
                handleEls.push('<div id="' + me.el.id + '-' + pos + '-handle" class="' + handleCls + pos + ' ' + Ext.baseCSSPrefix + 'unselectable"' + style + '></div>');
            }
        }
        Ext.DomHelper.append(me.el, handleEls.join(''));

        
        for (i = 0; i < len; i++){
            
            if (handles[i] && possibles[handles[i]]) {
                pos = possibles[handles[i]];
                me[pos] = me.el.getById(me.el.id + '-' + pos + '-handle');
                me[pos].region = pos;
                me[pos].unselectable();
                if (me.transparent) {
                    me[pos].setOpacity(0);
                }
            }
        }

        
        if (Ext.isNumber(me.width)) {
            me.width = Ext.Number.constrain(me.width, me.minWidth, me.maxWidth);
        }
        if (Ext.isNumber(me.height)) {
            me.height = Ext.Number.constrain(me.height, me.minHeight, me.maxHeight);
        }

        
        if (me.width !== null || me.height !== null) {
            if (me.originalTarget) {
                me.originalTarget.setWidth(me.width);
                me.originalTarget.setHeight(me.height);
            }
            me.resizeTo(me.width, me.height);
        }

        me.forceHandlesHeight();
    },

    disable: function() {
        this.resizeTracker.disable();
    },

    enable: function() {
        this.resizeTracker.enable();
    },

    
    onBeforeResize: function(tracker, e) {
        var box = this.el.getBox();
        return this.fireEvent('beforeresize', this, box.width, box.height, e);
    },

    
    onResize: function(tracker, e) {
        var me = this,
            box = me.el.getBox();
            
        me.forceHandlesHeight();
        return me.fireEvent('resizedrag', me, box.width, box.height, e);
    },

    
    onResizeEnd: function(tracker, e) {
        var me = this,
            box = me.el.getBox();
            
        me.forceHandlesHeight();
        return me.fireEvent('resize', me, box.width, box.height, e);
    },

    
    resizeTo : function(width, height) {
        var me = this;
        me.target.setSize(width, height);
        me.fireEvent('resize', me, width, height, null);
    },

    
    getEl : function() {
        return this.el;
    },

    
    getTarget: function() {
        return this.target;
    },

    destroy: function() {
        var i = 0,
            handles = this.handles,
            len = handles.length,
            positions = this.possiblePositions;

        for (; i < len; i++) {
            this[positions[handles[i]]].remove();
        }
    },

    
    forceHandlesHeight : function() {
        var me = this,
            handle;
        if (Ext.isIE6) {
            handle = me.east;
            if (handle) {
                handle.setHeight(me.el.getHeight());
            }
            handle = me.west;
            if (handle) {
                handle.setHeight(me.el.getHeight());
            }
            me.el.repaint();
        }
    }
});


Ext.define('Ext.resizer.ResizeTracker', {
    extend: 'Ext.dd.DragTracker',
    dynamic: true,
    preserveRatio: false,

    
    constrainTo: null,
    
    proxyCls:  Ext.baseCSSPrefix + 'resizable-proxy',

    constructor: function(config) {
        var me = this,
            widthRatio, heightRatio,
            throttledResizeFn;

        if (!config.el) {
            if (config.target.isComponent) {
                me.el = config.target.getEl();
            } else {
                me.el = config.target;
            }
        }
        this.callParent(arguments);

        
        if (me.preserveRatio && me.minWidth && me.minHeight) {
            widthRatio = me.minWidth / me.el.getWidth();
            heightRatio = me.minHeight / me.el.getHeight();

            
            
            
            if (heightRatio > widthRatio) {
                me.minWidth = me.el.getWidth() * heightRatio;
            } else {
                me.minHeight = me.el.getHeight() * widthRatio;
            }
        }

        
        
        if (me.throttle) {
            throttledResizeFn = Ext.Function.createThrottled(function() {
                    Ext.resizer.ResizeTracker.prototype.resize.apply(me, arguments);
                }, me.throttle);

            me.resize = function(box, direction, atEnd) {
                if (atEnd) {
                    Ext.resizer.ResizeTracker.prototype.resize.apply(me, arguments);
                } else {
                    throttledResizeFn.apply(null, arguments);
                }
            };
        }
    },

    onBeforeStart: function(e) {
        
        this.startBox = this.el.getBox();
    },

    
    getDynamicTarget: function() {
        var me = this,
            target = me.target;
            
        if (me.dynamic) {
            return target;
        } else if (!me.proxy) {
            me.proxy = me.createProxy(target);
        }
        me.proxy.show();
        return me.proxy;
    },
    
    
    createProxy: function(target){
        var proxy,
            cls = this.proxyCls,
            renderTo;
            
        if (target.isComponent) {
            proxy = target.getProxy().addCls(cls);
        } else {
            renderTo = Ext.getBody();
            if (Ext.scopeResetCSS) {
                renderTo = Ext.getBody().createChild({
                    cls: Ext.resetCls
                });
            }
            proxy = target.createProxy({
                tag: 'div',
                cls: cls,
                id: target.id + '-rzproxy'
            }, renderTo);
        }
        proxy.removeCls(Ext.baseCSSPrefix + 'proxy-el');
        return proxy;
    },

    onStart: function(e) {
        
        this.activeResizeHandle = Ext.get(this.getDragTarget().id);

        
        if (!this.dynamic) {
            this.resize(this.startBox, {
                horizontal: 'none',
                vertical: 'none'
            });
        }
    },

    onDrag: function(e) {
        
        if (this.dynamic || this.proxy) {
            this.updateDimensions(e);
        }
    },

    updateDimensions: function(e, atEnd) {
        var me = this,
            region = me.activeResizeHandle.region,
            offset = me.getOffset(me.constrainTo ? 'dragTarget' : null),
            box = me.startBox,
            ratio,
            widthAdjust = 0,
            heightAdjust = 0,
            snappedWidth,
            snappedHeight,
            adjustX = 0,
            adjustY = 0,
            dragRatio,
            horizDir = offset[0] < 0 ? 'right' : 'left',
            vertDir = offset[1] < 0 ? 'down' : 'up',
            oppositeCorner,
            axis, 
            newBox,
            newHeight, newWidth;

        switch (region) {
            case 'south':
                heightAdjust = offset[1];
                axis = 2;
                break;
            case 'north':
                heightAdjust = -offset[1];
                adjustY = -heightAdjust;
                axis = 2;
                break;
            case 'east':
                widthAdjust = offset[0];
                axis = 1;
                break;
            case 'west':
                widthAdjust = -offset[0];
                adjustX = -widthAdjust;
                axis = 1;
                break;
            case 'northeast':
                heightAdjust = -offset[1];
                adjustY = -heightAdjust;
                widthAdjust = offset[0];
                oppositeCorner = [box.x, box.y + box.height];
                axis = 3;
                break;
            case 'southeast':
                heightAdjust = offset[1];
                widthAdjust = offset[0];
                oppositeCorner = [box.x, box.y];
                axis = 3;
                break;
            case 'southwest':
                widthAdjust = -offset[0];
                adjustX = -widthAdjust;
                heightAdjust = offset[1];
                oppositeCorner = [box.x + box.width, box.y];
                axis = 3;
                break;
            case 'northwest':
                heightAdjust = -offset[1];
                adjustY = -heightAdjust;
                widthAdjust = -offset[0];
                adjustX = -widthAdjust;
                oppositeCorner = [box.x + box.width, box.y + box.height];
                axis = 3;
                break;
        }

        newBox = {
            width: box.width + widthAdjust,
            height: box.height + heightAdjust,
            x: box.x + adjustX,
            y: box.y + adjustY
        };

        
        snappedWidth = Ext.Number.snap(newBox.width, me.widthIncrement);
        snappedHeight = Ext.Number.snap(newBox.height, me.heightIncrement);
        if (snappedWidth != newBox.width || snappedHeight != newBox.height){
            switch (region) {
                case 'northeast':
                    newBox.y -= snappedHeight - newBox.height;
                    break;
                case 'north':
                    newBox.y -= snappedHeight - newBox.height;
                    break;
                case 'southwest':
                    newBox.x -= snappedWidth - newBox.width;
                    break;
                case 'west':
                    newBox.x -= snappedWidth - newBox.width;
                    break;
                case 'northwest':
                    newBox.x -= snappedWidth - newBox.width;
                    newBox.y -= snappedHeight - newBox.height;
            }
            newBox.width = snappedWidth;
            newBox.height = snappedHeight;
        }

        
        if (newBox.width < me.minWidth || newBox.width > me.maxWidth) {
            newBox.width = Ext.Number.constrain(newBox.width, me.minWidth, me.maxWidth);

            
            if (adjustX) {
                newBox.x = box.x + (box.width - newBox.width);
            }
        } else {
            me.lastX = newBox.x;
        }
        if (newBox.height < me.minHeight || newBox.height > me.maxHeight) {
            newBox.height = Ext.Number.constrain(newBox.height, me.minHeight, me.maxHeight);

            
            if (adjustY) {
                newBox.y = box.y + (box.height - newBox.height);
            }
        } else {
            me.lastY = newBox.y;
        }

        
        if (me.preserveRatio || e.shiftKey) {
            ratio = me.startBox.width / me.startBox.height;

            
            newHeight = Math.min(Math.max(me.minHeight, newBox.width / ratio), me.maxHeight);
            newWidth = Math.min(Math.max(me.minWidth, newBox.height * ratio), me.maxWidth);

            
            if (axis == 1) {
                newBox.height = newHeight;
            }

            
            else if (axis == 2) {
                newBox.width = newWidth;
            }

            
            else {
                
                
                dragRatio = Math.abs(oppositeCorner[0] - this.lastXY[0]) / Math.abs(oppositeCorner[1] - this.lastXY[1]);

                
                if (dragRatio > ratio) {
                    newBox.height = newHeight;
                } else {
                    newBox.width = newWidth;
                }

                
                if (region == 'northeast') {
                    newBox.y = box.y - (newBox.height - box.height);
                } else if (region == 'northwest') {
                    newBox.y = box.y - (newBox.height - box.height);
                    newBox.x = box.x - (newBox.width - box.width);
                } else if (region == 'southwest') {
                    newBox.x = box.x - (newBox.width - box.width);
                }
            }
        }

        if (heightAdjust === 0) {
            vertDir = 'none';
        }
        if (widthAdjust === 0) {
            horizDir = 'none';
        }
        me.resize(newBox, {
            horizontal: horizDir,
            vertical: vertDir
        }, atEnd);
    },

    getResizeTarget: function(atEnd) {
        return atEnd ? this.target : this.getDynamicTarget();
    },

    resize: function(box, direction, atEnd) {
        var target = this.getResizeTarget(atEnd);
        if (target.isComponent) {
            target.setSize(box.width, box.height);
            if (target.floating) {
                target.setPagePosition(box.x, box.y);
            }
        } else {
            target.setBox(box);
        }

        
        target = this.originalTarget;
        if (target && (this.dynamic || atEnd)) {
            if (target.isComponent) {
                target.setSize(box.width, box.height);
                if (target.floating) {
                    target.setPagePosition(box.x, box.y);
                }
            } else {
                target.setBox(box);
            }
        }
    },

    onEnd: function(e) {
        this.updateDimensions(e, true);
        if (this.proxy) {
            this.proxy.hide();
        }
    }
});


Ext.define('Ext.resizer.SplitterTracker', {
    extend: 'Ext.dd.DragTracker',
    requires: ['Ext.util.Region'],
    enabled: true,
    
    overlayCls: Ext.baseCSSPrefix + 'resizable-overlay',

    createDragOverlay: function () {
        var overlay;

        overlay = this.overlay =  Ext.getBody().createChild({
            cls: this.overlayCls, 
            html: '&#160;'
        });

        overlay.unselectable();
        overlay.setSize(Ext.Element.getViewWidth(true), Ext.Element.getViewHeight(true));
        overlay.show();
    },

    getPrevCmp: function() {
        var splitter = this.getSplitter();
        return splitter.previousSibling();
    },

    getNextCmp: function() {
        var splitter = this.getSplitter();
        return splitter.nextSibling();
    },

    
    
    onBeforeStart: function(e) {
        var me = this,
            prevCmp = me.getPrevCmp(),
            nextCmp = me.getNextCmp(),
            collapseEl = me.getSplitter().collapseEl,
            target = e.getTarget(),
            box;

        if (collapseEl && target === me.getSplitter().collapseEl.dom) {
            return false;
        }

        
        if (nextCmp.collapsed || prevCmp.collapsed) {
            return false;
        }

        
        me.prevBox  = prevCmp.getEl().getBox();
        me.nextBox  = nextCmp.getEl().getBox();
        me.constrainTo = box = me.calculateConstrainRegion();

        if (!box) {
            return false;
        }

        me.createDragOverlay();

        return box;
    },

    
    onStart: function(e) {
        var splitter = this.getSplitter();
        splitter.addCls(splitter.baseCls + '-active');
    },

    
    calculateConstrainRegion: function() {
        var me         = this,
            splitter   = me.getSplitter(),
            splitWidth = splitter.getWidth(),
            defaultMin = splitter.defaultSplitMin,
            orient     = splitter.orientation,
            prevBox    = me.prevBox,
            prevCmp    = me.getPrevCmp(),
            nextBox    = me.nextBox,
            nextCmp    = me.getNextCmp(),
            
            
            
            prevConstrainRegion, nextConstrainRegion;

        
        if (orient === 'vertical') {

            
            
            prevConstrainRegion = new Ext.util.Region(
                prevBox.y,
                
                
                (prevCmp.maxWidth ? prevBox.x + prevCmp.maxWidth : nextBox.right - (nextCmp.minWidth || defaultMin)) + splitWidth,
                prevBox.bottom,
                prevBox.x + (prevCmp.minWidth || defaultMin)
            );
            
            nextConstrainRegion = new Ext.util.Region(
                nextBox.y,
                nextBox.right - (nextCmp.minWidth || defaultMin),
                nextBox.bottom,
                
                
                (nextCmp.maxWidth ? nextBox.right - nextCmp.maxWidth : prevBox.x + (prevBox.minWidth || defaultMin)) - splitWidth
            );
        } else {
            
            prevConstrainRegion = new Ext.util.Region(
                prevBox.y + (prevCmp.minHeight || defaultMin),
                prevBox.right,
                
                
                (prevCmp.maxHeight ? prevBox.y + prevCmp.maxHeight : nextBox.bottom - (nextCmp.minHeight || defaultMin)) + splitWidth,
                prevBox.x
            );
            
            nextConstrainRegion = new Ext.util.Region(
                
                
                (nextCmp.maxHeight ? nextBox.bottom - nextCmp.maxHeight : prevBox.y + (prevCmp.minHeight || defaultMin)) - splitWidth,
                nextBox.right,
                nextBox.bottom - (nextCmp.minHeight || defaultMin),
                nextBox.x
            );
        }

        
        return prevConstrainRegion.intersect(nextConstrainRegion);
    },

    
    performResize: function(e, offset) {
        var me        = this,
            splitter  = me.getSplitter(),
            orient    = splitter.orientation,
            prevCmp   = me.getPrevCmp(),
            nextCmp   = me.getNextCmp(),
            owner     = splitter.ownerCt,
            flexedSiblings = owner.query('>[flex]'),
            len       = flexedSiblings.length,
            i         = 0,
            dimension,
            size,
            totalFlex = 0;

        
        for (; i < len; i++) {
            size = flexedSiblings[i].getWidth();
            totalFlex += size;
            flexedSiblings[i].flex = size;
        }

        offset = offset || me.getOffset('dragTarget');

        if (orient === 'vertical') {
            offset = offset[0];
            dimension = 'width';
        } else {
            dimension = 'height';
            offset = offset[1];
        }
        if (prevCmp) {
            size = me.prevBox[dimension] + offset;
            if (prevCmp.flex) {
                prevCmp.flex = size;
            } else {
                prevCmp[dimension] = size;
            }
        }
        if (nextCmp) {
            size = me.nextBox[dimension] - offset;
            if (nextCmp.flex) {
                nextCmp.flex = size;
            } else {
                nextCmp[dimension] = size;
            }
        }

        owner.updateLayout();
    },

    
    
    
    endDrag: function () {
        var me = this;

        if (me.overlay) {
             me.overlay.remove();
             delete me.overlay;
        }

        me.callParent(arguments); 
    },

    
    onEnd: function(e) {
        var me = this,
            splitter = me.getSplitter();
            
        splitter.removeCls(splitter.baseCls + '-active');
        me.performResize(e, me.getOffset('dragTarget'));
    },

    
    
    onDrag: function(e) {
        var me        = this,
            offset    = me.getOffset('dragTarget'),
            splitter  = me.getSplitter(),
            splitEl   = splitter.getEl(),
            orient    = splitter.orientation;

        if (orient === "vertical") {
            splitEl.setX(me.startRegion.left + offset[0]);
        } else {
            splitEl.setY(me.startRegion.top + offset[1]);
        }
    },

    getSplitter: function() {
        return this.splitter;
    }
});

Ext.define('Ext.slider.Thumb', {
    requires: ['Ext.dd.DragTracker', 'Ext.util.Format'],
    
    topZIndex: 10000,

    

    
    constructor: function(config) {
        var me = this;

        
        Ext.apply(me, config || {}, {
            cls: Ext.baseCSSPrefix + 'slider-thumb',

            
            constrain: false
        });
        me.callParent([config]);
    },

    
    render: function() {
        var me = this;
        me.el = me.slider.innerEl.insertFirst(me.getElConfig());
        me.onRender();
    },
    
    onRender: function() {
        if (this.disabled) {
            this.disable();
        }
        this.initEvents();
    },

    getElConfig: function() {
        var me = this,
            slider = me.slider,
            style = {};

        style[slider.vertical ? 'bottom' : 'left'] = slider.calculateThumbPosition(slider.normalizeValue(me.value)) + '%';
        return {
            style: style,
            id  : this.id,
            cls : this.cls
        };
    },

    
    move: function(v, animate) {
        var el = this.el,
            styleProp = this.slider.vertical ? 'bottom' : 'left',
            to,
            from;

        v += '%';
        
        if (!animate) {
            el.dom.style[styleProp] = v;
        } else {
            to = {};
            to[styleProp] = v;
            
            if (!Ext.supports.GetPositionPercentage) {
                from = {};
                from[styleProp] = el.dom.style[styleProp];
            }
            
            new Ext.fx.Anim({
                target: el,
                duration: 350,
                from: from,
                to: to
            });
        }
    },

    
    bringToFront: function() {
        this.el.setStyle('zIndex', this.topZIndex);
    },

    
    sendToBack: function() {
        this.el.setStyle('zIndex', '');
    },

    
    enable: function() {
        var me = this;

        me.disabled = false;
        if (me.el) {
            me.el.removeCls(me.slider.disabledCls);
        }
    },

    
    disable: function() {
        var me = this;

        me.disabled = true;
        if (me.el) {
            me.el.addCls(me.slider.disabledCls);
        }
    },

    
    initEvents: function() {
        var me = this,
            el = me.el;

        me.tracker = new Ext.dd.DragTracker({
            onBeforeStart: Ext.Function.bind(me.onBeforeDragStart, me),
            onStart      : Ext.Function.bind(me.onDragStart, me),
            onDrag       : Ext.Function.bind(me.onDrag, me),
            onEnd        : Ext.Function.bind(me.onDragEnd, me),
            tolerance    : 3,
            autoStart    : 300,
            overCls      : Ext.baseCSSPrefix + 'slider-thumb-over'
        });

        me.tracker.initEl(el);
    },

    
    onBeforeDragStart : function(e) {
        if (this.disabled) {
            return false;
        } else {
            this.slider.promoteThumb(this);
            return true;
        }
    },

    
    onDragStart: function(e){
        var me = this;

        me.el.addCls(Ext.baseCSSPrefix + 'slider-thumb-drag');
        me.dragging = me.slider.dragging = true;
        me.dragStartValue = me.value;

        me.slider.fireEvent('dragstart', me.slider, e, me);
    },

    
    onDrag: function(e) {
        var me       = this,
            slider   = me.slider,
            index    = me.index,
            newValue = me.getValueFromTracker(),
            above,
            below;

        
        if (newValue !== undefined) {
            if (me.constrain) {
                above = slider.thumbs[index + 1];
                below = slider.thumbs[index - 1];

                if (below !== undefined && newValue <= below.value) {
                    newValue = below.value;
                }

                if (above !== undefined && newValue >= above.value) {
                    newValue = above.value;
                }
            }
            slider.setValue(index, newValue, false);
            slider.fireEvent('drag', slider, e, me);
        }
    },

    getValueFromTracker: function() {
        var slider = this.slider,
            trackPoint = slider.getTrackpoint(this.tracker.getXY());

        
        if (trackPoint !== undefined) {
            return slider.reversePixelValue(trackPoint);
        }
    },

    
    onDragEnd: function(e) {
        var me     = this,
            slider = me.slider,
            value  = me.value;

        me.el.removeCls(Ext.baseCSSPrefix + 'slider-thumb-drag');

        me.dragging = slider.dragging = false;
        slider.fireEvent('dragend', slider, e);

        if (me.dragStartValue != value) {
            slider.fireEvent('changecomplete', slider, value, me);
        }
    },

    destroy: function() {
        Ext.destroy(this.tracker);
    }
});


Ext.define('Ext.tree.plugin.TreeViewDragDrop', {
    extend: 'Ext.AbstractPlugin',
    alias: 'plugin.treeviewdragdrop',

    uses: [
        'Ext.tree.ViewDragZone',
        'Ext.tree.ViewDropZone'
    ],

    

    

    
    
    dragText : '{0} selected node{1}',
    

    
    allowParentInserts: false,

    
    allowContainerDrops: false,

    
    appendOnly: false,

    
    ddGroup : "TreeDD",

    

    

    
    expandDelay : 1000,

    
    enableDrop: true,

    
    enableDrag: true,

    
    nodeHighlightColor: 'c3daf9',

    
    nodeHighlightOnDrop: Ext.enableFx,

    
    nodeHighlightOnRepair: Ext.enableFx,

    init : function(view) {
        view.on('render', this.onViewRender, this, {single: true});
    },

    
    destroy: function() {
        Ext.destroy(this.dragZone, this.dropZone);
    },

    onViewRender : function(view) {
        var me = this;

        if (me.enableDrag) {
            me.dragZone = new Ext.tree.ViewDragZone({
                view: view,
                ddGroup: me.dragGroup || me.ddGroup,
                dragText: me.dragText,
                repairHighlightColor: me.nodeHighlightColor,
                repairHighlight: me.nodeHighlightOnRepair
            });
        }

        if (me.enableDrop) {
            me.dropZone = new Ext.tree.ViewDropZone({
                view: view,
                ddGroup: me.dropGroup || me.ddGroup,
                allowContainerDrops: me.allowContainerDrops,
                appendOnly: me.appendOnly,
                allowParentInserts: me.allowParentInserts,
                expandDelay: me.expandDelay,
                dropHighlightColor: me.nodeHighlightColor,
                dropHighlight: me.nodeHighlightOnDrop
            });
        }
    }
});


Ext.define('Ext.util.Animate', {

    uses: ['Ext.fx.Manager', 'Ext.fx.Anim'],

    
    animate: function(animObj) {
        var me = this;
        if (Ext.fx.Manager.hasFxBlock(me.id)) {
            return me;
        }
        Ext.fx.Manager.queueFx(new Ext.fx.Anim(me.anim(animObj)));
        return this;
    },

    
    anim: function(config) {
        if (!Ext.isObject(config)) {
            return (config) ? {} : false;
        }

        var me = this;

        if (config.stopAnimation) {
            me.stopAnimation();
        }

        Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));

        return Ext.apply({
            target: me,
            paused: true
        }, config);
    },

    
    stopFx: Ext.Function.alias(Ext.util.Animate, 'stopAnimation'),

    
    stopAnimation: function() {
        Ext.fx.Manager.stopAnimation(this.id);
        return this;
    },

    
    syncFx: function() {
        Ext.fx.Manager.setFxDefaults(this.id, {
            concurrent: true
        });
        return this;
    },

    
    sequenceFx: function() {
        Ext.fx.Manager.setFxDefaults(this.id, {
            concurrent: false
        });
        return this;
    },

    
    hasActiveFx: Ext.Function.alias(Ext.util.Animate, 'getActiveAnimation'),

    
    getActiveAnimation: function() {
        return Ext.fx.Manager.getActiveAnimation(this.id);
    }
}, function(){
    
    Ext.applyIf(Ext.Element.prototype, this.prototype);
    
    Ext.CompositeElementLite.importElementMethods();
});

Ext.define('Ext.util.ClickRepeater', {
    extend: 'Ext.util.Observable',

    
    constructor : function(el, config){
        var me = this;

        me.el = Ext.get(el);
        me.el.unselectable();

        Ext.apply(me, config);

        me.callParent();

        me.addEvents(
        
        "mousedown",
        
        "click",
        
        "mouseup"
        );

        if(!me.disabled){
            me.disabled = true;
            me.enable();
        }

        
        if(me.handler){
            me.on("click", me.handler,  me.scope || me);
        }
    },

    

    

    

    
    interval : 20,

    
    delay: 250,

    
    preventDefault : true,

    
    stopDefault : false,

    timer : 0,

    
    enable: function(){
        if(this.disabled){
            this.el.on('mousedown', this.handleMouseDown, this);
            
            
            if (Ext.isIE && !(Ext.isStrict && Ext.isIE9)){
                this.el.on('dblclick', this.handleDblClick, this);
            }
            if(this.preventDefault || this.stopDefault){
                this.el.on('click', this.eventOptions, this);
            }
        }
        this.disabled = false;
    },

    
    disable: function( force){
        if(force || !this.disabled){
            clearTimeout(this.timer);
            if(this.pressedCls){
                this.el.removeCls(this.pressedCls);
            }
            Ext.getDoc().un('mouseup', this.handleMouseUp, this);
            this.el.removeAllListeners();
        }
        this.disabled = true;
    },

    
    setDisabled: function(disabled){
        this[disabled ? 'disable' : 'enable']();
    },

    eventOptions: function(e){
        if(this.preventDefault){
            e.preventDefault();
        }
        if(this.stopDefault){
            e.stopEvent();
        }
    },

    
    destroy : function() {
        this.disable(true);
        Ext.destroy(this.el);
        this.clearListeners();
    },

    handleDblClick : function(e){
        clearTimeout(this.timer);
        this.el.blur();

        this.fireEvent("mousedown", this, e);
        this.fireEvent("click", this, e);
    },

    
    handleMouseDown : function(e){
        clearTimeout(this.timer);
        this.el.blur();
        if(this.pressedCls){
            this.el.addCls(this.pressedCls);
        }
        this.mousedownTime = new Date();

        Ext.getDoc().on("mouseup", this.handleMouseUp, this);
        this.el.on("mouseout", this.handleMouseOut, this);

        this.fireEvent("mousedown", this, e);
        this.fireEvent("click", this, e);

        
        if (this.accelerate) {
            this.delay = 400;
        }

        
        
        e = new Ext.EventObjectImpl(e);

        this.timer =  Ext.defer(this.click, this.delay || this.interval, this, [e]);
    },

    
    click : function(e){
        this.fireEvent("click", this, e);
        this.timer =  Ext.defer(this.click, this.accelerate ?
            this.easeOutExpo(Ext.Date.getElapsed(this.mousedownTime),
                400,
                -390,
                12000) :
            this.interval, this, [e]);
    },

    easeOutExpo : function (t, b, c, d) {
        return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
    },

    
    handleMouseOut : function(){
        clearTimeout(this.timer);
        if(this.pressedCls){
            this.el.removeCls(this.pressedCls);
        }
        this.el.on("mouseover", this.handleMouseReturn, this);
    },

    
    handleMouseReturn : function(){
        this.el.un("mouseover", this.handleMouseReturn, this);
        if(this.pressedCls){
            this.el.addCls(this.pressedCls);
        }
        this.click();
    },

    
    handleMouseUp : function(e){
        clearTimeout(this.timer);
        this.el.un("mouseover", this.handleMouseReturn, this);
        this.el.un("mouseout", this.handleMouseOut, this);
        Ext.getDoc().un("mouseup", this.handleMouseUp, this);
        if(this.pressedCls){
            this.el.removeCls(this.pressedCls);
        }
        this.fireEvent("mouseup", this, e);
    }
});


Ext.define('Ext.util.ComponentDragger', {
    extend: 'Ext.dd.DragTracker',

    

    

    

    autoStart: 500,

    
    constructor: function(comp, config) {
        this.comp = comp;
        this.initialConstrainTo = config.constrainTo;
        this.callParent([ config ]);
    },

    onStart: function(e) {
        var me = this,
            comp = me.comp;

        
        this.startPosition = comp.el.getXY();

        
        
        if (comp.ghost && !comp.liveDrag) {
             me.proxy = comp.ghost();
             me.dragTarget = me.proxy.header.el;
        }

        
        if (me.constrain || me.constrainDelegate) {
            me.constrainTo = me.calculateConstrainRegion();
        }

        if (comp.beginDrag) {
            comp.beginDrag();
        }
    },

    calculateConstrainRegion: function() {
        var me = this,
            comp = me.comp,
            c = me.initialConstrainTo,
            delegateRegion,
            elRegion,
            dragEl = me.proxy ? me.proxy.el : comp.el,
            shadowSize = (!me.constrainDelegate && dragEl.shadow && !dragEl.shadowDisabled) ? dragEl.shadow.getShadowSize() : 0;

        
        if (!(c instanceof Ext.util.Region)) {
            c =  Ext.fly(c).getViewRegion();
        }

        
        if (shadowSize) {
            c.adjust(shadowSize[0], -shadowSize[1], -shadowSize[2], shadowSize[3]);
        }

        
        
        
        if (!me.constrainDelegate) {
            delegateRegion = Ext.fly(me.dragTarget).getRegion();
            elRegion = dragEl.getRegion();

            c.adjust(
                delegateRegion.top - elRegion.top,
                delegateRegion.right - elRegion.right,
                delegateRegion.bottom - elRegion.bottom,
                delegateRegion.left - elRegion.left
            );
        }
        return c;
    },

    
    onDrag: function(e) {
        var me = this,
            comp = (me.proxy && !me.comp.liveDrag) ? me.proxy : me.comp,
            offset = me.getOffset(me.constrain || me.constrainDelegate ? 'dragTarget' : null);

        comp.setPagePosition(me.startPosition[0] + offset[0], me.startPosition[1] + offset[1]);
    },

    onEnd: function(e) {
        var comp = this.comp;
        if (this.proxy && !comp.liveDrag) {
            comp.unghost();
        }
        if (comp.endDrag) {
            comp.endDrag();
        }
    }
});

Ext.define('Ext.util.Cookies', {
    singleton: true,
    
    
    set : function(name, value){
        var argv = arguments,
            argc = arguments.length,
            expires = (argc > 2) ? argv[2] : null,
            path = (argc > 3) ? argv[3] : '/',
            domain = (argc > 4) ? argv[4] : null,
            secure = (argc > 5) ? argv[5] : false;
            
        document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");
    },

    
    get : function(name){
        var arg = name + "=",
            alen = arg.length,
            clen = document.cookie.length,
            i = 0,
            j = 0;
            
        while(i < clen){
            j = i + alen;
            if(document.cookie.substring(i, j) == arg){
                return this.getCookieVal(j);
            }
            i = document.cookie.indexOf(" ", i) + 1;
            if(i === 0){
                break;
            }
        }
        return null;
    },

    
    clear : function(name, path){
        if(this.get(name)){
            path = path || '/';
            document.cookie = name + '=' + '; expires=Thu, 01-Jan-70 00:00:01 GMT; path=' + path;
        }
    },
    
    
    getCookieVal : function(offset){
        var endstr = document.cookie.indexOf(";", offset);
        if(endstr == -1){
            endstr = document.cookie.length;
        }
        return unescape(document.cookie.substring(offset, endstr));
    }
});


Ext.define('Ext.util.CSS', (function() {
    var rules = null,
        doc = document,
        camelRe = /(-[a-z])/gi,
        camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };

    return {

        singleton: true,

        constructor: function() {
            this.rules = {};
            this.initialized = false;
        },

        
        createStyleSheet : function(cssText, id) {
            var ss,
                head = doc.getElementsByTagName("head")[0],
                styleEl = doc.createElement("style");

            styleEl.setAttribute("type", "text/css");
            if (id) {
               styleEl.setAttribute("id", id);
            }

            if (Ext.isIE) {
               head.appendChild(styleEl);
               ss = styleEl.styleSheet;
               ss.cssText = cssText;
            } else {
                try{
                    styleEl.appendChild(doc.createTextNode(cssText));
                } catch(e) {
                   styleEl.cssText = cssText;
                }
                head.appendChild(styleEl);
                ss = styleEl.styleSheet ? styleEl.styleSheet : (styleEl.sheet || doc.styleSheets[doc.styleSheets.length-1]);
            }
            this.cacheStyleSheet(ss);
            return ss;
        },

        
        removeStyleSheet : function(id) {
            var existing = document.getElementById(id);
            if (existing) {
                existing.parentNode.removeChild(existing);
            }
        },

        
        swapStyleSheet : function(id, url) {
            var doc = document,
                ss;
            this.removeStyleSheet(id);
            ss = doc.createElement("link");
            ss.setAttribute("rel", "stylesheet");
            ss.setAttribute("type", "text/css");
            ss.setAttribute("id", id);
            ss.setAttribute("href", url);
            doc.getElementsByTagName("head")[0].appendChild(ss);
        },

        
        refreshCache : function() {
            return this.getRules(true);
        },

        
        cacheStyleSheet : function(ss) {
            if(!rules){
                rules = {};
            }
            try {
                var ssRules = ss.cssRules || ss.rules,
                    selectorText,
                    i = ssRules.length - 1,
                    j,
                    selectors;

                for (; i >= 0; --i) {
                    selectorText = ssRules[i].selectorText;
                    if (selectorText) {

                        
                        selectorText = selectorText.split(',');
                        selectors = selectorText.length;
                        for (j = 0; j < selectors; j++) {
                            rules[Ext.String.trim(selectorText[j]).toLowerCase()] = ssRules[i];
                        }
                    }
                }
            } catch(e) {}
        },

        
        getRules : function(refreshCache) {
            if (rules === null || refreshCache) {
                rules = {};
                var ds = doc.styleSheets,
                    i = 0,
                    len = ds.length;

                for (; i < len; i++) {
                    try {
                        if (!ds[i].disabled) {
                            this.cacheStyleSheet(ds[i]);
                        }
                    } catch(e) {}
                }
            }
            return rules;
        },

        
        getRule: function(selector, refreshCache) {
            var rs = this.getRules(refreshCache),
                i;
            if (!Ext.isArray(selector)) {
                return rs[selector.toLowerCase()];
            }
            for (i = 0; i < selector.length; i++) {
                if (rs[selector[i]]) {
                    return rs[selector[i].toLowerCase()];
                }
            }
            return null;
        },

        
        updateRule : function(selector, property, value){
            var rule, i;
            if (!Ext.isArray(selector)) {
                rule = this.getRule(selector);
                if (rule) {
                    rule.style[property.replace(camelRe, camelFn)] = value;
                    return true;
                }
            } else {
                for (i = 0; i < selector.length; i++) {
                    if (this.updateRule(selector[i], property, value)) {
                        return true;
                    }
                }
            }
            return false;
        }
    };
}()));

Ext.define('Ext.util.Floating', {

    uses: ['Ext.Layer', 'Ext.window.Window'],

    
    focusOnToFront: true,

    
    shadow: 'sides',

    

    constructor: function (dom) {
        var me = this;

        me.el = new Ext.Layer(Ext.apply({
            hideMode     : me.hideMode,
            hidden       : me.hidden,
            shadow       : (typeof me.shadow != 'undefined') ? me.shadow : 'sides',
            shadowOffset : me.shadowOffset,
            constrain    : false,
            shim         : (me.shim === false) ? false : undefined
        }, me.floating), dom);

        
        me.floating = true;
        
        
        
        
        me.registerWithOwnerCt();
    },

    registerWithOwnerCt: function() {
        var me = this;

        if (me.zIndexParent) {
            me.zIndexParent.unregisterFloatingItem(me);
        }

        
        me.zIndexParent = me.up('[floating]');
        me.setFloatParent(me.ownerCt);
        delete me.ownerCt;

        if (me.zIndexParent) {
            me.zIndexParent.registerFloatingItem(me);
        } else {
            Ext.WindowManager.register(me);
        }
    },

    setFloatParent: function(floatParent) {
        var me = this;

        
        if (me.floatParent) {
            me.mun(me.floatParent, {
                hide: me.onFloatParentHide,
                show: me.onFloatParentShow,
                scope: me
            });
        }

        me.floatParent = floatParent;

        
        if (floatParent) {
            me.mon(me.floatParent, {
                hide: me.onFloatParentHide,
                show: me.onFloatParentShow,
                scope: me
            });
        }

        
        
        if ((me.constrain || me.constrainHeader) && !me.constrainTo) {
            me.constrainTo = floatParent ? floatParent.getTargetEl() : me.container;
        }
    },
    
    onAfterFloatLayout: function(){
        this.syncShadow();   
    },

    onFloatParentHide: function() {
        var me = this;

        if (me.hideOnParentHide !== false && me.isVisible()) {
            me.hide();
            me.showOnParentShow = true;
        }
    },

    onFloatParentShow: function() {
        if (this.showOnParentShow) {
            delete this.showOnParentShow;
            this.show();
        }
    },

    
    
    
    
    
    setZIndex: function(index) {
        var me = this;

        me.el.setZIndex(index);

        
        index += 10;

        
        
        if (me.floatingDescendants) {
            index = Math.floor(me.floatingDescendants.setBase(index) / 100) * 100 + 10000;
        }
        return index;
    },

    
    doConstrain: function(constrainTo) {
        var me = this,

            
            
            
            vector = me.getConstrainVector(constrainTo),
            xy;

        if (vector) {
            xy = me.getPosition(!!me.floatParent);
            xy[0] += vector[0];
            xy[1] += vector[1];
            me.setPosition(xy);
        }
    },


    
    getConstrainVector: function(constrainTo){
        var me = this;

        if (me.constrain || me.constrainHeader) {
            constrainTo = constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container || me.el.getScopeParent();
            return (me.constrainHeader ? me.header.el : me.el).getConstrainVector(constrainTo);
        }
    },

    
    alignTo: function(element, position, offsets) {

        
        
        this.setPagePosition(this.el.getAlignToXY(element.el || element, position, offsets));
        return this;
    },

    
    toFront: function(preventFocus) {
        var me = this;

        
        
        if (me.zIndexParent && me.bringParentToFront !== false) {
            me.zIndexParent.toFront(true);
        }
        
        if (!Ext.isDefined(preventFocus)) {
            preventFocus = !me.focusOnToFront;
        }
        
        if (preventFocus) {
            me.preventFocusOnActivate = true;
        }
        if (me.zIndexManager.bringToFront(me)) {    
            if (!preventFocus) {
                
                
                
                me.focus(false, true);
            }
        }
        delete me.preventFocusOnActivate;
        return me;
    },

    
    setActive: function(active, newActive) {
        var me = this;
        
        if (active) {
            if (me.el.shadow && !me.maximized) {
                me.el.enableShadow(true);
            }
            if (me.modal && !me.preventFocusOnActivate) {
                me.focus(false, true);
            }
            me.fireEvent('activate', me);
        } else {
            
            
            if (me.isWindow && (newActive && newActive.isWindow)) {
                me.el.disableShadow();
            }
            me.fireEvent('deactivate', me);
        }
    },

    
    toBack: function() {
        this.zIndexManager.sendToBack(this);
        return this;
    },

    
    center: function() {
        var me = this,
            xy;
            
        if (me.isVisible()) {
            xy = me.el.getAlignToXY(me.container, 'c-c');
            me.setPagePosition(xy);
        } else {
            me.needsCenter = true;
        }
        return me;
    },
    
    onFloatShow: function() {
        if (this.needsCenter) {
            this.center();    
        }
        delete this.needsCenter;
    },

    
    syncShadow : function() {
        if (this.floating) {
            this.el.sync(true);
        }
    },

    
    fitContainer: function() {
        var me = this,
            parent = me.floatParent,
            container = parent ? parent.getTargetEl() : me.container;

        me.setSize(container.getViewSize(false));
        me.setPosition.apply(me, parent ? [0, 0] : container.getXY());
    }
});


Ext.define('Ext.util.History', {
    singleton: true,
    alternateClassName: 'Ext.History',
    mixins: {
        observable: 'Ext.util.Observable'
    },

    
    useTopWindow: true,

    
    fieldId: Ext.baseCSSPrefix + 'history-field',
    
    iframeId: Ext.baseCSSPrefix + 'history-frame',

    constructor: function() {
        var me = this;
        me.oldIEMode = Ext.isIE6 || Ext.isIE7 || !Ext.isStrict && Ext.isIE8;
        me.iframe = null;
        me.hiddenField = null;
        me.ready = false;
        me.currentToken = null;
        me.mixins.observable.constructor.call(me);
    },

    getHash: function() {
        var href = window.location.href,
            i = href.indexOf("#");

        return i >= 0 ? href.substr(i + 1) : null;
    },

    setHash: function (hash) {
        var me = this,
            win = me.useTopWindow ? window.top : window;
        try {
            win.location.hash = hash;
        } catch (e) {
            
        }
    },

    doSave: function() {
        this.hiddenField.value = this.currentToken;
    },


    handleStateChange: function(token) {
        this.currentToken = token;
        this.fireEvent('change', token);
    },

    updateIFrame: function(token) {
        var html = '<html><body><div id="state">' +
                    Ext.util.Format.htmlEncode(token) +
                    '</div></body></html>',
            doc;

        try {
            doc = this.iframe.contentWindow.document;
            doc.open();
            doc.write(html);
            doc.close();
            return true;
        } catch (e) {
            return false;
        }
    },

    checkIFrame: function () {
        var me = this,
            contentWindow = me.iframe.contentWindow,
            doc, elem, oldToken, oldHash;

        if (!contentWindow || !contentWindow.document) {
            Ext.Function.defer(this.checkIFrame, 10, this);
            return;
        }

        doc = contentWindow.document;
        elem = doc.getElementById("state");
        oldToken = elem ? elem.innerText : null;
        oldHash = me.getHash();

        Ext.TaskManager.start({
            run: function () {
                var doc = contentWindow.document,
                    elem = doc.getElementById("state"),
                    newToken = elem ? elem.innerText : null,
                    newHash = me.getHash();

                if (newToken !== oldToken) {
                    oldToken = newToken;
                    me.handleStateChange(newToken);
                    me.setHash(newToken);
                    oldHash = newToken;
                    me.doSave();
                } else if (newHash !== oldHash) {
                    oldHash = newHash;
                    me.updateIFrame(newHash);
                }
            },
            interval: 50,
            scope: me
        });
        me.ready = true;
        me.fireEvent('ready', me);
    },

    startUp: function () {
        var me = this,
            hash;

        me.currentToken = me.hiddenField.value || this.getHash();

        if (me.oldIEMode) {
            me.checkIFrame();
        } else {
            hash = me.getHash();
            Ext.TaskManager.start({
                run: function () {
                    var newHash = me.getHash();
                    if (newHash !== hash) {
                        hash = newHash;
                        me.handleStateChange(hash);
                        me.doSave();
                    }
                },
                interval: 50,
                scope: me
            });
            me.ready = true;
            me.fireEvent('ready', me);
        }

    },

    
    init: function (onReady, scope) {
        var me = this,
            DomHelper = Ext.DomHelper;

        if (me.ready) {
            Ext.callback(onReady, scope, [me]);
            return;
        }

        if (!Ext.isReady) {
            Ext.onReady(function() {
                me.init(onReady, scope);
            });
            return;
        }

        
        me.hiddenField = Ext.getDom(me.fieldId);
        if (!me.hiddenField) {
            me.hiddenField = Ext.getBody().createChild({
                id: Ext.id(),
                tag: 'form',
                cls: Ext.baseCSSPrefix + 'hide-display',
                children: [{
                    tag: 'input',
                    type: 'hidden',
                    id: me.fieldId
                }]
            }, false, true).firstChild;
        }

        if (me.oldIEMode) {
            me.iframe = Ext.getDom(me.iframeId);
            if (!me.iframe) {
                me.iframe = DomHelper.append(me.hiddenField.parentNode, {
                    tag: 'iframe',
                    id: me.iframeId,
                    src: Ext.SSL_SECURE_URL
                });
            }
        }

        me.addEvents(
            
            'ready',
            
            'change'
        );

        if (onReady) {
            me.on('ready', onReady, scope, {single: true});
        }
        me.startUp();
    },

    
    add: function (token, preventDup) {
        var me = this;

        if (preventDup !== false) {
            if (me.getToken() === token) {
                return true;
            }
        }

        if (me.oldIEMode) {
            return me.updateIFrame(token);
        } else {
            me.setHash(token);
            return true;
        }
    },

    
    back: function() {
        window.history.go(-1);
    },

    
    forward: function(){
        window.history.go(1);
    },

    
    getToken: function() {
        return this.ready ? this.currentToken : this.getHash();
    }
});

Ext.define('Ext.util.KeyMap', {
    alternateClassName: 'Ext.KeyMap',

    

    

    

    

    
    eventName: 'keydown',

    constructor: function(config) {
        var me = this;

        
        
        if ((arguments.length !== 1) || (typeof config === 'string') || config.dom || config.tagName || config === document || config.isComponent) {
            me.legacyConstructor.apply(me, arguments);
            return;
        }

        Ext.apply(me, config);
        me.bindings = [];

        if (!me.target.isComponent) {
            me.target = Ext.get(me.target);
        }

        if (me.binding) {
            me.addBinding(me.binding);
        } else if (config.key) {
            me.addBinding(config);
        }
        me.enable();
    },

    
    legacyConstructor: function(el, binding, eventName){
        var me = this;

        Ext.apply(me, {
            target: Ext.get(el),
            eventName: eventName || me.eventName,
            bindings: []
        });
        if (binding) {
            me.addBinding(binding);
        }
        me.enable();
    },

    
    addBinding : function(binding){
        var keyCode = binding.key,
            processed = false,
            key,
            keys,
            keyString,
            i,
            len;

        if (Ext.isArray(binding)) {
            for (i = 0, len = binding.length; i < len; i++) {
                this.addBinding(binding[i]);
            }
            return;
        }

        if (Ext.isString(keyCode)) {
            keys = [];
            keyString = keyCode.toUpperCase();

            for (i = 0, len = keyString.length; i < len; ++i){
                keys.push(keyString.charCodeAt(i));
            }
            keyCode = keys;
            processed = true;
        }

        if (!Ext.isArray(keyCode)) {
            keyCode = [keyCode];
        }

        if (!processed) {
            for (i = 0, len = keyCode.length; i < len; ++i) {
                key = keyCode[i];
                if (Ext.isString(key)) {
                    keyCode[i] = key.toUpperCase().charCodeAt(0);
                }
            }
        }

        this.bindings.push(Ext.apply({
            keyCode: keyCode
        }, binding));
    },

    
    handleTargetEvent: (function() {
        var tagRe = /input|textarea/i;

        return function(event) {
            var me = this,
                bindings, i, len,
                target, contentEditable;

            if (this.enabled) { 
                bindings = this.bindings;
                i = 0;
                len = bindings.length;

                
                event = me.processEvent.apply(me||me.processEventScope, arguments);

                
                if (me.ignoreInputFields) {
                    target = event.target;
                    contentEditable = target.contentEditable;
                    
                    
                    
                    if (tagRe.test(target.tagName) || (contentEditable === '' || contentEditable === 'true')) {
                        return;
                    }
                }

                
                
                if (!event.getKey) {
                    return event;
                }
                for(; i < len; ++i){
                    this.processBinding(bindings[i], event);
                }
            }
        }
    }()),

    
    processEvent: function(event){
        return event;
    },

    
    processBinding: function(binding, event){
        if (this.checkModifiers(binding, event)) {
            var key = event.getKey(),
                handler = binding.fn || binding.handler,
                scope = binding.scope || this,
                keyCode = binding.keyCode,
                defaultEventAction = binding.defaultEventAction,
                i,
                len,
                keydownEvent = new Ext.EventObjectImpl(event);


            for (i = 0, len = keyCode.length; i < len; ++i) {
                if (key === keyCode[i]) {
                    if (handler.call(scope, key, event) !== true && defaultEventAction) {
                        keydownEvent[defaultEventAction]();
                    }
                    break;
                }
            }
        }
    },

    
    checkModifiers: function(binding, e) {
        var keys = ['shift', 'ctrl', 'alt'],
            i = 0,
            len = keys.length,
            val, key;

        for (; i < len; ++i){
            key = keys[i];
            val = binding[key];
            if (!(val === undefined || (val === e[key + 'Key']))) {
                return false;
            }
        }
        return true;
    },

    
    on: function(key, fn, scope) {
        var keyCode, shift, ctrl, alt;
        if (Ext.isObject(key) && !Ext.isArray(key)) {
            keyCode = key.key;
            shift = key.shift;
            ctrl = key.ctrl;
            alt = key.alt;
        } else {
            keyCode = key;
        }
        this.addBinding({
            key: keyCode,
            shift: shift,
            ctrl: ctrl,
            alt: alt,
            fn: fn,
            scope: scope
        });
    },

    
    isEnabled : function() {
        return this.enabled;
    },

    
    enable: function() {
        var me = this;
        
        if (!me.enabled) {
            me.target.on(me.eventName, me.handleTargetEvent, me);
            me.enabled = true;
        }
    },

    
    disable: function() {
        var me = this;
        
        if (me.enabled) {
            me.target.removeListener(me.eventName, me.handleTargetEvent, me);
            me.enabled = false;
        }
    },

    
    setDisabled : function(disabled) {
        if (disabled) {
            this.disable();
        } else {
            this.enable();
        }
    },

    
    destroy: function(removeTarget) {
        var me = this,
            target = me.target;

        me.bindings = [];
        me.disable();
        if (removeTarget === true) {
            if (target.isComponent) {
                target.destroy();
            } else {
                target.remove();
            }
        }
        delete me.target;
    }
});

Ext.define('Ext.util.KeyNav', {
    alternateClassName: 'Ext.KeyNav',
    
    requires: ['Ext.util.KeyMap'],
    
    statics: {
        keyOptions: {
            left: 37,
            right: 39,
            up: 38,
            down: 40,
            space: 32,
            pageUp: 33,
            pageDown: 34,
            del: 46,
            backspace: 8,
            home: 36,
            end: 35,
            enter: 13,
            esc: 27,
            tab: 9
        }
    },

    constructor: function(config) {
        var me = this;
        if (arguments.length === 2) {
            me.legacyConstructor.apply(me, arguments);
            return;
        }
        me.setConfig(config);
    },

    
    legacyConstructor: function(el, config) {
        this.setConfig(Ext.apply({
            target: el
        }, config));
    },

    
    setConfig: function(config) {
        var me = this,
            keymapCfg = {
                target: config.target,
                ignoreInputFields: config.ignoreInputFields,
                eventName: me.getKeyEvent('forceKeyDown' in config ? config.forceKeyDown : me.forceKeyDown, config.eventName)
            },
            map, keyCodes, defaultScope, keyName, binding;

        if (me.map) {
            me.map.destroy();
        }

        if (config.processEvent) {
            keymapCfg.processEvent = config.processEvent;
            keymapCfg.processEventScope = config.processEventScope||me;
        }
        map = me.map = new Ext.util.KeyMap(keymapCfg);
        keyCodes = Ext.util.KeyNav.keyOptions;
        defaultScope = config.scope || me;
        
        for (keyName in keyCodes) {
            if (keyCodes.hasOwnProperty(keyName)) {

                
                
                if (binding = config[keyName]) {
                    if (typeof binding === 'function') {
                        binding = {
                            handler: binding,
                            defaultAction: (config.defaultEventAction !== undefined) ? config.defaultEventAction : me.defaultEventAction
                        };
                    }
                    map.addBinding({
                        key: keyCodes[keyName],
                        handler: Ext.Function.bind(me.handleEvent, binding.scope||defaultScope, binding.handler||binding.fn, true),
                        defaultEventAction: (binding.defaultEventAction !== undefined) ? binding.defaultAction : me.defaultEventAction
                    });
                }
            }
        }
        
        map.disable();
        if (!config.disabled) {
            map.enable();
        }
    },
    
    
    handleEvent: function(keyCode, event, handler){
        return handler.call(this, event);
    },
    
    
    disabled: false,
    
    
    defaultEventAction: "stopEvent",
    
    
    forceKeyDown: false,

    

    
    eventName: 'keypress',

    

    

    

    
    destroy: function(removeEl) {
        this.map.destroy(removeEl);
        delete this.map;
    },

    
    enable: function() {
        this.map.enable();
        this.disabled = false;
    },

    
    disable: function() {
        this.map.disable();
        this.disabled = true;
    },
    
    
    setDisabled : function(disabled) {
        this.map.setDisabled(disabled);
        this.disabled = disabled;
    },
    
    
    getKeyEvent: function(forceKeyDown, configuredEventName) {
        if (forceKeyDown || (Ext.EventManager.useKeyDown && !configuredEventName)) {
            return 'keydown';
        } else {
            return configuredEventName||this.eventName;
        }
    }
});

Ext.define('Ext.util.TextMetrics', {
    statics: {
        shared: null,
        
        measure: function(el, text, fixedWidth){
            var me = this,
                shared = me.shared;
            
            if(!shared){
                shared = me.shared = new me(el, fixedWidth);
            }
            shared.bind(el);
            shared.setFixedWidth(fixedWidth || 'auto');
            return shared.getSize(text);
        },
        
        
        destroy: function(){
            var me = this;
            Ext.destroy(me.shared);
            me.shared = null;
        }
    },
    
    
    constructor: function(bindTo, fixedWidth){
        var measure = this.measure = Ext.getBody().createChild({
            cls: Ext.baseCSSPrefix + 'textmetrics'
        });
        this.el = Ext.get(bindTo);
        
        measure.position('absolute');
        measure.setLeftTop(-1000, -1000);
        measure.hide();

        if (fixedWidth) {
           measure.setWidth(fixedWidth);
        }
    },
    
    
    getSize: function(text){
        var measure = this.measure,
            size;
        
        measure.update(text);
        size = measure.getSize();
        measure.update('');
        return size;
    },
    
    
    bind: function(el){
        var me = this;
        
        me.el = Ext.get(el);
        me.measure.setStyle(
            me.el.getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
        );
    },
    
    
     setFixedWidth : function(width){
         this.measure.setWidth(width);
     },
     
     
     getWidth : function(text){
         this.measure.dom.style.width = 'auto';
         return this.getSize(text).width;
     },
     
     
     getHeight : function(text){
         return this.getSize(text).height;
     },
     
     
     destroy: function(){
         var me = this;
         me.measure.remove();
         delete me.el;
         delete me.measure;
     }
}, function(){
    Ext.Element.addMethods({
        
        getTextWidth : function(text, min, max){
            return Ext.Number.constrain(Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width, min || 0, max || 1000000);
        }
    });
});


Ext.define('Ext.ElementLoader', {

    

    mixins: {
        observable: 'Ext.util.Observable'
    },

    uses: [
        'Ext.data.Connection',
        'Ext.Ajax'
    ],

    statics: {
        Renderer: {
            Html: function(loader, response, active){
                loader.getTarget().update(response.responseText, active.scripts === true);
                return true;
            }
        }
    },

    

    
    url: null,

    
    params: null,

    
    baseParams: null,

    
    autoLoad: false,

    
    target: null,

    
    loadMask: false,

    
    ajaxOptions: null,

    
    scripts: false,

    

    

    

    

    

    
    isLoader: true,

    constructor: function(config) {
        var me = this,
            autoLoad;

        config = config || {};
        Ext.apply(me, config);
        me.setTarget(me.target);
        me.addEvents(
            
            'beforeload',

            
            'exception',

            
            'load'
        );

        
        me.mixins.observable.constructor.call(me);

        if (me.autoLoad) {
            autoLoad = me.autoLoad;
            if (autoLoad === true) {
                autoLoad = {};
            }
            me.load(autoLoad);
        }
    },

    
    setTarget: function(target){
        var me = this;
        target = Ext.get(target);
        if (me.target && me.target != target) {
            me.abort();
        }
        me.target = target;
    },

    
    getTarget: function(){
        return this.target || null;
    },

    
    abort: function(){
        var active = this.active;
        if (active !== undefined) {
            Ext.Ajax.abort(active.request);
            if (active.mask) {
                this.removeMask();
            }
            delete this.active;
        }
    },

    
    removeMask: function(){
        this.target.unmask();
    },

    
    addMask: function(mask){
        this.target.mask(mask === true ? null : mask);
    },

    
    load: function(options) {

        options = Ext.apply({}, options);

        var me = this,
            target = me.target,
            mask = Ext.isDefined(options.loadMask) ? options.loadMask : me.loadMask,
            params = Ext.apply({}, options.params),
            ajaxOptions = Ext.apply({}, options.ajaxOptions),
            callback = options.callback || me.callback,
            scope = options.scope || me.scope || me,
            request;

        Ext.applyIf(ajaxOptions, me.ajaxOptions);
        Ext.applyIf(options, ajaxOptions);

        Ext.applyIf(params, me.params);
        Ext.apply(params, me.baseParams);

        Ext.applyIf(options, {
            url: me.url
        });


        Ext.apply(options, {
            scope: me,
            params: params,
            callback: me.onComplete
        });

        if (me.fireEvent('beforeload', me, options) === false) {
            return;
        }

        if (mask) {
            me.addMask(mask);
        }

        request = Ext.Ajax.request(options);
        me.active = {
            request: request,
            options: options,
            mask: mask,
            scope: scope,
            callback: callback,
            success: options.success || me.success,
            failure: options.failure || me.failure,
            renderer: options.renderer || me.renderer,
            scripts: Ext.isDefined(options.scripts) ? options.scripts : me.scripts
        };
        me.setOptions(me.active, options);
    },

    
    setOptions: Ext.emptyFn,

    
    onComplete: function(options, success, response) {
        var me = this,
            active = me.active,
            scope = active.scope,
            renderer = me.getRenderer(active.renderer);


        if (success) {
            success = renderer.call(me, me, response, active) !== false;
        }

        if (success) {
            Ext.callback(active.success, scope, [me, response, options]);
            me.fireEvent('load', me, response, options);
        } else {
            Ext.callback(active.failure, scope, [me, response, options]);
            me.fireEvent('exception', me, response, options);
        }
        Ext.callback(active.callback, scope, [me, success, response, options]);

        if (active.mask) {
            me.removeMask();
        }

        delete me.active;
    },

    
    getRenderer: function(renderer){
        if (Ext.isFunction(renderer)) {
            return renderer;
        }
        return this.statics().Renderer.Html;
    },

    
    startAutoRefresh: function(interval, options){
        var me = this;
        me.stopAutoRefresh();
        me.autoRefresh = setInterval(function(){
            me.load(options);
        }, interval);
    },

    
    stopAutoRefresh: function(){
        clearInterval(this.autoRefresh);
        delete this.autoRefresh;
    },

    
    isAutoRefreshing: function(){
        return Ext.isDefined(this.autoRefresh);
    },

    
    destroy: function(){
        var me = this;
        me.stopAutoRefresh();
        delete me.target;
        me.abort();
        me.clearListeners();
    }
});


Ext.define('Ext.ComponentLoader', {

    

    extend: 'Ext.ElementLoader',

    statics: {
        Renderer: {
            Data: function(loader, response, active){
                var success = true;
                try {
                    loader.getTarget().update(Ext.decode(response.responseText));
                } catch (e) {
                    success = false;
                }
                return success;
            },

            Component: function(loader, response, active){
                var success = true,
                    target = loader.getTarget(),
                    items = [];


                try {
                    items = Ext.decode(response.responseText);
                } catch (e) {
                    success = false;
                }

                if (success) {
                    target.suspendLayouts();
                    if (active.removeAll) {
                        target.removeAll();
                    }
                    target.add(items);
                    target.resumeLayouts(true);
                }
                return success;
            }
        }
    },

    

    
    target: null,

    
    loadMask: false,

    

    
    renderer: 'html',

    
    setTarget: function(target){
        var me = this;

        if (Ext.isString(target)) {
            target = Ext.getCmp(target);
        }

        if (me.target && me.target != target) {
            me.abort();
        }
        me.target = target;
    },

    
    removeMask: function(){
        this.target.setLoading(false);
    },

    
    addMask: function(mask){
        this.target.setLoading(mask);
    },


    setOptions: function(active, options){
        active.removeAll = Ext.isDefined(options.removeAll) ? options.removeAll : this.removeAll;
    },

    
    getRenderer: function(renderer){
        if (Ext.isFunction(renderer)) {
            return renderer;
        }

        var renderers = this.statics().Renderer;
        switch (renderer) {
            case 'component':
                return renderers.Component;
            case 'data':
                return renderers.Data;
            default:
                return Ext.ElementLoader.Renderer.Html;
        }
    }
});


Ext.define('Ext.XTemplateCompiler', {
    extend: 'Ext.XTemplateParser',

    
    
    
    useEval: Ext.isGecko,

    
    
    
    useIndex: Ext.isIE6 || Ext.isIE7,

    useFormat: true,
    
    propNameRe: /^[\w\d\$]*$/,

    compile: function (tpl) {
        var me = this,
            code = me.generate(tpl);

        
        
        
        
        return me.useEval ? me.evalTpl(code) : (new Function('Ext', code))(Ext);
    },

    generate: function (tpl) {
        var me = this,
            
            definitions = 'var fm=Ext.util.Format,ts=Object.prototype.toString;',
            code;

        
        me.maxLevel = 0;

        me.body = [
            'var c0=values, a0=' + me.createArrayTest(0) + ', p0=parent, n0=xcount, i0=xindex, v;\n'
        ];
        if (me.definitions) {
            if (typeof me.definitions === 'string') {
                me.definitions = [me.definitions, definitions ];
            } else {
                me.definitions.push(definitions);
            }
        } else {
            me.definitions = [ definitions ];
        }
        me.switches = [];

        me.parse(tpl);

        me.definitions.push(
            (me.useEval ? '$=' : 'return') + ' function (' + me.fnArgs + ') {',
                me.body.join(''),
            '}'
        );

        code = me.definitions.join('\n');

        
        me.definitions.length = me.body.length = me.switches.length = 0;
        delete me.definitions;
        delete me.body;
        delete me.switches;

        return code;
    },

    
    

    doText: function (text) {
        var me = this,
            out = me.body;

        text = text.replace(me.aposRe, "\\'").replace(me.newLineRe, '\\n');
        if (me.useIndex) {
            out.push('out[out.length]=\'', text, '\'\n');
        } else {
            out.push('out.push(\'', text, '\')\n');
        }
    },

    doExpr: function (expr) {
        var out = this.body;
        out.push('if ((v=' + expr + ')!==undefined) out');

        
        
        if (this.useIndex) {
             out.push('[out.length]=v+\'\'\n');
        } else {
             out.push('.push(v+\'\')\n');
        }
    },

    doTag: function (tag) {
        this.doExpr(this.parseTag(tag));
    },

    doElse: function () {
        this.body.push('} else {\n');
    },

    doEval: function (text) {
        this.body.push(text, '\n');
    },

    doIf: function (action, actions) {
        var me = this;

        
        if (action === '.') {
            me.body.push('if (values) {\n');
        } else if (me.propNameRe.test(action)) {
            me.body.push('if (', me.parseTag(action), ') {\n');
        }
        
        else {
            me.body.push('if (', me.addFn(action), me.callFn, ') {\n');
        }
        if (actions.exec) {
            me.doExec(actions.exec);
        }
    },

    doElseIf: function (action, actions) {
        var me = this;

        
        if (action === '.') {
            me.body.push('else if (values) {\n');
        } else if (me.propNameRe.test(action)) {
            me.body.push('} else if (', me.parseTag(action), ') {\n');
        }
        
        else {
            me.body.push('} else if (', me.addFn(action), me.callFn, ') {\n');
        }
        if (actions.exec) {
            me.doExec(actions.exec);
        }
    },

    doSwitch: function (action) {
        var me = this;

        
        if (action === '.') {
            me.body.push('switch (values) {\n');
        } else if (me.propNameRe.test(action)) {
            me.body.push('switch (', me.parseTag(action), ') {\n');
        }
        
        else {
            me.body.push('switch (', me.addFn(action), me.callFn, ') {\n');
        }
        me.switches.push(0);
    },

    doCase: function (action) {
        var me = this,
            cases = Ext.isArray(action) ? action : [action],
            n = me.switches.length - 1,
            match, i;

        if (me.switches[n]) {
            me.body.push('break;\n');
        } else {
            me.switches[n]++;
        }

        for (i = 0, n = cases.length; i < n; ++i) {
            match = me.intRe.exec(cases[i]);
            cases[i] = match ? match[1] : ("'" + cases[i].replace(me.aposRe,"\\'") + "'");
        }

        me.body.push('case ', cases.join(': case '), ':\n');
    },

    doDefault: function () {
        var me = this,
            n = me.switches.length - 1;

        if (me.switches[n]) {
            me.body.push('break;\n');
        } else {
            me.switches[n]++;
        }

        me.body.push('default:\n');
    },

    doEnd: function (type, actions) {
        var me = this,
            L = me.level-1;

        if (type == 'for') {
            
            if (actions.exec) {
                me.doExec(actions.exec);
            }

            me.body.push('}\n');
            me.body.push('parent=p',L,';values=r',L+1,';xcount=n',L,';xindex=i',L,'\n');
        } else if (type == 'if' || type == 'switch') {
            me.body.push('}\n');
        }
    },

    doFor: function (action, actions) {
        var me = this,
            s,
            L = me.level,
            up = L-1,
            pL = 'p' + L,
            parentAssignment;

        
        if (action === '.') {
            s = 'values';
        } else if (me.propNameRe.test(action)) {
            s = me.parseTag(action);
        }
        
        else {
            s = me.addFn(action) + me.callFn;
        }

        

        
        if (me.maxLevel < L) {
            me.maxLevel = L;
            me.body.push('var ');
        }
        
        if (action == '.') {
            parentAssignment = 'c' + L;
        } else {
            parentAssignment = 'a' + up + '?c' + up + '[i' + up + ']:p' + L;
        }
        
        me.body.push('i',L,'=0,n', L, '=0,c',L,'=',s,',a',L,'=', me.createArrayTest(L), ',p',L,'=c',up,',r',L,'=values;\n',
            'parent=',parentAssignment,'\n',
            'if (c',L,'){if(a',L,'){n', L,'=c', L, '.length;}else if (c', L, '.isMixedCollection){c',L,'=c',L,'.items;n',L,'=c',L,'.length;}else if(c',L,'.isStore){c',L,'=c',L,'.data.items;n',L,'=c',L,'.length;}else{c',L,'=[c',L,'];n',L,'=1;}}\n',
            'for (xcount=n',L,';i',L,'<n'+L+';++i',L,'){\n',
            'values=c',L,'[i',L,']');
        if (actions.propName) {
            me.body.push('.', actions.propName);
        }
        me.body.push('\n',
            'xindex=i',L,'+1\n');
    },

    createArrayTest: ('isArray' in Array) ? function(L) {
        return 'Array.isArray(c' + L + ')';
    } : function(L) {
        return 'ts.call(c' + L + ')==="[object Array]"';
    },

    doExec: function (action, actions) {
        var me = this,
            name = 'f' + me.definitions.length;

        me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
                            ' try { with(values) {',
                            '  ' + action,
                            ' }} catch(e) {',
                            '}',
                      '}');

        me.body.push(name + me.callFn + '\n');
    },

    
    

    addFn: function (body) {
        var me = this,
            name = 'f' + me.definitions.length;

        if (body === '.') {
            me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
                            ' return values',
                       '}');
        } else if (body === '..') {
            me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
                            ' return parent',
                       '}');
        } else {
            me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
                            ' try { with(values) {',
                            '  return(' + body + ')',
                            ' }} catch(e) {',
                            '}',
                       '}');
        }

        return name;
    },

    parseTag: function (tag) {
        var me = this,
            m = me.tagRe.exec(tag),
            name = m[1],
            format = m[2],
            args = m[3],
            math = m[4],
            v;

        
        if (name == '.') {
            
            if (!me.validTypes) {
                me.definitions.push('var validTypes={string:1,number:1,boolean:1};');
                me.validTypes = true;
            }
            v = 'validTypes[typeof values] || ts.call(values) === "[object Date]" ? values : ""';
        }
        
        else if (name == '#') {
            v = 'xindex';
        }
        else if (name.substr(0, 7) == "parent.") {
            v = name;
        }
        
        else if (isNaN(name) && name.indexOf('-') == -1 && name.indexOf('.') != -1) {
            v = "values." + name;
        }
        
        
        else {    
            v = "values['" + name + "']";
        }

        if (math) {
            v = '(' + v + math + ')';
        }

        if (format && me.useFormat) {
            args = args ? ',' + args : "";
            if (format.substr(0, 5) != "this.") {
                format = "fm." + format + '(';
            } else {
                format += '(';
            }
        } else {
            return v;
        }

        return format + v + args + ')';
    },

    
    evalTpl: function ($) {

        
        
        
        
        eval($);
        return $;
    },

    newLineRe: /\r\n|\r|\n/g,
    aposRe: /[']/g,
    intRe:  /^\s*(\d+)\s*$/,
    tagRe:  /([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?/

}, function () {
    var proto = this.prototype;

    proto.fnArgs = 'out,values,parent,xindex,xcount';
    proto.callFn = '.call(this,' + proto.fnArgs + ')';
});

/**
 * A template class that supports advanced functionality like:
 *
 * - Autofilling arrays using templates and sub-templates
 * - Conditional processing with basic comparison operators
 * - Basic math function support
 * - Execute arbitrary inline code with special built-in template variables
 * - Custom member functions
 * - Many special tags and built-in operators that aren't defined as part of the API, but are supported in the templates that can be created
 *
 * XTemplate provides the templating mechanism built into {@link Ext.view.View}.
 *
 * The {@link Ext.Template} describes the acceptable parameters to pass to the constructor. The following examples
 * demonstrate all of the supported features.
 *
 * # Sample Data
 *
 * This is the data object used for reference in each code example:
 *
 *     var data = {
 *         name: 'Don Griffin',
 *         title: 'Senior Technomage',
 *         company: 'Sencha Inc.',
 *         drinks: ['Coffee', 'Water', 'More Coffee'],
 *         kids: [
 *             { name: 'Aubrey',  age: 17 },
 *             { name: 'Joshua',  age: 13 },
 *             { name: 'Cale',    age: 10 },
 *             { name: 'Nikol',   age: 5 },
 *             { name: 'Solomon', age: 0 }
 *         ]
 *     };
 *
 * # Auto filling of arrays
 *
 * The **tpl** tag and the **for** operator are used to process the provided data object:
 *
 * - If the value specified in for is an array, it will auto-fill, repeating the template block inside the tpl
 *   tag for each item in the array.
 * - If for="." is specified, the data object provided is examined.
 * - While processing an array, the special variable {#} will provide the current array index + 1 (starts at 1, not 0).
 *
 * Examples:
 *
 *     <tpl for=".">...</tpl>       
 *     <tpl for="foo">...</tpl>     
 *     <tpl for="foo.bar">...</tpl> 
 *
 * Using the sample data above:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Kids: ',
 *         '<tpl for=".">',       
 *             '<p>{#}. {name}</p>',  
 *         '</tpl></p>'
 *     );
 *     tpl.overwrite(panel.body, data.kids); 
 *
 * An example illustrating how the **for** property can be leveraged to access specified members of the provided data
 * object to populate the template:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Title: {title}</p>',
 *         '<p>Company: {company}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',     
 *             '<p>{name}</p>',
 *         '</tpl></p>'
 *     );
 *     tpl.overwrite(panel.body, data);  
 *
 * Flat arrays that contain values (and not objects) can be auto-rendered using the special **`{.}`** variable inside a
 * loop. This variable will represent the value of the array at the current index:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>{name}\'s favorite beverages:</p>',
 *         '<tpl for="drinks">',
 *             '<div> - {.}</div>',
 *         '</tpl>'
 *     );
 *     tpl.overwrite(panel.body, data);
 *
 * When processing a sub-template, for example while looping through a child array, you can access the parent object's
 * members via the **parent** object:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '<tpl if="age &gt; 1">',
 *                 '<p>{name}</p>',
 *                 '<p>Dad: {parent.name}</p>',
 *             '</tpl>',
 *         '</tpl></p>'
 *     );
 *     tpl.overwrite(panel.body, data);
 *
 * # Conditional processing with basic comparison operators
 *
 * The **tpl** tag and the **if** operator are used to provide conditional checks for deciding whether or not to render
 * specific parts of the template.
 *
 * Using the sample data above:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '<tpl if="age &gt; 1">',
 *                 '<p>{name}</p>',
 *             '</tpl>',
 *         '</tpl></p>'
 *     );
 *     tpl.overwrite(panel.body, data);
 *
 * More advanced conditionals are also supported:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '<p>{name} is a ',
 *             '<tpl if="age &gt;= 13">',
 *                 '<p>teenager</p>',
 *             '<tpl elseif="age &gt;= 2">',
 *                 '<p>kid</p>',
 *             '<tpl else>',
 *                 '<p>baby</p>',
 *             '</tpl>',
 *         '</tpl></p>'
 *     );
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '<p>{name} is a ',
 *             '<tpl switch="name">',
 *                 '<tpl case="Aubrey" case="Nikol">',
 *                     '<p>girl</p>',
 *                 '<tpl default>',
 *                     '<p>boy</p>',
 *             '</tpl>',
 *         '</tpl></p>'
 *     );
 *
 * A `break` is implied between each case and default, however, multiple cases can be listed
 * in a single &lt;tpl&gt; tag.
 *
 * # Using double quotes
 *
 * Examples:
 *
 *     var tpl = new Ext.XTemplate(
 *         "<tpl if='age &gt; 1 && age &lt; 10'>Child</tpl>",
 *         "<tpl if='age &gt;= 10 && age &lt; 18'>Teenager</tpl>",
 *         "<tpl if='this.isGirl(name)'>...</tpl>",
 *         '<tpl if="id == \'download\'">...</tpl>',
 *         "<tpl if='needsIcon'><img src='{icon}' class='{iconCls}'/></tpl>",
 *         "<tpl if='name == \"Don\"'>Hello</tpl>"
 *     );
 *
 * # Basic math support
 *
 * The following basic math operators may be applied directly on numeric data values:
 *
 *     + - * /
 *
 * For example:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '<tpl if="age &gt; 1">',  
 *                 '<p>{#}: {name}</p>',  
 *                 '<p>In 5 Years: {age+5}</p>',  
 *                 '<p>Dad: {parent.name}</p>',
 *             '</tpl>',
 *         '</tpl></p>'
 *     );
 *     tpl.overwrite(panel.body, data);
 *
 * # Execute arbitrary inline code with special built-in template variables
 *
 * Anything between `{[ ... ]}` is considered code to be executed in the scope of the template.
 * The expression is evaluated and the result is included in the generated result. There are
 * some special variables available in that code:
 *
 * - **out**: The output array into which the template is being appended (using `push` to later
 *   `join`).
 * - **values**: The values in the current scope. If you are using scope changing sub-templates,
 *   you can change what values is.
 * - **parent**: The scope (values) of the ancestor template.
 * - **xindex**: If you are in a looping template, the index of the loop you are in (1-based).
 * - **xcount**: If you are in a looping template, the total length of the array you are looping.
 *
 * This example demonstrates basic row striping using an inline code block and the xindex variable:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
 *             '{name}',
 *             '</div>',
 *         '</tpl></p>'
 *      );
 *
 * Any code contained in "verbatim" blocks (using "{% ... %}") will be inserted directly in
 * the generated code for the template. These blocks are not included in the output. This
 * can be used for simple things like break/continue in a loop, or control structures or
 * method calls (when they don't produce output). The `this` references the template instance.
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '{% if (xindex % 2 === 0) continue; %}',
 *             '{name}',
 *             '{% if (xindex > 100) break; %}',
 *             '</div>',
 *         '</tpl></p>'
 *      );
 *
 * # Template member functions
 *
 * One or more member functions can be specified in a configuration object passed into the XTemplate constructor for
 * more complex processing:
 *
 *     var tpl = new Ext.XTemplate(
 *         '<p>Name: {name}</p>',
 *         '<p>Kids: ',
 *         '<tpl for="kids">',
 *             '<tpl if="this.isGirl(name)">',
 *                 '<p>Girl: {name} - {age}</p>',
 *             '<tpl else>',
 *                 '<p>Boy: {name} - {age}</p>',
 *             '</tpl>',
 *             '<tpl if="this.isBaby(age)">',
 *                 '<p>{name} is a baby!</p>',
 *             '</tpl>',
 *         '</tpl></p>',
 *         {
 *             // XTemplate configuration:
 *             disableFormats: true,
 *             // member functions:
 *             isGirl: function(name){
 *                return name == 'Aubrey' || name == 'Nikol';
 *             },
 *             isBaby: function(age){
 *                return age < 1;
 *             }
 *         }
 *     );
 *     tpl.overwrite(panel.body, data);
 */
Ext.define('Ext.XTemplate', {
    extend: 'Ext.Template',

    requires: 'Ext.XTemplateCompiler',

    /**
     * @private
     */
    emptyObj: {},

    /**
     * @cfg {Boolean} compiled
     * Only applies to {@link Ext.Template}, XTemplates are compiled automatically on the
     * first call to {@link #apply} or {@link #applyOut}.
     */

    /**
     * @cfg {String/Array} definitions
     * Optional. A statement, or array of statements which set up `var`s which may then
     * be accessed within the scope of the generated function.
     */

    apply: function(values, parent) {
        return this.applyOut(values, [], parent).join('');
    },

    applyOut: function(values, out, parent) {
        var me = this,
            compiler;

        if (!me.fn) {
            compiler = new Ext.XTemplateCompiler({
                useFormat: me.disableFormats !== true,
                definitions: me.definitions
            });

            me.fn = compiler.compile(me.html);
        }

        try {
            me.fn.call(me, out, values, parent || me.emptyObj, 1, 1);
        } catch (e) {
        }

        return out;
    },

    /**
     * Does nothing. XTemplates are compiled automatically, so this function simply returns this.
     * @return {Ext.XTemplate} this
     */
    compile: function() {
        return this;
    },

    statics: {
        /**
         * Gets an `XTemplate` from an object (an instance of an {@link Ext#define}'d class).
         * Many times, templates are configured high in the class hierarchy and are to be
         * shared by all classes that derive from that base. To further complicate matters,
         * these templates are seldom actual instances but are rather configurations. For
         * example:
         * 
         *      Ext.define('MyApp.Class', {
         *          someTpl: [
         *              'tpl text here'
         *          ]
         *      });
         * 
         * The goal being to share that template definition with all instances and even
         * instances of derived classes, until `someTpl` is overridden. This method will
         * "upgrade" these configurations to be real `XTemplate` instances *in place* (to
         * avoid creating one instance per object).
         *
         * @param {Object} instance The object from which to get the `XTemplate` (must be
         * an instance of an {@link Ext#define}'d class).
         * @param {String} name The name of the property by which to get the `XTemplate`.
         * @return {Ext.XTemplate} The `XTemplate` instance or null if not found.
         * @protected
         */
        getTpl: function (instance, name) {
            var tpl = instance[name], // go for it! 99% of the time we will get it!
                proto;

            if (tpl && !tpl.isTemplate) { // tpl is just a configuration (not an instance)
                // create the template instance from the configuration:
                tpl = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);

                // and replace the reference with the new instance:
                if (instance.hasOwnProperty(name)) { // the tpl is on the instance
                    instance[name] = tpl;
                } else { // must be somewhere in the prototype chain
                    for (proto = instance.self.prototype; proto; proto = proto.superclass) {
                        if (proto.hasOwnProperty(name)) {
                            proto[name] = tpl;
                            break;
                        }
                    }
                }
            }
            // else !tpl (no such tpl) or the tpl is an instance already... either way, tpl
            // is ready to return

            return tpl || null;
        }
    }
});

/**
 * Controllers are the glue that binds an application together. All they really do is listen for events (usually from
 * views) and take some action. Here's how we might create a Controller to manage Users:
 *
 *     Ext.define('MyApp.controller.Users', {
 *         extend: 'Ext.app.Controller',
 *
 *         init: function() {
 *             console.log('Initialized Users! This happens before the Application launch function is called');
 *         }
 *     });
 *
 * The init function is a special method that is called when your application boots. It is called before the
 * {@link Ext.app.Application Application}'s launch function is executed so gives a hook point to run any code before
 * your Viewport is created.
 *
 * The init function is a great place to set up how your controller interacts with the view, and is usually used in
 * conjunction with another Controller function - {@link Ext.app.Controller#control control}. The control function
 * makes it easy to listen to events on your view classes and take some action with a handler function. Let's update
 * our Users controller to tell us when the panel is rendered:
 *
 *     Ext.define('MyApp.controller.Users', {
 *         extend: 'Ext.app.Controller',
 *
 *         init: function() {
 *             this.control({
 *                 'viewport > panel': {
 *                     render: this.onPanelRendered
 *                 }
 *             });
 *         },
 *
 *         onPanelRendered: function() {
 *             console.log('The panel was rendered');
 *         }
 *     });
 *
 * We've updated the init function to use this.control to set up listeners on views in our application. The control
 * function uses the new ComponentQuery engine to quickly and easily get references to components on the page. If you
 * are not familiar with ComponentQuery yet, be sure to check out the {@link Ext.ComponentQuery documentation}. In brief though,
 * it allows us to pass a CSS-like selector that will find every matching component on the page.
 *
 * In our init function above we supplied 'viewport > panel', which translates to "find me every Panel that is a direct
 * child of a Viewport". We then supplied an object that maps event names (just 'render' in this case) to handler
 * functions. The overall effect is that whenever any component that matches our selector fires a 'render' event, our
 * onPanelRendered function is called.
 *
 * ## Using refs
 *
 * One of the most useful parts of Controllers is the new ref system. These use the new {@link Ext.ComponentQuery} to
 * make it really easy to get references to Views on your page. Let's look at an example of this now:
 *
 *     Ext.define('MyApp.controller.Users', {
 *         extend: 'Ext.app.Controller',
 *
 *         refs: [
 *             {
 *                 ref: 'list',
 *                 selector: 'grid'
 *             }
 *         ],
 *
 *         init: function() {
 *             this.control({
 *                 'button': {
 *                     click: this.refreshGrid
 *                 }
 *             });
 *         },
 *
 *         refreshGrid: function() {
 *             this.getList().store.load();
 *         }
 *     });
 *
 * This example assumes the existence of a {@link Ext.grid.Panel Grid} on the page, which contains a single button to
 * refresh the Grid when clicked. In our refs array, we set up a reference to the grid. There are two parts to this -
 * the 'selector', which is a {@link Ext.ComponentQuery ComponentQuery} selector which finds any grid on the page and
 * assigns it to the reference 'list'.
 *
 * By giving the reference a name, we get a number of things for free. The first is the getList function that we use in
 * the refreshGrid method above. This is generated automatically by the Controller based on the name of our ref, which
 * was capitalized and prepended with get to go from 'list' to 'getList'.
 *
 * The way this works is that the first time getList is called by your code, the ComponentQuery selector is run and the
 * first component that matches the selector ('grid' in this case) will be returned. All future calls to getList will
 * use a cached reference to that grid. Usually it is advised to use a specific ComponentQuery selector that will only
 * match a single View in your application (in the case above our selector will match any grid on the page).
 *
 * Bringing it all together, our init function is called when the application boots, at which time we call this.control
 * to listen to any click on a {@link Ext.button.Button button} and call our refreshGrid function (again, this will
 * match any button on the page so we advise a more specific selector than just 'button', but have left it this way for
 * simplicity). When the button is clicked we use out getList function to refresh the grid.
 *
 * You can create any number of refs and control any number of components this way, simply adding more functions to
 * your Controller as you go. For an example of real-world usage of Controllers see the Feed Viewer example in the
 * examples/app/feed-viewer folder in the SDK download.
 *
 * ## Generated getter methods
 *
 * Refs aren't the only thing that generate convenient getter methods. Controllers often have to deal with Models and
 * Stores so the framework offers a couple of easy ways to get access to those too. Let's look at another example:
 *
 *     Ext.define('MyApp.controller.Users', {
 *         extend: 'Ext.app.Controller',
 *
 *         models: ['User'],
 *         stores: ['AllUsers', 'AdminUsers'],
 *
 *         init: function() {
 *             var User = this.getUserModel(),
 *                 allUsers = this.getAllUsersStore();
 *
 *             var ed = new User({name: 'Ed'});
 *             allUsers.add(ed);
 *         }
 *     });
 *
 * By specifying Models and Stores that the Controller cares about, it again dynamically loads them from the appropriate
 * locations (app/model/User.js, app/store/AllUsers.js and app/store/AdminUsers.js in this case) and creates getter
 * functions for them all. The example above will create a new User model instance and add it to the AllUsers Store.
 * Of course, you could do anything in this function but in this case we just did something simple to demonstrate the
 * functionality.
 *
 * ## Further Reading
 *
 * For more information about writing Ext JS 4 applications, please see the
 * [application architecture guide](#/guide/application_architecture). Also see the {@link Ext.app.Application} documentation.
 *
 * @docauthor Ed Spencer
 */
Ext.define('Ext.app.Controller', {

    mixins: {
        observable: 'Ext.util.Observable'
    },

    
    
    

    

    

    

    onClassExtended: function(cls, data, hooks) {
        var className = Ext.getClassName(cls),
            match = className.match(/^(.*)\.controller\./),
            namespace,
            onBeforeClassCreated,
            requires,
            modules,
            namespaceAndModule;
        
        if (match !== null) {
            namespace = Ext.Loader.getPrefix(className) || match[1];
            onBeforeClassCreated = hooks.onBeforeCreated;
            requires = [];
            modules = ['model', 'view', 'store'];

            hooks.onBeforeCreated = function(cls, data) {
                var i, ln, module,
                    items, j, subLn, item;

                for (i = 0,ln = modules.length; i < ln; i++) {
                    module = modules[i];
                    namespaceAndModule = namespace + '.' + module + '.';

                    items = Ext.Array.from(data[module + 's']);

                    for (j = 0,subLn = items.length; j < subLn; j++) {
                        item = items[j];
                        
                        
                        
                        
                        
                        
                        
                        if (item.indexOf('.') !== -1 && (Ext.ClassManager.isCreated(item) || Ext.Loader.isAClassNameWithAKnownPrefix(item))) {
                            requires.push(item);
                        } else {
                            requires.push(namespaceAndModule + item);
                        }
                    }
                }

                Ext.require(requires, Ext.Function.pass(onBeforeClassCreated, arguments, this));
            };
        }
    },

    
    constructor: function(config) {
        this.mixins.observable.constructor.call(this, config);

        Ext.apply(this, config || {});
        this.createGetters('model', this.models);
        this.createGetters('store', this.stores);
        this.createGetters('view', this.views);

        if (this.refs) {
            this.ref(this.refs);
        }
    },

    
    init: Ext.emptyFn,

    
    onLaunch: Ext.emptyFn,

    createGetters: function(type, refs) {
        type = Ext.String.capitalize(type);

        var i      = 0,
            length = (refs) ? refs.length : 0,
            fn, ref, parts, x, numParts;

        for (; i < length; i++) {
            fn    = 'get';
            ref   = refs[i];
            parts = ref.split('.');
            numParts = parts.length;

            
            for (x = 0 ; x < numParts; x++) {
                fn += Ext.String.capitalize(parts[x]);
            }

            fn += type;

            if (!this[fn]) {
                this[fn] = Ext.Function.pass(this['get' + type], [ref], this);
            }
            
            this[fn](ref);
        }
    },

    ref: function(refs) {
        refs = Ext.Array.from(refs);
        
        var me = this,
            i = 0,
            length = refs.length,
            info, ref, fn;
        
        me.references = me.references || [];

        for (; i < length; i++) {
            info = refs[i];
            ref  = info.ref;
            fn   = 'get' + Ext.String.capitalize(ref);

            if (!me[fn]) {
                me[fn] = Ext.Function.pass(me.getRef, [ref, info], me);
            }
            me.references.push(ref.toLowerCase());
        }
    },

    
    addRef: function(ref) {
        return this.ref([ref]);
    },

    getRef: function(ref, info, config) {
        this.refCache = this.refCache || {};
        info = info || {};
        config = config || {};

        Ext.apply(info, config);

        if (info.forceCreate) {
            return Ext.ComponentManager.create(info, 'component');
        }

        var me = this,
            cached = me.refCache[ref];

        if (!cached) {
            me.refCache[ref] = cached = Ext.ComponentQuery.query(info.selector)[0];
            if (!cached && info.autoCreate) {
                me.refCache[ref] = cached = Ext.ComponentManager.create(info, 'component');
            }
            if (cached) {
                cached.on('beforedestroy', function() {
                    me.refCache[ref] = null;
                });
            }
        }

        return cached;
    },

    
    hasRef: function(ref) {
        return this.references && this.references.indexOf(ref.toLowerCase()) !== -1;
    },

    
    control: function(selectors, listeners) {
        this.application.control(selectors, listeners, this);
    },

    
    getController: function(name) {
        return this.application.getController(name);
    },

    
    getStore: function(name) {
        return this.application.getStore(name);
    },

    
    getModel: function(model) {
        return this.application.getModel(model);
    },

    
    getView: function(view) {
        return this.application.getView(view);
    }
});


Ext.define('Ext.chart.Label', {

    

    requires: ['Ext.draw.Color'],

    

    

    
    colorStringRe: /url\s*\(\s*#([^\/)]+)\s*\)/,

    
    constructor: function(config) {
        var me = this;
        me.label = Ext.applyIf(me.label || {},
        {
            display: "none",
            color: "#000",
            field: "name",
            minMargin: 50,
            font: "11px Helvetica, sans-serif",
            orientation: "horizontal",
            renderer: function(v) {
                return v;
            }
        });

        if (me.label.display !== 'none') {
            me.labelsGroup = me.chart.surface.getGroup(me.seriesId + '-labels');
        }
    },

    
    renderLabels: function() {
        var me = this,
            chart = me.chart,
            gradients = chart.gradients,
            items = me.items,
            animate = chart.animate,
            config = me.label,
            display = config.display,
            color = config.color,
            field = [].concat(config.field),
            group = me.labelsGroup,
            groupLength = (group || 0) && group.length,
            store = me.chart.getChartStore(),
            len = store.getCount(),
            itemLength = (items || 0) && items.length,
            ratio = itemLength / len,
            gradientsCount = (gradients || 0) && gradients.length,
            Color = Ext.draw.Color,
            hides = [],
            gradient, i, count, groupIndex, index, j, k, colorStopTotal, colorStopIndex, colorStop, item, label,
            storeItem, sprite, spriteColor, spriteBrightness, labelColor, colorString;

        if (display == 'none') {
            return;
        }
        
        if(itemLength == 0){
            while(groupLength--) {
                hides.push(groupLength);
            }
        } else {
            for (i = 0, count = 0, groupIndex = 0; i < len; i++) {
                index = 0;
                for (j = 0; j < ratio; j++) {
                    item = items[count];
                    label = group.getAt(groupIndex);
                    storeItem = store.getAt(i);
                    
                    while(this.__excludes && this.__excludes[index]) {
                        index++;
                    }

                    if (!item && label) {
                        label.hide(true);
                        groupIndex++;
                    }

                    if (item && field[j]) {
                        if (!label) {
                            label = me.onCreateLabel(storeItem, item, i, display, j, index);
                        }
                        me.onPlaceLabel(label, storeItem, item, i, display, animate, j, index);
                        groupIndex++;

                        
                        if (config.contrast && item.sprite) {
                            sprite = item.sprite;
                            
                            if (sprite._endStyle) {
                                colorString = sprite._endStyle.fill;
                            }
                            else if (sprite._to) {
                                colorString = sprite._to.fill;
                            }
                            else {
                                colorString = sprite.attr.fill;
                            }
                            colorString = colorString || sprite.attr.fill;

                            spriteColor = Color.fromString(colorString);
                            
                            if (colorString && !spriteColor) {
                                colorString = colorString.match(me.colorStringRe)[1];
                                for (k = 0; k < gradientsCount; k++) {
                                    gradient = gradients[k];
                                    if (gradient.id == colorString) {
                                        
                                        colorStop = 0; colorStopTotal = 0;
                                        for (colorStopIndex in gradient.stops) {
                                            colorStop++;
                                            colorStopTotal += Color.fromString(gradient.stops[colorStopIndex].color).getGrayscale();
                                        }
                                        spriteBrightness = (colorStopTotal / colorStop) / 255;
                                        break;
                                    }
                                }
                            }
                            else {
                                spriteBrightness = spriteColor.getGrayscale() / 255;
                            }
                            if (label.isOutside) {
                                spriteBrightness = 1;
                            }
                            labelColor = Color.fromString(label.attr.color || label.attr.fill).getHSL();
                            labelColor[2] = spriteBrightness > 0.5 ? 0.2 : 0.8;
                            label.setAttributes({
                                fill: String(Color.fromHSL.apply({}, labelColor))
                            }, true);
                        }

                    }
                    count++;
                    index++;
                }
            }
            groupLength = group.length;
        
            while(groupLength > groupIndex){
                hides.push(groupIndex);
                groupIndex++;
           }
        }
        me.hideLabels(hides);
    },

    hideLabels: function(hides){
        var labelsGroup = this.labelsGroup,
            hlen = !!hides && hides.length;

        if (!labelsGroup) {
            return;
        }

        if (hlen === false) {
            hlen = labelsGroup.getCount();
            while (hlen--) {
              labelsGroup.getAt(hlen).hide(true);
            }
        } else {
            while(hlen--) {
                labelsGroup.getAt(hides[hlen]).hide(true);
            }
        }
    }
});


Ext.define('Ext.chart.theme.Theme', {

    

    requires: ['Ext.draw.Color'],

    

    theme: 'Base',
    themeAttrs: false,
    
    initTheme: function(theme) {
        var me = this,
            themes = Ext.chart.theme,
            key, gradients;
        if (theme) {
            theme = theme.split(':');
            for (key in themes) {
                if (key == theme[0]) {
                    gradients = theme[1] == 'gradients';
                    me.themeAttrs = new themes[key]({
                        useGradients: gradients
                    });
                    if (gradients) {
                        me.gradients = me.themeAttrs.gradients;
                    }
                    if (me.themeAttrs.background) {
                        me.background = me.themeAttrs.background;
                    }
                    return;
                }
            }
        }
    }
}, 

function() {
   

(function() {
    Ext.chart.theme = function(config, base) {
        config = config || {};
        var i = 0, d = +new Date(), l, colors, color,
            seriesThemes, markerThemes,
            seriesTheme, markerTheme, 
            key, gradients = [],
            midColor, midL;
        
        if (config.baseColor) {
            midColor = Ext.draw.Color.fromString(config.baseColor);
            midL = midColor.getHSL()[2];
            if (midL < 0.15) {
                midColor = midColor.getLighter(0.3);
            } else if (midL < 0.3) {
                midColor = midColor.getLighter(0.15);
            } else if (midL > 0.85) {
                midColor = midColor.getDarker(0.3);
            } else if (midL > 0.7) {
                midColor = midColor.getDarker(0.15);
            }
            config.colors = [ midColor.getDarker(0.3).toString(),
                              midColor.getDarker(0.15).toString(),
                              midColor.toString(),
                              midColor.getLighter(0.15).toString(),
                              midColor.getLighter(0.3).toString()];

            delete config.baseColor;
        }
        if (config.colors) {
            colors = config.colors.slice();
            markerThemes = base.markerThemes;
            seriesThemes = base.seriesThemes;
            l = colors.length;
            base.colors = colors;
            for (; i < l; i++) {
                color = colors[i];
                markerTheme = markerThemes[i] || {};
                seriesTheme = seriesThemes[i] || {};
                markerTheme.fill = seriesTheme.fill = markerTheme.stroke = seriesTheme.stroke = color;
                markerThemes[i] = markerTheme;
                seriesThemes[i] = seriesTheme;
            }
            base.markerThemes = markerThemes.slice(0, l);
            base.seriesThemes = seriesThemes.slice(0, l);
        
        }
        for (key in base) {
            if (key in config) {
                if (Ext.isObject(config[key]) && Ext.isObject(base[key])) {
                    Ext.apply(base[key], config[key]);
                } else {
                    base[key] = config[key];
                }
            }
        }
        if (config.useGradients) {
            colors = base.colors || (function () {
                var ans = [];
                for (i = 0, seriesThemes = base.seriesThemes, l = seriesThemes.length; i < l; i++) {
                    ans.push(seriesThemes[i].fill || seriesThemes[i].stroke);
                }
                return ans;
            }());
            for (i = 0, l = colors.length; i < l; i++) {
                midColor = Ext.draw.Color.fromString(colors[i]);
                if (midColor) {
                    color = midColor.getDarker(0.1).toString();
                    midColor = midColor.toString();
                    key = 'theme-' + midColor.substr(1) + '-' + color.substr(1) + '-' + d;
                    gradients.push({
                        id: key,
                        angle: 45,
                        stops: {
                            0: {
                                color: midColor.toString()
                            },
                            100: {
                                color: color.toString()
                            }
                        }
                    });
                    colors[i] = 'url(#' + key + ')'; 
                }
            }
            base.gradients = gradients;
            base.colors = colors;
        }
        
        Ext.apply(this, base);
    };
}());
});


Ext.define('Ext.chart.theme.Base', {

    

    requires: ['Ext.chart.theme.Theme'],

    

    constructor: function(config) {
        Ext.chart.theme.call(this, config, {
            background: false,
            axis: {
                stroke: '#444',
                'stroke-width': 1
            },
            axisLabelTop: {
                fill: '#444',
                font: '12px Arial, Helvetica, sans-serif',
                spacing: 2,
                padding: 5,
                renderer: function(v) { return v; }
            },
            axisLabelRight: {
                fill: '#444',
                font: '12px Arial, Helvetica, sans-serif',
                spacing: 2,
                padding: 5,
                renderer: function(v) { return v; }
            },
            axisLabelBottom: {
                fill: '#444',
                font: '12px Arial, Helvetica, sans-serif',
                spacing: 2,
                padding: 5,
                renderer: function(v) { return v; }
            },
            axisLabelLeft: {
                fill: '#444',
                font: '12px Arial, Helvetica, sans-serif',
                spacing: 2,
                padding: 5,
                renderer: function(v) { return v; }
            },
            axisTitleTop: {
                font: 'bold 18px Arial',
                fill: '#444'
            },
            axisTitleRight: {
                font: 'bold 18px Arial',
                fill: '#444',
                rotate: {
                    x:0, y:0,
                    degrees: 270
                }
            },
            axisTitleBottom: {
                font: 'bold 18px Arial',
                fill: '#444'
            },
            axisTitleLeft: {
                font: 'bold 18px Arial',
                fill: '#444',
                rotate: {
                    x:0, y:0,
                    degrees: 270
                }
            },
            series: {
                'stroke-width': 0
            },
            seriesLabel: {
                font: '12px Arial',
                fill: '#333'
            },
            marker: {
                stroke: '#555',
                radius: 3,
                size: 3
            },
            colors: [ "#94ae0a", "#115fa6","#a61120", "#ff8809", "#ffd13e", "#a61187", "#24ad9a", "#7c7474", "#a66111"],
            seriesThemes: [{
                fill: "#115fa6"
            }, {
                fill: "#94ae0a"
            }, {
                fill: "#a61120"
            }, {
                fill: "#ff8809"
            }, {
                fill: "#ffd13e"
            }, {
                fill: "#a61187"
            }, {
                fill: "#24ad9a"
            }, {
                fill: "#7c7474"
            }, {
                fill: "#115fa6"
            }, {
                fill: "#94ae0a"
            }, {
                fill: "#a61120"
            }, {
                fill: "#ff8809"
            }, {
                fill: "#ffd13e"
            }, {
                fill: "#a61187"
            }, {
                fill: "#24ad9a"
            }, {
                fill: "#7c7474"
            }, {
                fill: "#a66111"
            }],
            markerThemes: [{
                fill: "#115fa6",
                type: 'circle' 
            }, {
                fill: "#94ae0a",
                type: 'cross'
            }, {
                fill: "#115fa6",
                type: 'plus' 
            }, {
                fill: "#94ae0a",
                type: 'circle'
            }, {
                fill: "#a61120",
                type: 'cross'
            }]
        });
    }
}, function() {
    var palette = ['#b1da5a', '#4ce0e7', '#e84b67', '#da5abd', '#4d7fe6', '#fec935'],
        names = ['Green', 'Sky', 'Red', 'Purple', 'Blue', 'Yellow'],
        i = 0, j = 0, l = palette.length, themes = Ext.chart.theme,
        categories = [['#f0a50a', '#c20024', '#2044ba', '#810065', '#7eae29'],
                      ['#6d9824', '#87146e', '#2a9196', '#d39006', '#1e40ac'],
                      ['#fbbc29', '#ce2e4e', '#7e0062', '#158b90', '#57880e'],
                      ['#ef5773', '#fcbd2a', '#4f770d', '#1d3eaa', '#9b001f'],
                      ['#7eae29', '#fdbe2a', '#910019', '#27b4bc', '#d74dbc'],
                      ['#44dce1', '#0b2592', '#996e05', '#7fb325', '#b821a1']],
        cats = categories.length;
    
    
    for (; i < l; i++) {
        themes[names[i]] = (function(color) {
            return Ext.extend(themes.Base, {
                constructor: function(config) {
                    themes.Base.prototype.constructor.call(this, Ext.apply({
                        baseColor: color
                    }, config));
                }
            });
        }(palette[i]));
    }
    
    
    for (i = 0; i < cats; i++) {
        themes['Category' + (i + 1)] = (function(category) {
            return Ext.extend(themes.Base, {
                constructor: function(config) {
                    themes.Base.prototype.constructor.call(this, Ext.apply({
                        colors: category
                    }, config));
                }
            });
        }(categories[i]));
    }
});


Ext.define('Ext.data.Batch', {
    mixins: {
        observable: 'Ext.util.Observable'
    },

    
    autoStart: false,
    
    
    pauseOnException: false,

    
    current: -1,

    
    total: 0,

    
    isRunning: false,

    
    isComplete: false,

    
    hasException: false,

    
    constructor: function(config) {
        var me = this;

        

        

        

        me.mixins.observable.constructor.call(me, config);

        
        me.operations = [];
        
        
        me.exceptions = [];
    },

    
    add: function(operation) {
        this.total++;

        operation.setBatch(this);

        this.operations.push(operation);
        
        return this;
    },

    
    start: function( index) {
        var me = this;
        
        if (me.isRunning) {
            return me;
        }
        
        me.exceptions.length = 0;
        me.hasException = false;
        me.isRunning = true;

        return me.runOperation(Ext.isDefined(index) ? index : me.current + 1);
    },
    
    
    retry: function() {
        return this.start(this.current);
    },

    
    runNextOperation: function() {
        return this.runOperation(this.current + 1);
    },

    
    pause: function() {
        this.isRunning = false;
        return this;
    },

    
    runOperation: function(index) {
        var me = this,
            operations = me.operations,
            operation = operations[index],
            onProxyReturn;

        if (operation === undefined) {
            me.isRunning = false;
            me.isComplete = true;
            me.fireEvent('complete', me, operations[operations.length - 1]);
        } else {
            me.current = index;

            onProxyReturn = function(operation) {
                var hasException = operation.hasException();

                if (hasException) {
                    me.hasException = true;
                    me.exceptions.push(operation);
                    me.fireEvent('exception', me, operation);
                }

                if (hasException && me.pauseOnException) {
                    me.pause();
                } else {
                    operation.setCompleted();
                    me.fireEvent('operationcomplete', me, operation);
                    me.runNextOperation();
                }
            };

            operation.setStarted();

            me.proxy[operation.action](operation, onProxyReturn, me);
        }
        
        return me;
    }
});


Ext.define('Ext.data.Connection', {
    mixins: {
        observable: 'Ext.util.Observable'
    },

    statics: {
        requestId: 0
    },

    url: null,
    async: true,
    method: null,
    username: '',
    password: '',

    
    disableCaching: true,

    
    withCredentials: false,

    
    cors: false,

    
    disableCachingParam: '_dc',

    
    timeout : 30000,

    

    

    

    

    useDefaultHeader : true,
    defaultPostHeader : 'application/x-www-form-urlencoded; charset=UTF-8',
    useDefaultXhrHeader : true,
    defaultXhrHeader : 'XMLHttpRequest',

    constructor : function(config) {
        config = config || {};
        Ext.apply(this, config);

        
        
        
        this.requests = {};
        this.mixins.observable.constructor.call(this);
    },

    
    request : function(options) {
        options = options || {};
        var me = this,
            scope = options.scope || window,
            username = options.username || me.username,
            password = options.password || me.password || '',
            async,
            requestOptions,
            request,
            headers,
            xhr;

        if (me.fireEvent('beforerequest', me, options) !== false) {

            requestOptions = me.setOptions(options, scope);

            if (me.isFormUpload(options)) {
                me.upload(options.form, requestOptions.url, requestOptions.data, options);
                return null;
            }

            
            if (options.autoAbort || me.autoAbort) {
                me.abort();
            }

            
            async = options.async !== false ? (options.async || me.async) : false;
            xhr = me.openRequest(options, requestOptions, async, username, password);

            headers = me.setupHeaders(xhr, options, requestOptions.data, requestOptions.params);

            
            request = {
                id: ++Ext.data.Connection.requestId,
                xhr: xhr,
                headers: headers,
                options: options,
                async: async,
                timeout: setTimeout(function() {
                    request.timedout = true;
                    me.abort(request);
                }, options.timeout || me.timeout)
            };
            me.requests[request.id] = request;
            me.latestId = request.id;
            
            if (async) {
                xhr.onreadystatechange = Ext.Function.bind(me.onStateChange, me, [request]);
            }

            
            xhr.send(requestOptions.data);
            if (!async) {
                return me.onComplete(request);
            }
            return request;
        } else {
            Ext.callback(options.callback, options.scope, [options, undefined, undefined]);
            return null;
        }
    },

    
    upload: function(form, url, params, options) {
        form = Ext.getDom(form);
        options = options || {};

        var id = Ext.id(),
            frame = document.createElement('iframe'),
            hiddens = [],
            encoding = 'multipart/form-data',
            buf = {
                target: form.target,
                method: form.method,
                encoding: form.encoding,
                enctype: form.enctype,
                action: form.action
            },
            addField = function(name, value) {
                hiddenItem = document.createElement('input');
                Ext.fly(hiddenItem).set({
                    type: 'hidden',
                    value: value,
                    name: name
                });
                form.appendChild(hiddenItem);
                hiddens.push(hiddenItem);
            },
            hiddenItem, obj, value, name, vLen, v, hLen, h;

        
        Ext.fly(frame).set({
            id: id,
            name: id,
            cls: Ext.baseCSSPrefix + 'hide-display',
            src: Ext.SSL_SECURE_URL
        });

        document.body.appendChild(frame);

        
        if (document.frames) {
            document.frames[id].name = id;
        }

        Ext.fly(form).set({
            target: id,
            method: 'POST',
            enctype: encoding,
            encoding: encoding,
            action: url || buf.action
        });

        
        if (params) {
            obj = Ext.Object.fromQueryString(params) || {};

            for (name in obj) {
                if (obj.hasOwnProperty(name)) {
                    value = obj[name];  
                    if (Ext.isArray(value)) {
                        vLen = value.length;
                        for (v = 0; v < vLen; v++) {
                            addField(name, value[v]);
                        }
                    } else {
                        addField(name, value);
                    }
                }
            }
        }

        Ext.fly(frame).on('load', Ext.Function.bind(this.onUploadComplete, this, [frame, options]), null, {single: true});
        form.submit();

        Ext.fly(form).set(buf);

        hLen = hiddens.length;

        for (h = 0; h < hLen; h++) {
            Ext.removeNode(hiddens[h]);
        }
    },

    
    onUploadComplete: function(frame, options) {
        var me = this,
            
            response = {
                responseText: '',
                responseXML: null
            }, doc, contentNode;

        try {
            doc = frame.contentWindow.document || frame.contentDocument || window.frames[frame.id].document;
            if (doc) {
                if (doc.body) {

                    
                    
                    if ((contentNode = doc.body.firstChild) && /pre/i.test(contentNode.tagName)) {
                        response.responseText = contentNode.innerText;
                    }

                    
                    
                    else if (contentNode = doc.getElementsByTagName('textarea')[0]) {
                        response.responseText = contentNode.value;
                    }
                    
                    else {
                        response.responseText = doc.body.textContent || doc.body.innerText;
                    }
                }
                
                response.responseXML = doc.XMLDocument || doc;
            }
        } catch (e) {
        }

        me.fireEvent('requestcomplete', me, response, options);

        Ext.callback(options.success, options.scope, [response, options]);
        Ext.callback(options.callback, options.scope, [options, true, response]);

        setTimeout(function() {
            Ext.removeNode(frame);
        }, 100);
    },

    
    isFormUpload: function(options) {
        var form = this.getForm(options);
        if (form) {
            return (options.isUpload || (/multipart\/form-data/i).test(form.getAttribute('enctype')));
        }
        return false;
    },

    
    getForm: function(options) {
        return Ext.getDom(options.form) || null;
    },

    
    setOptions: function(options, scope) {
        var me = this,
            params = options.params || {},
            extraParams = me.extraParams,
            urlParams = options.urlParams,
            url = options.url || me.url,
            jsonData = options.jsonData,
            method,
            disableCache,
            data;


        
        if (Ext.isFunction(params)) {
            params = params.call(scope, options);
        }

        
        if (Ext.isFunction(url)) {
            url = url.call(scope, options);
        }

        url = this.setupUrl(options, url);


        
        data = options.rawData || options.xmlData || jsonData || null;
        if (jsonData && !Ext.isPrimitive(jsonData)) {
            data = Ext.encode(data);
        }

        
        if (Ext.isObject(params)) {
            params = Ext.Object.toQueryString(params);
        }

        if (Ext.isObject(extraParams)) {
            extraParams = Ext.Object.toQueryString(extraParams);
        }

        params = params + ((extraParams) ? ((params) ? '&' : '') + extraParams : '');

        urlParams = Ext.isObject(urlParams) ? Ext.Object.toQueryString(urlParams) : urlParams;

        params = this.setupParams(options, params);

        
        method = (options.method || me.method || ((params || data) ? 'POST' : 'GET')).toUpperCase();
        this.setupMethod(options, method);


        disableCache = options.disableCaching !== false ? (options.disableCaching || me.disableCaching) : false;
        
        if (method === 'GET' && disableCache) {
            url = Ext.urlAppend(url, (options.disableCachingParam || me.disableCachingParam) + '=' + (new Date().getTime()));
        }

        
        if ((method == 'GET' || data) && params) {
            url = Ext.urlAppend(url, params);
            params = null;
        }

        
        if (urlParams) {
            url = Ext.urlAppend(url, urlParams);
        }

        return {
            url: url,
            method: method,
            data: data || params || null
        };
    },

    
    setupUrl: function(options, url) {
        var form = this.getForm(options);
        if (form) {
            url = url || form.action;
        }
        return url;
    },


    
    setupParams: function(options, params) {
        var form = this.getForm(options),
            serializedForm;
        if (form && !this.isFormUpload(options)) {
            serializedForm = Ext.Element.serializeForm(form);
            params = params ? (params + '&' + serializedForm) : serializedForm;
        }
        return params;
    },

    
    setupMethod: function(options, method) {
        if (this.isFormUpload(options)) {
            return 'POST';
        }
        return method;
    },

    
    setupHeaders: function(xhr, options, data, params) {
        var me = this,
            headers = Ext.apply({}, options.headers || {}, me.defaultHeaders || {}),
            contentType = me.defaultPostHeader,
            jsonData = options.jsonData,
            xmlData = options.xmlData,
            key,
            header;

        if (!headers['Content-Type'] && (data || params)) {
            if (data) {
                if (options.rawData) {
                    contentType = 'text/plain';
                } else {
                    if (xmlData && Ext.isDefined(xmlData)) {
                        contentType = 'text/xml';
                    } else if (jsonData && Ext.isDefined(jsonData)) {
                        contentType = 'application/json';
                    }
                }
            }
            headers['Content-Type'] = contentType;
        }

        if (me.useDefaultXhrHeader && !headers['X-Requested-With']) {
            headers['X-Requested-With'] = me.defaultXhrHeader;
        }
        
        try {
            for (key in headers) {
                if (headers.hasOwnProperty(key)) {
                    header = headers[key];
                    xhr.setRequestHeader(key, header);
                }

            }
        } catch(e) {
            me.fireEvent('exception', key, header);
        }
        return headers;
    },

    
    newRequest: function (options) {
        var xhr;

        if ((options.cors || this.cors) && Ext.isIE && Ext.ieVersion >= 8) {
            xhr = new XDomainRequest();
        } else {
            xhr = this.getXhrInstance();
        }

        return xhr;
    },

    
    openRequest: function (options, requestOptions, async, username, password) {
        var xhr = this.newRequest(options);

        if (username) {
            xhr.open(requestOptions.method, requestOptions.url, async, username, password);
        } else {
            xhr.open(requestOptions.method, requestOptions.url, async);
        }

        if (options.withCredentials || this.withCredentials) {
            xhr.withCredentials = true;
        }

        return xhr;
    },

    
    getXhrInstance: (function() {
        var options = [function() {
            return new XMLHttpRequest();
        }, function() {
            return new ActiveXObject('MSXML2.XMLHTTP.3.0');
        }, function() {
            return new ActiveXObject('MSXML2.XMLHTTP');
        }, function() {
            return new ActiveXObject('Microsoft.XMLHTTP');
        }], i = 0,
            len = options.length,
            xhr;

        for (; i < len; ++i) {
            try {
                xhr = options[i];
                xhr();
                break;
            } catch(e) {
            }
        }
        return xhr;
    }()),

    
    isLoading : function(request) {
        if (!request) {
            request = this.getLatest();
        }
        if (!(request && request.xhr)) {
            return false;
        }
        
        var state = request.xhr.readyState;
        return !(state === 0 || state == 4);
    },

    
    abort : function(request) {
        var me = this,
            xhr;
        
        if (!request) {
            request = me.getLatest();
        }

        if (request && me.isLoading(request)) {
            
            xhr = request.xhr;
            try {
                xhr.onreadystatechange = null;
            } catch (e) {
                
                
                xhr = Ext.emptyFn;
            }
            xhr.abort();
            me.clearTimeout(request);
            if (!request.timedout) {
                request.aborted = true;
            }
            me.onComplete(request);
            me.cleanup(request);
        }
    },
    
    
    abortAll: function(){
        var requests = this.requests,
            id;
        
        for (id in requests) {
            if (requests.hasOwnProperty(id)) {
                this.abort(requests[id]);
            }
        }
    },
    
    
    getLatest: function(){
        var id = this.latestId,
            request;
            
        if (id) {
            request = this.requests[id];
        }
        return request || null;
    },

    
    onStateChange : function(request) {
        if (request.xhr.readyState == 4) {
            this.clearTimeout(request);
            this.onComplete(request);
            this.cleanup(request);
        }
    },

    
    clearTimeout: function(request) {
        clearTimeout(request.timeout);
        delete request.timeout;
    },

    
    cleanup: function(request) {
        request.xhr = null;
        delete request.xhr;
    },

    
    onComplete : function(request) {
        var me = this,
            options = request.options,
            result,
            success,
            response;

        try {
            result = me.parseStatus(request.xhr.status);
        } catch (e) {
            
            result = {
                success : false,
                isException : false
            };
        }
        success = result.success;

        if (success) {
            response = me.createResponse(request);
            me.fireEvent('requestcomplete', me, response, options);
            Ext.callback(options.success, options.scope, [response, options]);
        } else {
            if (result.isException || request.aborted || request.timedout) {
                response = me.createException(request);
            } else {
                response = me.createResponse(request);
            }
            me.fireEvent('requestexception', me, response, options);
            Ext.callback(options.failure, options.scope, [response, options]);
        }
        Ext.callback(options.callback, options.scope, [options, success, response]);
        delete me.requests[request.id];
        return response;
    },

    
    parseStatus: function(status) {
        
        status = status == 1223 ? 204 : status;

        var success = (status >= 200 && status < 300) || status == 304,
            isException = false;

        if (!success) {
            switch (status) {
                case 12002:
                case 12029:
                case 12030:
                case 12031:
                case 12152:
                case 13030:
                    isException = true;
                    break;
            }
        }
        return {
            success: success,
            isException: isException
        };
    },

    
    createResponse : function(request) {
        var xhr = request.xhr,
            headers = {},
            lines = xhr.getAllResponseHeaders().replace(/\r\n/g, '\n').split('\n'),
            count = lines.length,
            line, index, key, value, response;

        while (count--) {
            line = lines[count];
            index = line.indexOf(':');
            if (index >= 0) {
                key = line.substr(0, index).toLowerCase();
                if (line.charAt(index + 1) == ' ') {
                    ++index;
                }
                headers[key] = line.substr(index + 1);
            }
        }

        request.xhr = null;
        delete request.xhr;

        response = {
            request: request,
            requestId : request.id,
            status : xhr.status,
            statusText : xhr.statusText,
            getResponseHeader : function(header) {
                return headers[header.toLowerCase()];
            },
            getAllResponseHeaders : function() {
                return headers;
            },
            responseText : xhr.responseText,
            responseXML : xhr.responseXML
        };

        
        
        xhr = null;
        return response;
    },

    
    createException : function(request) {
        return {
            request : request,
            requestId : request.id,
            status : request.aborted ? -1 : 0,
            statusText : request.aborted ? 'transaction aborted' : 'communication failure',
            aborted: request.aborted,
            timedout: request.timedout
        };
    }
});


Ext.define('Ext.Ajax', {
    extend: 'Ext.data.Connection',
    singleton: true,

    
    
    
    
    
    

    
    
    
    
    
    

    
    autoAbort : false
});


Ext.define('Ext.data.Field', {
    requires: ['Ext.data.Types', 'Ext.data.SortTypes'],
    alias: 'data.field',

    isField: true,
    
    constructor : function(config) {
        var me = this,
            types = Ext.data.Types,
            st;
        
        if (Ext.isString(config)) {
            config = {name: config};
        }
        Ext.apply(me, config);

        st = me.sortType;

        if (me.type) {
            if (Ext.isString(me.type)) {
                me.type = types[me.type.toUpperCase()] || types.AUTO;
            }
        } else {
            me.type = types.AUTO;
        }

        
        if (Ext.isString(st)) {
            me.sortType = Ext.data.SortTypes[st];
        } else if(Ext.isEmpty(st)) {
            me.sortType = me.type.sortType;
        }

        
        if (!config.hasOwnProperty('convert')) {
            me.convert = me.type.convert; 
        } else if (!me.convert && me.type.convert && !config.hasOwnProperty('defaultValue')) {
            
            
            me.defaultValue = me.type.convert(me.defaultValue);
        }

        if (config.convert) {
            me.hasCustomConvert = true;
        }
    },
    
    
    
    

    

    

    
    dateFormat: null,
    
    
    useNull: false,
    
    
    defaultValue: "",

    
    mapping: null,

    
    sortType : null,

    
    sortDir : "ASC",

    
    allowBlank : true,

    
    persist: true
});


Ext.define('Ext.data.NodeInterface', {
    requires: ['Ext.data.Field'],

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    


    

    

    

    

    

    

    statics: {
        
        decorate: function(modelClass) {
            var idName, idType;
            
            
            if (typeof modelClass == 'string') {
                modelClass = Ext.ModelManager.getModel(modelClass);
            } else if (modelClass.isModel) {
                modelClass = Ext.ModelManager.getModel(modelClass.modelName);
            }
            
            
            if (modelClass.prototype.isNode) {
                return;
            }

            idName = modelClass.prototype.idProperty;
            idField = modelClass.prototype.fields.get(idName);
            idType = modelClass.prototype.fields.get(idName).type.type;
            modelClass.override(this.getPrototypeBody());
            this.applyFields(modelClass, [
                {name: 'parentId',   type: idType,    defaultValue: null, useNull: idField.useNull},
                {name: 'index',      type: 'int',     defaultValue: null, persist: false},
                {name: 'depth',      type: 'int',     defaultValue: 0, persist: false},
                {name: 'expanded',   type: 'bool',    defaultValue: false, persist: false},
                {name: 'expandable', type: 'bool',    defaultValue: true, persist: false},
                {name: 'checked',    type: 'auto',    defaultValue: null, persist: false},
                {name: 'leaf',       type: 'bool',    defaultValue: false},
                {name: 'cls',        type: 'string',  defaultValue: null, persist: false},
                {name: 'iconCls',    type: 'string',  defaultValue: null, persist: false},
                {name: 'icon',       type: 'string',  defaultValue: null, persist: false},
                {name: 'root',       type: 'boolean', defaultValue: false, persist: false},
                {name: 'isLast',     type: 'boolean', defaultValue: false, persist: false},
                {name: 'isFirst',    type: 'boolean', defaultValue: false, persist: false},
                {name: 'allowDrop',  type: 'boolean', defaultValue: true, persist: false},
                {name: 'allowDrag',  type: 'boolean', defaultValue: true, persist: false},
                {name: 'loaded',     type: 'boolean', defaultValue: false, persist: false},
                {name: 'loading',    type: 'boolean', defaultValue: false, persist: false},
                {name: 'href',       type: 'string',  defaultValue: null, persist: false},
                {name: 'hrefTarget', type: 'string',  defaultValue: null, persist: false},
                {name: 'qtip',       type: 'string',  defaultValue: null, persist: false},
                {name: 'qtitle',     type: 'string',  defaultValue: null, persist: false},
                {name: 'children',   type: 'auto',   defaultValue: null, persist: false}
            ]);
        },
        
        applyFields: function(modelClass, addFields) {
            var modelPrototype = modelClass.prototype,
                fields = modelPrototype.fields,
                keys = fields.keys,
                ln = addFields.length,
                addField, i;

            for (i = 0; i < ln; i++) {
                addField = addFields[i];
                if (!Ext.Array.contains(keys, addField.name)) {
                    fields.add(new Ext.data.Field(addField));
                }
            }

        },

        getPrototypeBody: function() {
            return {
                
                isNode: true,
                
                constructor: function() {
                    var me = this;
                    this.callParent(arguments);
                    Ext.applyIf(me, {
                        firstChild: null,
                        lastChild: null,
                        parentNode: null,
                        previousSibling: null,
                        nextSibling: null,
                        childNodes: []
                    });
                    me.enableBubble([
                        
                        "append",

                        
                        "remove",

                        
                        "move",

                        
                        "insert",

                        
                        "beforeappend",

                        
                        "beforeremove",

                        
                        "beforemove",

                         
                        "beforeinsert",

                        
                        "expand",

                        
                        "collapse",

                        
                        "beforeexpand",

                        
                        "beforecollapse",

                        
                        "sort"
                    ]);
                    return me;
                },
                
                createNode: function(node) {
                    if (Ext.isObject(node) && !node.isModel) {
                        node = Ext.ModelManager.create(node, this.modelName);
                    }
                    
                    
                    
                    if (!node.childNodes) {
                        Ext.applyIf(node, {
                            firstChild: null,
                            lastChild: null,
                            parentNode: null,
                            previousSibling: null,
                            nextSibling: null,
                            childNodes: []
                        });
                    }
                    return node;
                },

                
                isLeaf : function() {
                    return this.get('leaf') === true;
                },

                
                setFirstChild : function(node) {
                    this.firstChild = node;
                },

                
                setLastChild : function(node) {
                    this.lastChild = node;
                },

                
                updateInfo: function(commit) {
                    var me = this,
                        isRoot = me.isRoot(),
                        parentNode = me.parentNode,
                        isFirst = (!parentNode || isRoot ? true : parentNode.firstChild === me),
                        isLast = (!parentNode || isRoot ? true : parentNode.lastChild === me),
                        depth = 0,
                        parent = me,
                        children = me.childNodes,
                        len = children.length,
                        i = 0,
                        phantom = me.phantom;

                    while (parent.parentNode) {
                        ++depth;
                        parent = parent.parentNode;
                    }

                    me.beginEdit();
                    me.set({
                        isFirst: isFirst,
                        isLast: isLast,
                        depth: depth,
                        index: parentNode ? parentNode.indexOf(me) : 0,
                        parentId: parentNode ? parentNode.getId() : null
                    });
                    me.endEdit(true);
                    if (commit) {
                        me.commit();
                        me.phantom = phantom;
                    }

                    for (i = 0; i < len; i++) {
                        children[i].updateInfo(commit);
                    }
                },

                
                isLast : function() {
                   return this.get('isLast');
                },

                
                isFirst : function() {
                   return this.get('isFirst');
                },

                
                hasChildNodes : function() {
                    return !this.isLeaf() && this.childNodes.length > 0;
                },

                
                isExpandable : function() {
                    var me = this;

                    if (me.get('expandable')) {
                        return !(me.isLeaf() || (me.isLoaded() && !me.hasChildNodes()));
                    }
                    return false;
                },
                
                triggerUIUpdate: function(){
                    
                    
                    this.afterEdit([]);    
                },

                
                appendChild : function(node, suppressEvents, commit) {
                    var me = this,
                        i, ln,
                        index,
                        oldParent,
                        ps;

                    
                    if (Ext.isArray(node)) {
                        
                        me.callStore('suspendAutoSync');
                        for (i = 0, ln = node.length - 1; i < ln; i++) {
                            me.appendChild(node[i]);
                        }
                        
                        me.callStore('resumeAutoSync');
                        me.appendChild(node[ln]);
                    } else {
                        
                        node = me.createNode(node);

                        if (suppressEvents !== true && (!me.hasListeners.beforeappend || me.fireEvent("beforeappend", me, node) === false)) {
                            return false;
                        }

                        index = me.childNodes.length;
                        oldParent = node.parentNode;

                        
                        if (oldParent) {
                            if (suppressEvents !== true && (!me.hasListeners.beforeremove || node.fireEvent("beforemove", node, oldParent, me, index) === false)) {
                                return false;
                            }
                            oldParent.removeChild(node, false, false, true);
                        }

                        index = me.childNodes.length;
                        if (index === 0) {
                            me.setFirstChild(node);
                        }

                        me.childNodes.push(node);
                        node.parentNode = me;
                        node.nextSibling = null;

                        me.setLastChild(node);

                        ps = me.childNodes[index - 1];
                        if (ps) {
                            node.previousSibling = ps;
                            ps.nextSibling = node;
                            ps.updateInfo(commit);
                        } else {
                            node.previousSibling = null;
                        }

                        node.updateInfo(commit);

                        
                        if (!me.isLoaded()) {
                            me.set('loaded', true);
                        } else if (me.childNodes.length === 1) {
                            me.triggerUIUpdate();
                        }

                        if(!node.isLeaf() && node.phantom) {
                            node.set('loaded', true);
                        }

                        if (suppressEvents !== true) {
                            me.fireEvent("append", me, node, index);

                            if (oldParent) {
                                node.fireEvent("move", node, oldParent, me, index);
                            }
                        }

                        return node;
                    }
                },

                
                getBubbleTarget: function() {
                    return this.parentNode;
                },

                
                removeChild : function(node, destroy, suppressEvents, isMove) {
                    var me = this,
                        index = me.indexOf(node),
                        i, childCount;

                    if (index == -1 || (suppressEvents !== true && (!me.hasListeners.beforeremove || me.fireEvent("beforeremove", me, node, !!isMove) === false))) {
                        return false;
                    }

                    
                    Ext.Array.erase(me.childNodes, index, 1);

                    
                    if (me.firstChild == node) {
                        me.setFirstChild(node.nextSibling);
                    }
                    if (me.lastChild == node) {
                        me.setLastChild(node.previousSibling);
                    }

                    
                    if (node.previousSibling) {
                        node.previousSibling.nextSibling = node.nextSibling;
                    }
                    if (node.nextSibling) {
                        node.nextSibling.previousSibling = node.previousSibling;
                    }

                    
                    for(i = index > 0 ? index - 1 : 0, childCount = me.childNodes.length; i < childCount; i++) {
                        me.childNodes[i].updateInfo();
                    }

                    
                    if (!me.childNodes.length) {
                        me.triggerUIUpdate();
                    }

                    if (suppressEvents !== true) {
                        if (me.hasListeners.remove) {
                            me.fireEvent("remove", me, node, !!isMove);
                        }
                    }

                    if (destroy) {
                        node.destroy(true);
                    } else {
                        node.clear();
                    }

                    return node;
                },

                
                copy: function(newId, deep) {
                    var me = this,
                        result = me.callOverridden(arguments),
                        len = me.childNodes ? me.childNodes.length : 0,
                        i;

                    
                    if (deep) {
                        for (i = 0; i < len; i++) {
                            result.appendChild(me.childNodes[i].copy(true));
                        }
                    }
                    return result;
                },

                
                clear : function(destroy) {
                    var me = this;

                    
                    me.parentNode = me.previousSibling = me.nextSibling = null;
                    if (destroy) {
                        me.firstChild = me.lastChild = null;
                    }
                },

                
                destroy : function(silent) {
                    
                    var me      = this,
                        options = me.destroyOptions,
                        nodes   = me.childNodes,
                        nLen    = nodes.length,
                        n;

                    if (silent === true) {
                        me.clear(true);

                        for (n = 0; n < nLen; n++) {
                            nodes[n].destroy(true);
                        }

                        me.childNodes = null;
                        delete me.destroyOptions;
                        me.callOverridden([options]);
                    } else {
                        me.destroyOptions = silent;
                        
                        me.remove(true);
                    }
                },

                
                insertBefore : function(node, refNode, suppressEvents) {
                    var me = this,
                        index     = me.indexOf(refNode),
                        oldParent = node.parentNode,
                        refIndex  = index,
                        childCount, ps, i;

                    if (!refNode) { 
                        return me.appendChild(node);
                    }

                    
                    if (node == refNode) {
                        return false;
                    }

                    
                    node = me.createNode(node);

                    if (suppressEvents !== true && (!me.hasListeners.beforeinsert || me.fireEvent("beforeinsert", me, node, refNode) === false)) {
                        return false;
                    }

                    
                    if (oldParent == me && me.indexOf(node) < index) {
                        refIndex--;
                    }

                    
                    if (oldParent) {
                        if (suppressEvents !== true && (!me.hasListeners.beforeremove || node.fireEvent("beforemove", node, oldParent, me, index, refNode) === false)) {
                            return false;
                        }
                        oldParent.removeChild(node, false, false, true);
                    }

                    if (refIndex === 0) {
                        me.setFirstChild(node);
                    }

                    Ext.Array.splice(me.childNodes, refIndex, 0, node);
                    node.parentNode = me;

                    node.nextSibling = refNode;
                    refNode.previousSibling = node;

                    ps = me.childNodes[refIndex - 1];
                    if (ps) {
                        node.previousSibling = ps;
                        ps.nextSibling = node;
                    } else {
                        node.previousSibling = null;
                    }

                    
                    for(i = refIndex > 0 ? refIndex - 1 : 0, childCount = me.childNodes.length; i < childCount; i++) {
                        me.childNodes[i].updateInfo();
                    }

                    if (!me.isLoaded()) {
                        me.set('loaded', true);
                    }
                    
                    else if (me.childNodes.length === 1) {
                        me.triggerUIUpdate();
                    }

                    if(!node.isLeaf() && node.phantom) {
                        node.set('loaded', true);
                    }

                    if (suppressEvents !== true) {
                        if (me.hasListeners.insert) {
                            me.fireEvent("insert", me, node, refNode);
                        }

                        if (oldParent && me.hasListeners.move) {
                            node.fireEvent("move", node, oldParent, me, refIndex, refNode);
                        }
                    }

                    return node;
                },

                
                insertChild: function(index, node) {
                    var sibling = this.childNodes[index];
                    if (sibling) {
                        return this.insertBefore(node, sibling);
                    }
                    else {
                        return this.appendChild(node);
                    }
                },

                
                remove : function(destroy, suppressEvents) {
                    var parentNode = this.parentNode;

                    if (parentNode) {
                        parentNode.removeChild(this, destroy, suppressEvents);
                    }
                    return this;
                },

                
                removeAll : function(destroy, suppressEvents) {
                    var cn = this.childNodes,
                        n;

                    while ((n = cn[0])) {
                        this.removeChild(n, destroy, suppressEvents);
                    }
                    return this;
                },

                
                getChildAt : function(index) {
                    return this.childNodes[index];
                },

                
                replaceChild : function(newChild, oldChild, suppressEvents) {
                    var s = oldChild ? oldChild.nextSibling : null;

                    this.removeChild(oldChild, false, suppressEvents);
                    this.insertBefore(newChild, s, suppressEvents);
                    return oldChild;
                },

                
                indexOf : function(child) {
                    return Ext.Array.indexOf(this.childNodes, child);
                },
                
                
                indexOfId: function(id) {
                    var childNodes = this.childNodes,
                        len = childNodes.length,
                        i = 0;
                        
                    for (; i < len; ++i) {
                        if (childNodes[i].getId() === id) {
                            return i;
                        }    
                    }
                    return -1;
                },

                
                getPath: function(field, separator) {
                    field = field || this.idProperty;
                    separator = separator || '/';

                    var path = [this.get(field)],
                        parent = this.parentNode;

                    while (parent) {
                        path.unshift(parent.get(field));
                        parent = parent.parentNode;
                    }
                    return separator + path.join(separator);
                },

                
                getDepth : function() {
                    return this.get('depth');
                },

                
                bubble : function(fn, scope, args) {
                    var p = this;
                    while (p) {
                        if (fn.apply(scope || p, args || [p]) === false) {
                            break;
                        }
                        p = p.parentNode;
                    }
                },

                cascade: function() {
                    if (Ext.isDefined(Ext.global.console)) {
                        Ext.global.console.warn('Ext.data.Node: cascade has been deprecated. Please use cascadeBy instead.');
                    }
                    return this.cascadeBy.apply(this, arguments);
                },

                
                cascadeBy : function(fn, scope, args) {
                    if (fn.apply(scope || this, args || [this]) !== false) {
                        var childNodes = this.childNodes,
                            length     = childNodes.length,
                            i;

                        for (i = 0; i < length; i++) {
                            childNodes[i].cascadeBy(fn, scope, args);
                        }
                    }
                },

                
                eachChild : function(fn, scope, args) {
                    var childNodes = this.childNodes,
                        length     = childNodes.length,
                        i;

                    for (i = 0; i < length; i++) {
                        if (fn.apply(scope || this, args || [childNodes[i]]) === false) {
                            break;
                        }
                    }
                },

                
                findChild : function(attribute, value, deep) {
                    return this.findChildBy(function() {
                        return this.get(attribute) == value;
                    }, null, deep);
                },

                
                findChildBy : function(fn, scope, deep) {
                    var cs = this.childNodes,
                        len = cs.length,
                        i = 0, n, res;

                    for (; i < len; i++) {
                        n = cs[i];
                        if (fn.call(scope || n, n) === true) {
                            return n;
                        }
                        else if (deep) {
                            res = n.findChildBy(fn, scope, deep);
                            if (res !== null) {
                                return res;
                            }
                        }
                    }

                    return null;
                },

                
                contains : function(node) {
                    return node.isAncestor(this);
                },

                
                isAncestor : function(node) {
                    var p = this.parentNode;
                    while (p) {
                        if (p == node) {
                            return true;
                        }
                        p = p.parentNode;
                    }
                    return false;
                },

                
                sort : function(sortFn, recursive, suppressEvent) {
                    var cs  = this.childNodes,
                        ln = cs.length,
                        i, n;

                    if (ln > 0) {
                        Ext.Array.sort(cs, sortFn);
                        for (i = 0; i < ln; i++) {
                            n = cs[i];
                            n.previousSibling = cs[i-1];
                            n.nextSibling = cs[i+1];

                            if (i === 0) {
                                this.setFirstChild(n);
                            }
                            if (i == ln - 1) {
                                this.setLastChild(n);
                            }
                            n.updateInfo();
                            if (recursive && !n.isLeaf()) {
                                n.sort(sortFn, true, true);
                            }
                        }

                        if (suppressEvent !== true) {
                            this.fireEvent('sort', this, cs);
                        }
                    }
                },

                
                isExpanded: function() {
                    return this.get('expanded');
                },

                
                isLoaded: function() {
                    return this.get('loaded');
                },

                
                isLoading: function() {
                    return this.get('loading');
                },

                
                isRoot: function() {
                    return !this.parentNode;
                },

                
                isVisible: function() {
                    var parent = this.parentNode;
                    while (parent) {
                        if (!parent.isExpanded()) {
                            return false;
                        }
                        parent = parent.parentNode;
                    }
                    return true;
                },

                
                expand: function(recursive, callback, scope) {
                    var me = this;

                    
                    

                    
                    if (!me.isLeaf()) {
                        
                        if (me.isLoading()) {
                            me.on('expand', function(){
                                me.expand(recursive, callback, scope);
                            }, me, {single: true});
                        } else {
                            
                            if (!me.isExpanded()) {
                                
                                
                                
                                
                                me.fireEvent('beforeexpand', me, function() {
                                    me.set('expanded', true);
                                    if (me.hasListeners.expand) {
                                        me.fireEvent('expand', me, me.childNodes, false);
                                    }

                                    
                                    if (recursive) {
                                        me.expandChildren(true, callback, scope);
                                    } else {
                                        Ext.callback(callback, scope || me, [me.childNodes]);
                                    }
                                }, me);
                            } else if (recursive) {
                                
                                me.expandChildren(true, callback, scope);
                            } else {
                                Ext.callback(callback, scope || me, [me.childNodes]);
                            }
                        }
                    } else {
                        
                        Ext.callback(callback, scope || me); 
                    }
                },

                
                expandChildren: function(recursive, callback, scope) {
                    var me = this,
                        i = 0,
                        nodes = me.childNodes,
                        ln = nodes.length,
                        node,
                        expanding = 0;

                    for (; i < ln; ++i) {
                        node = nodes[i];
                        if (!node.isLeaf()) {
                            expanding++;
                            nodes[i].expand(recursive, function () {
                                expanding--;
                                if (callback && !expanding) {
                                    Ext.callback(callback, scope || me, [me.childNodes]);
                                }
                            });
                        }
                    }

                    if (!expanding && callback) {
                        Ext.callback(callback, scope || me, [me.childNodes]);                    }
                },

                
                collapse: function(recursive, callback, scope) {
                    var me = this;

                    
                    if (!me.isLeaf()) {
                        
                        if (!me.collapsing && me.isExpanded()) {
                            me.fireEvent('beforecollapse', me, function() {
                                me.set('expanded', false);
                                if (me.hasListeners.collapse) {
                                    me.fireEvent('collapse', me, me.childNodes, false);
                                }

                                
                                if (recursive) {
                                    me.collapseChildren(true, callback, scope);
                                }
                                else {
                                    Ext.callback(callback, scope || me, [me.childNodes]);
                                }
                            }, me);
                        }
                        
                        else if (recursive) {
                            me.collapseChildren(true, callback, scope);
                        } else {
                            Ext.callback(callback, scope || me, [me.childNodes]);
                        }
                    }
                    
                    else {
                        Ext.callback(callback, scope || me, [me.childNodes]);
                    }
                },

                
                collapseChildren: function(recursive, callback, scope) {
                    var me = this,
                        i = 0,
                        nodes = me.childNodes,
                        ln = nodes.length,
                        node,
                        collapsing = 0;

                    for (; i < ln; ++i) {
                        node = nodes[i];
                        if (!node.isLeaf()) {
                            collapsing++;
                            nodes[i].collapse(recursive, function () {
                                collapsing--;
                                if (callback && !collapsing) {
                                    Ext.callback(callback, scope || me, [me.childNodes]);
                                }
                            });
                        }
                    }

                    if (!collapsing && callback) {
                        Ext.callback(callback, scope || me, [me.childNodes]);
                    }
                }
            };
        }
    }
});


Ext.define('Ext.data.Tree', {
    alias: 'data.tree',

    mixins: {
        observable: "Ext.util.Observable"
    },

    
    root: null,

    
    constructor: function(root) {
        var me = this;

        me.mixins.observable.constructor.call(me);

        if (root) {
            me.setRootNode(root);
        }
    },

    
    getRootNode : function() {
        return this.root;
    },

    
    setRootNode : function(node) {
        var me = this;

        me.root = node;

        if (me.fireEvent('beforeappend', null, node) !== false) {
            node.set('root', true);
            node.updateInfo();
            
            node.commit();

            node.on({
                scope: me,
                insert: me.onNodeInsert,
                append: me.onNodeAppend,
                remove: me.onNodeRemove
            });

            me.relayEvents(node, [
                
                "append",

                
                "remove",

                
                "move",

                
                "insert",

                
                "beforeappend",

                
                "beforeremove",

                
                "beforemove",

                
                "beforeinsert",

                
                "expand",

                
                "collapse",

                
                "beforeexpand",

                
                "beforecollapse" ,

                
                "sort",

                
                "rootchange"
            ]);

            me.nodeHash = {};
            me.registerNode(node);
            me.fireEvent('append', null, node);
            me.fireEvent('rootchange', node);
        }

        return node;
    },

    
    flatten: function(){
        return Ext.Object.getValues(this.nodeHash);
    },

    
    onNodeInsert: function(parent, node) {
        this.registerNode(node, true);
    },

    
    onNodeAppend: function(parent, node) {
        this.registerNode(node, true);
    },

    
    onNodeRemove: function(parent, node) {
        this.unregisterNode(node, true);
    },

    
    onNodeIdChanged: function(node, oldId, newId) {
        var nodeHash = this.nodeHash;
    
        nodeHash[newId] = node;
        delete nodeHash[oldId || node.internalId];
    },

    
    getNodeById : function(id) {
        return this.nodeHash[id];
    },

    
    registerNode : function(node, includeChildren) {
        var me = this;

        me.nodeHash[node.getId() || node.internalId] = node;
        node.on('idchanged', me.onNodeIdChanged, me);
        if (includeChildren === true) {
            node.eachChild(function(child){
                me.registerNode(child, true);
            });
        }
    },

    
    unregisterNode : function(node, includeChildren) {
        delete this.nodeHash[node.getId() || node.internalId];
        if (includeChildren === true) {
            node.eachChild(function(child){
                this.unregisterNode(child, true);
            }, this);
        }
    },

    
    sort: function(sorterFn, recursive) {
        this.getRootNode().sort(sorterFn, recursive);
    },

     
    filter: function(filters, recursive) {
        this.getRootNode().filter(filters, recursive);
    }
});

Ext.define('Ext.data.association.HasMany', {
    extend: 'Ext.data.association.Association',
    alternateClassName: 'Ext.data.HasManyAssociation',
    requires: ['Ext.util.Inflector'],

    alias: 'association.hasmany',

    
    
    
    
    
    
    
    
    
    
    
    
    constructor: function(config) {
        var me = this,
            ownerProto,
            name;
            
        me.callParent(arguments);
        
        me.name = me.name || Ext.util.Inflector.pluralize(me.associatedName.toLowerCase());
        
        ownerProto = me.ownerModel.prototype;
        name = me.name;
        
        Ext.applyIf(me, {
            storeName : name + "Store",
            foreignKey: me.ownerName.toLowerCase() + "_id"
        });
        
        ownerProto[name] = me.createStore();
    },
    
    
    createStore: function() {
        var that            = this,
            associatedModel = that.associatedModel,
            storeName       = that.storeName,
            foreignKey      = that.foreignKey,
            primaryKey      = that.primaryKey,
            filterProperty  = that.filterProperty,
            autoLoad        = that.autoLoad,
            storeConfig     = that.storeConfig || {};
        
        return function() {
            var me = this,
                config, filter,
                modelDefaults = {};
                
            if (me[storeName] === undefined) {
                if (filterProperty) {
                    filter = {
                        property  : filterProperty,
                        value     : me.get(filterProperty),
                        exactMatch: true
                    };
                } else {
                    filter = {
                        property  : foreignKey,
                        value     : me.get(primaryKey),
                        exactMatch: true
                    };
                }
                
                modelDefaults[foreignKey] = me.get(primaryKey);
                
                config = Ext.apply({}, storeConfig, {
                    model        : associatedModel,
                    filters      : [filter],
                    remoteFilter : false,
                    modelDefaults: modelDefaults
                });
                
                me[storeName] = Ext.data.AbstractStore.create(config);
                if (autoLoad) {
                    me[storeName].load();
                }
            }
            
            return me[storeName];
        };
    },
    
    
    read: function(record, reader, associationData){
        var store = record[this.name](),
            inverse,
            items, iLen, i;
    
        store.add(reader.read(associationData).records);
    
        
        
        inverse = this.associatedModel.prototype.associations.findBy(function(assoc){
            return assoc.type === 'belongsTo' && assoc.associatedName === record.$className;
        });
    
        
        if (inverse) {
            items = store.data.items;
            iLen  = items.length;

            for (i = 0; i < iLen; i++) {
                items[i][inverse.instanceName] = record;
            }
        }
    }
});

Ext.define('Ext.data.proxy.Proxy', {
    alias: 'proxy.proxy',
    alternateClassName: ['Ext.data.DataProxy', 'Ext.data.Proxy'],

    uses: [
        'Ext.data.Batch',
        'Ext.data.Operation',
        'Ext.data.Model'
    ],

    mixins: {
        observable: 'Ext.util.Observable'
    },

    
    batchOrder: 'create,update,destroy',

    
    batchActions: true,

    
    defaultReaderType: 'json',

    
    defaultWriterType: 'json',

    

    

    

    
    isProxy: true,

    
    constructor: function(config) {
        config = config || {};

        if (config.model === undefined) {
            delete config.model;
        }

        this.mixins.observable.constructor.call(this, config);

        if (this.model !== undefined && !(this.model instanceof Ext.data.Model)) {
            this.setModel(this.model);
        }

        
    },

    
    setModel: function(model, setOnStore) {
        this.model = Ext.ModelManager.getModel(model);

        var reader = this.reader,
            writer = this.writer;

        this.setReader(reader);
        this.setWriter(writer);

        if (setOnStore && this.store) {
            this.store.setModel(this.model);
        }
    },

    
    getModel: function() {
        return this.model;
    },

    
    setReader: function(reader) {
        var me = this,
            needsCopy = true;

        if (reader === undefined || typeof reader == 'string') {
            reader = {
                type: reader
            };
            needsCopy = false;
        }

        if (reader.isReader) {
            reader.setModel(me.model);
        } else {
            if (needsCopy) {
                reader = Ext.apply({}, reader);
            }
            Ext.applyIf(reader, {
                proxy: me,
                model: me.model,
                type : me.defaultReaderType
            });

            reader = Ext.createByAlias('reader.' + reader.type, reader);
        }

        if (reader.onMetaChange) {
            reader.onMetaChange = Ext.Function.createSequence(reader.onMetaChange, this.onMetaChange, this);
        }

        me.reader = reader;
        return me.reader;
    },

    
    getReader: function() {
        return this.reader;
    },

    
    onMetaChange: function(meta) {
        this.fireEvent('metachange', this, meta);
    },

    
    setWriter: function(writer) {
        var me = this,
            needsCopy = true;
            
        if (writer === undefined || typeof writer == 'string') {
            writer = {
                type: writer
            };
            needsCopy = false;
        }

        if (!writer.isWriter) {
            if (needsCopy) {
                writer = Ext.apply({}, writer);
            }
            Ext.applyIf(writer, {
                model: me.model,
                type : me.defaultWriterType
            });

            writer = Ext.createByAlias('writer.' + writer.type, writer);
        }

        me.writer = writer;

        return me.writer;
    },

    
    getWriter: function() {
        return this.writer;
    },

    
    create: Ext.emptyFn,

    
    read: Ext.emptyFn,

    
    update: Ext.emptyFn,

    
    destroy: Ext.emptyFn,

    
    batch: function(options, listeners) {
        var me = this,
            useBatch = me.batchActions,
            batch,
            records,
            actions, aLen, action, a, r, rLen, record;

        if (options.operations === undefined) {
            
            
            options = {
                operations: options,
                listeners: listeners
            };
        }

        if (options.batch) {
            if (Ext.isDefined(options.batch.runOperation)) {
                batch = Ext.applyIf(options.batch, {
                    proxy: me,
                    listeners: {}
                });
            }
        } else {
            options.batch = {
                proxy: me,
                listeners: options.listeners || {}
            };
        }

        if (!batch) {
            batch = new Ext.data.Batch(options.batch);
        }

        batch.on('complete', Ext.bind(me.onBatchComplete, me, [options], 0));

        actions = me.batchOrder.split(',');
        aLen    = actions.length;

        for (a = 0; a < aLen; a++) {
            action  = actions[a];
            records = options.operations[action];

            if (records) {
                if (useBatch) {
                    batch.add(new Ext.data.Operation({
                        action  : action,
                        records : records
                    }));
                } else {
                    rLen = records.length;

                    for (r = 0; r < rLen; r++) {
                        record = records[r];

                        batch.add(new Ext.data.Operation({
                            action  : action,
                            records : [record]
                        }));
                    }
                }
            }
        }

        batch.start();
        return batch;
    },

    
    onBatchComplete: function(batchOptions, batch) {
        var scope = batchOptions.scope || this;

        if (batch.hasException) {
            if (Ext.isFunction(batchOptions.failure)) {
                Ext.callback(batchOptions.failure, scope, [batch, batchOptions]);
            }
        } else if (Ext.isFunction(batchOptions.success)) {
            Ext.callback(batchOptions.success, scope, [batch, batchOptions]);
        }

        if (Ext.isFunction(batchOptions.callback)) {
            Ext.callback(batchOptions.callback, scope, [batch, batchOptions]);
        }
    }
}, function() {
    
    Ext.data.DataProxy = this;
});


Ext.define('Ext.data.proxy.Client', {
    extend: 'Ext.data.proxy.Proxy',
    alternateClassName: 'Ext.data.ClientProxy',
    
    
    isSynchronous: true,

    
    clear: function() {
    }
});

Ext.define('Ext.data.proxy.Memory', {
    extend: 'Ext.data.proxy.Client',
    alias: 'proxy.memory',
    alternateClassName: 'Ext.data.MemoryProxy',

    

    constructor: function(config) {
        this.callParent([config]);

        
        this.setReader(this.reader);
    },
    
    
    updateOperation: function(operation, callback, scope) {
        var i = 0,
            recs = operation.getRecords(),
            len = recs.length;
            
        for (i; i < len; i++) {
            recs[i].commit();
        }
        operation.setCompleted();
        operation.setSuccessful();
        
        Ext.callback(callback, scope || this, [operation]);
    },
    
    
    create: function() {
        this.updateOperation.apply(this, arguments);
    },
    
    
    update: function() {
        this.updateOperation.apply(this, arguments);
    },
    
    
    destroy: function() {
        this.updateOperation.apply(this, arguments);
    },

    
    read: function(operation, callback, scope) {
        var me = this;

        operation.resultSet = me.getReader().read(me.data);

        operation.setCompleted();
        operation.setSuccessful();
        Ext.callback(callback, scope || me, [operation]);
    },

    clear: Ext.emptyFn
});


Ext.define('Ext.data.proxy.Server', {
    extend: 'Ext.data.proxy.Proxy',
    alias : 'proxy.server',
    alternateClassName: 'Ext.data.ServerProxy',
    uses  : ['Ext.data.Request'],

    

    
    pageParam: 'page',

    
    startParam: 'start',

    
    limitParam: 'limit',

    
    groupParam: 'group',

    
    groupDirectionParam: 'groupDir',

    
    sortParam: 'sort',

    
    filterParam: 'filter',

    
    directionParam: 'dir',

    
    simpleSortMode: false,

    
    simpleGroupMode: false,

    
    noCache : true,

    
    cacheString: "_dc",

    
    timeout : 30000,

    

    constructor: function(config) {
        var me = this;

        config = config || {};
        
        me.callParent([config]);

        
        me.extraParams = config.extraParams || {};

        me.api = Ext.apply({}, config.api || me.api);
        

        
        me.nocache = me.noCache;
    },

    
    create: function() {
        return this.doRequest.apply(this, arguments);
    },

    read: function() {
        return this.doRequest.apply(this, arguments);
    },

    update: function() {
        return this.doRequest.apply(this, arguments);
    },

    destroy: function() {
        return this.doRequest.apply(this, arguments);
    },

    
    setExtraParam: function(name, value) {
        this.extraParams[name] = value;
    },

    
    buildRequest: function(operation) {
        var me = this,
            params = Ext.applyIf(operation.params || {}, me.extraParams || {}),
            request;

        
        params = Ext.applyIf(params, me.getParams(operation));

        if (operation.id !== undefined && params.id === undefined) {
            params.id = operation.id;
        }

        request = new Ext.data.Request({
            params   : params,
            action   : operation.action,
            records  : operation.records,
            operation: operation,
            url      : operation.url,

            
            
            proxy: me
        });

        request.url = me.buildUrl(request);

        
        operation.request = request;

        return request;
    },

    
    processResponse: function(success, operation, request, response, callback, scope) {
        var me = this,
            reader,
            result;

        if (success === true) {
            reader = me.getReader();

            
            
            
            reader.applyDefaults = operation.action === 'read';

            result = reader.read(me.extractResponseData(response));

            if (result.success !== false) {
                
                Ext.apply(operation, {
                    response: response,
                    resultSet: result
                });

                operation.commitRecords(result.records);
                operation.setCompleted();
                operation.setSuccessful();
            } else {
                operation.setException(result.message);
                me.fireEvent('exception', this, response, operation);
            }
        } else {
            me.setException(operation, response);
            me.fireEvent('exception', this, response, operation);
        }

        
        if (typeof callback == 'function') {
            callback.call(scope || me, operation);
        }

        me.afterRequest(request, success);
    },

    
    setException: function(operation, response) {
        operation.setException({
            status: response.status,
            statusText: response.statusText
        });
    },

    
    extractResponseData: function(response) {
        return response;
    },

    
    applyEncoding: function(value) {
        return Ext.encode(value);
    },

    
    encodeSorters: function(sorters) {
        var min = [],
            length = sorters.length,
            i = 0;

        for (; i < length; i++) {
            min[i] = {
                property : sorters[i].property,
                direction: sorters[i].direction
            };
        }
        return this.applyEncoding(min);

    },

    
    encodeFilters: function(filters) {
        var min = [],
            length = filters.length,
            i = 0;

        for (; i < length; i++) {
            min[i] = {
                property: filters[i].property,
                value   : filters[i].value
            };
        }
        return this.applyEncoding(min);
    },

    
    getParams: function(operation) {
        var me = this,
            params = {},
            isDef = Ext.isDefined,
            groupers = operation.groupers,
            sorters = operation.sorters,
            filters = operation.filters,
            page = operation.page,
            start = operation.start,
            limit = operation.limit,
            simpleSortMode = me.simpleSortMode,
            simpleGroupMode = me.simpleGroupMode,
            pageParam = me.pageParam,
            startParam = me.startParam,
            limitParam = me.limitParam,
            groupParam = me.groupParam,
            groupDirectionParam = me.groupDirectionParam,
            sortParam = me.sortParam,
            filterParam = me.filterParam,
            directionParam = me.directionParam;

        if (pageParam && isDef(page)) {
            params[pageParam] = page;
        }

        if (startParam && isDef(start)) {
            params[startParam] = start;
        }

        if (limitParam && isDef(limit)) {
            params[limitParam] = limit;
        }

        if (groupParam && groupers && groupers.length > 0) {
            
            if (simpleGroupMode) {
                params[groupParam] = groupers[0].property;
                params[groupDirectionParam] = groupers[0].direction || 'ASC';
            } else {
                params[groupParam] = me.encodeSorters(groupers);
            }
        }

        if (sortParam && sorters && sorters.length > 0) {
            if (simpleSortMode) {
                params[sortParam] = sorters[0].property;
                params[directionParam] = sorters[0].direction;
            } else {
                params[sortParam] = me.encodeSorters(sorters);
            }

        }

        if (filterParam && filters && filters.length > 0) {
            params[filterParam] = me.encodeFilters(filters);
        }

        return params;
    },

    
    buildUrl: function(request) {
        var me = this,
            url = me.getUrl(request);


        if (me.noCache) {
            url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.cacheString, Ext.Date.now()));
        }

        return url;
    },

    
    getUrl: function(request) {
        return request.url || this.api[request.action] || this.url;
    },

    
    doRequest: function(operation, callback, scope) {
    },

    
    afterRequest: Ext.emptyFn,

    onDestroy: function() {
        Ext.destroy(this.reader, this.writer);
    }
});


Ext.define('Ext.data.proxy.JsonP', {
    extend: 'Ext.data.proxy.Server',
    alternateClassName: 'Ext.data.ScriptTagProxy',
    alias: ['proxy.jsonp', 'proxy.scripttag'],
    requires: ['Ext.data.JsonP'],

    defaultWriterType: 'base',

    
    callbackKey : 'callback',

    
    recordParam: 'records',

    
    autoAppendParams: true,

    constructor: function(){
        this.addEvents(
            
            'exception'
        );
        this.callParent(arguments);
    },

    
    doRequest: function(operation, callback, scope) {
        
        var me      = this,
            writer  = me.getWriter(),
            request = me.buildRequest(operation),
            params = request.params;

        if (operation.allowWrite()) {
            request = writer.write(request);
        }

        
        Ext.apply(request, {
            callbackKey: me.callbackKey,
            timeout: me.timeout,
            scope: me,
            disableCaching: false, 
            callback: me.createRequestCallback(request, operation, callback, scope)
        });

        
        if (me.autoAppendParams) {
            request.params = {};
        }

        request.jsonp = Ext.data.JsonP.request(request);
        
        request.params = params;
        operation.setStarted();
        me.lastRequest = request;

        return request;
    },

    
    createRequestCallback: function(request, operation, callback, scope) {
        var me = this;

        return function(success, response, errorType) {
            delete me.lastRequest;
            me.processResponse(success, operation, request, response, callback, scope);
        };
    },

    
    setException: function(operation, response) {
        operation.setException(operation.request.jsonp.errorType);
    },


    
    buildUrl: function(request) {
        var me      = this,
            url     = me.callParent(arguments),
            params  = Ext.apply({}, request.params),
            filters = params.filters,
            records,
            filter, i;

        delete params.filters;

        if (me.autoAppendParams) {
            url = Ext.urlAppend(url, Ext.Object.toQueryString(params));
        }

        if (filters && filters.length) {
            for (i = 0; i < filters.length; i++) {
                filter = filters[i];

                if (filter.value) {
                    url = Ext.urlAppend(url, filter.property + "=" + filter.value);
                }
            }
        }

        
        records = request.records;

        if (Ext.isArray(records) && records.length > 0) {
            url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.recordParam, me.encodeRecords(records)));
        }

        return url;
    },

    
    destroy: function() {
        this.abort();
        this.callParent(arguments);
    },

    
    abort: function() {
        var lastRequest = this.lastRequest;
        if (lastRequest) {
            Ext.data.JsonP.abort(lastRequest.jsonp);
        }
    },

    
    encodeRecords: function(records) {
        var encoded = "",
            i = 0,
            len = records.length;

        for (; i < len; i++) {
            encoded += Ext.Object.toQueryString(records[i].getData());
        }

        return encoded;
    }
});


Ext.define('Ext.data.proxy.WebStorage', {
    extend: 'Ext.data.proxy.Client',
    alternateClassName: 'Ext.data.WebStorageProxy',
    requires: [
        'Ext.data.SequentialIdGenerator'
    ],

    
    id: undefined,

    
    constructor: function(config) {
        this.callParent(arguments);

        
        this.cache = {};


        
        this.id = this.id || (this.store ? this.store.storeId : undefined);


        this.initialize();
    },

    
    create: function(operation, callback, scope) {
        var me = this,
            records = operation.records,
            length = records.length,
            ids = me.getIds(),
            id, record, i;

        operation.setStarted();

        if(me.isHierarchical === undefined) {
            
            
            me.isHierarchical = !!records[0].isNode;
            if(me.isHierarchical) {
                me.getStorageObject().setItem(me.getTreeKey(), true);
            }
        }

        for (i = 0; i < length; i++) {
            record = records[i];

            if (record.phantom) {
                record.phantom = false;
                id = me.getNextId();
            } else {
                id = record.getId();
            }

            me.setRecord(record, id);
            record.commit();
            ids.push(id);
        }

        me.setIds(ids);

        operation.setCompleted();
        operation.setSuccessful();

        if (typeof callback == 'function') {
            callback.call(scope || me, operation);
        }
    },

    
    read: function(operation, callback, scope) {
        

        var me = this,
            records = [],
            i = 0,
            success = true,
            Model = me.model,
            ids, length, record, data, id;

        operation.setStarted();

        if(me.isHierarchical) {
            records = me.getTreeData();
        } else {
            ids = me.getIds();
            length = ids.length;
            id = operation.id;
            
            if (id) {
                data = me.getRecord(id);
                if (data !== null) {
                    record = new Model(data, id, data);
                }

                if (record) {
                    records.push(record);
                } else {
                    success = false;
                }
            } else {
                for (; i < length; i++) {
                    id = ids[i];
                    data = me.getRecord(id);
                    records.push(new Model(data, id, data));
                }
            }

        }

        if(success) {
            operation.setSuccessful();
        }
        operation.setCompleted();

        operation.resultSet = Ext.create('Ext.data.ResultSet', {
            records: records,
            total  : records.length,
            loaded : true
        });

        if (typeof callback == 'function') {
            callback.call(scope || me, operation);
        }
    },

    
    update: function(operation, callback, scope) {
        var records = operation.records,
            length  = records.length,
            ids     = this.getIds(),
            record, id, i;

        operation.setStarted();

        for (i = 0; i < length; i++) {
            record = records[i];
            this.setRecord(record);
            record.commit();

            
            
            id = record.getId();
            if (id !== undefined && Ext.Array.indexOf(ids, id) == -1) {
                ids.push(id);
            }
        }
        this.setIds(ids);

        operation.setCompleted();
        operation.setSuccessful();

        if (typeof callback == 'function') {
            callback.call(scope || this, operation);
        }
    },

    
    destroy: function(operation, callback, scope) {
        var me = this,
            records = operation.records,
            ids = me.getIds(),
            idLength = ids.length,
            newIds = [],
            removedHash = {},
            i = records.length,
            id;

        operation.setStarted();

        for (; i--;) {
            Ext.apply(removedHash, me.removeRecord(records[i]));
        }

        for(i = 0; i < idLength; i++) {
            id = ids[i];
            if(!removedHash[id]) {
                newIds.push(id);
            }
        }

        me.setIds(newIds);

        operation.setCompleted();
        operation.setSuccessful();

        if (typeof callback == 'function') {
            callback.call(scope || me, operation);
        }
    },

    
    getRecord: function(id) {
        var me = this,
            cache = me.cache,
            data = !cache[id] ? Ext.decode(me.getStorageObject().getItem(me.getRecordKey(id))) : cache[id];

        if(!data) {
            return null;
        }

        cache[id] = data;
        data[me.model.prototype.idProperty] = id;

        return data;
    },

    
    setRecord: function(record, id) {
        if (id) {
            record.setId(id);
        } else {
            id = record.getId();
        }

        var me = this,
            rawData = record.data,
            data    = {},
            model   = me.model,
            fields  = model.prototype.fields.items,
            length  = fields.length,
            i = 0,
            field, name, obj, key;

        for (; i < length; i++) {
            field = fields[i];
            name  = field.name;

            if(field.persist) {
                data[name] = rawData[name];
            }
        }

        
        delete data[me.model.prototype.idProperty];

        
        if(record.isNode && record.get('depth') === 1) {
            delete data.parentId;
        }

        obj = me.getStorageObject();
        key = me.getRecordKey(id);

        
        me.cache[id] = data;

        
        obj.removeItem(key);
        obj.setItem(key, Ext.encode(data));
    },

    
    removeRecord: function(record) {
        var me = this,
            id = record.getId(),
            records = {},
            i, childNodes;

        records[id] = record;
        me.getStorageObject().removeItem(me.getRecordKey(id));
        delete me.cache[id];

        if(record.childNodes) {
            childNodes = record.childNodes;
            for(i = childNodes.length; i--;) {
                Ext.apply(records, me.removeRecord(childNodes[i]));
            }
        }

        return records;
    },

    
    getRecordKey: function(id) {
        if (id.isModel) {
            id = id.getId();
        }

        return Ext.String.format("{0}-{1}", this.id, id);
    },

    
    getRecordCounterKey: function() {
        return Ext.String.format("{0}-counter", this.id);
    },

    
    getTreeKey: function() {
        return Ext.String.format("{0}-tree", this.id);
    },

    
    getIds: function() {
        var me = this,
            ids = (me.getStorageObject().getItem(me.id) || "").split(","),
            model = me.model,
            length = ids.length,
            isString = model.prototype.fields.get(model.prototype.idProperty).type.type === 'string',
            i;

        if (length == 1 && ids[0] === "") {
            ids = [];
        } else {
            for (i = 0; i < length; i++) {
                ids[i] = isString ? ids[i] : +ids[i];
            }
        }

        return ids;
    },

    
    setIds: function(ids) {
        var obj = this.getStorageObject(),
            str = ids.join(",");

        obj.removeItem(this.id);

        if (!Ext.isEmpty(str)) {
            obj.setItem(this.id, str);
        }
    },

    
    getNextId: function() {
        var me = this,
            obj = me.getStorageObject(),
            key = me.getRecordCounterKey(),
            model = me.model,
            isString = model.prototype.fields.get(model.prototype.idProperty).type.type === 'string',
            id;

        id = me.idGenerator.generate();

        obj.setItem(key, id);

        if(!isString) {
            id = +id;
        }

        return id;
    },

    
    getTreeData: function() {
        var me = this,
            ids = me.getIds(),
            length = ids.length,
            records = [],
            recordHash = {},
            root = [],
            i = 0,
            Model = me.model,
            idProperty = Model.prototype.idProperty,
            rootLength, record, parent, parentId, children, id;

        for(; i < length; i++) {
            id = ids[i];
            
            record = me.getRecord(id);
            
            records.push(record);
            
            recordHash[id] = record;
            if(!record.parentId) {
                
                root.push(record);
            }
        }

        rootLength = root.length;

        
        Ext.Array.sort(records, me.sortByParentId);

        
        for(i = rootLength; i < length; i++) {
            record = records[i];
            parentId = record.parentId;
            if(!parent || parent[idProperty] !== parentId) {
                
                parent = recordHash[parentId];
                parent.children = children = [];
            }

            
            children.push(record);
        }

        for(i = length; i--;) {
            record = records[i];
            if(!record.children && !record.leaf) {
                
                record.loaded = true;
            }
        }

        
        for(i = rootLength; i--;) {
            record = root[i];
            root[i] = new Model(record, record[idProperty], record);
        }

        return root;
    },

    
    sortByParentId: function(node1, node2) {
        return (node1.parentId || 0) - (node2.parentId || 0);
    },

    
    initialize: function() {
        var me = this,
            storageObject = me.getStorageObject(),
            lastId = +storageObject.getItem(me.getRecordCounterKey());

        storageObject.setItem(me.id, storageObject.getItem(me.id) || "");
        if(storageObject.getItem(me.getTreeKey())) {
            me.isHierarchical = true;
        }

        me.idGenerator = new Ext.data.SequentialIdGenerator({
            seed: lastId ? lastId + 1 : 1
        });
    },

    
    clear: function() {
        var me = this,
            obj = me.getStorageObject(),
            ids = me.getIds(),
            len = ids.length,
            i;

        
        for (i = 0; i < len; i++) {
            obj.removeItem(me.getRecordKey(ids[i]));
        }

        
        obj.removeItem(me.getRecordCounterKey());
        obj.removeItem(me.getTreeKey());
        obj.removeItem(me.id);

        
        me.cache = {};
    },

    
    getStorageObject: function() {
    }
});

Ext.define('Ext.data.proxy.LocalStorage', {
    extend: 'Ext.data.proxy.WebStorage',
    alias: 'proxy.localstorage',
    alternateClassName: 'Ext.data.LocalStorageProxy',
    
    
    getStorageObject: function() {
        return window.localStorage;
    }
});

Ext.define('Ext.data.proxy.SessionStorage', {
    extend: 'Ext.data.proxy.WebStorage',
    alias: 'proxy.sessionstorage',
    alternateClassName: 'Ext.data.SessionStorageProxy',
    
    
    getStorageObject: function() {
        return window.sessionStorage;
    }
});


Ext.define('Ext.data.reader.Reader', {
    requires: ['Ext.data.ResultSet', 'Ext.XTemplate'],
    alternateClassName: ['Ext.data.Reader', 'Ext.data.DataReader'],

    mixins: {
        observable: 'Ext.util.Observable'
    },

    

    
    totalProperty: 'total',

    
    successProperty: 'success',

    
    root: '',
    
    
    
    
    implicitIncludes: true,
    
    
    readRecordsOnFailure: true,
    
    
    
    
    isReader: true,

    
    
    
    applyDefaults: true,

    lastFieldGeneration: null,
    
    
    constructor: function(config) {
        var me = this;
        
        me.mixins.observable.constructor.call(me, config);
        me.fieldCount = 0;
        me.model = Ext.ModelManager.getModel(me.model);
        me.accessExpressionFn = Ext.Function.bind(me.createFieldAccessExpression, me);

        
        
        
        
        
        if (me.model && me.model.prototype.fields) {
            me.buildExtractors();
        }

        this.addEvents(
            
            'exception'
        );
    },

    
    setModel: function(model, setOnProxy) {
        var me = this;
        
        me.model = Ext.ModelManager.getModel(model);
        me.buildExtractors(true);
        
        if (setOnProxy && me.proxy) {
            me.proxy.setModel(me.model, true);
        }
    },

    
    read: function(response) {
        var data;

        if (response) {
            data = response.responseText ? this.getResponseData(response) : this.readRecords(response);
        }

        return data || this.nullResultSet;
    },

    
    readRecords: function(data) {
        var me = this,
            success,
            recordCount,
            records,
            root,
            total,
            value,
            message;
        
        
        if (me.lastFieldGeneration !== me.model.prototype.fields.generation) {
            me.buildExtractors(true);
        }
        
        
        me.rawData = data;

        data = me.getData(data);
        
        success = true;
        recordCount = 0;
        records = [];
            
        if (me.successProperty) {
            value = me.getSuccess(data);
            if (value === false || value === 'false') {
                success = false;
            }
        }
        
        if (me.messageProperty) {
            message = me.getMessage(data);
        }

        
        
        if (me.readRecordsOnFailure || success) {
            
            
            root = Ext.isArray(data) ? data : me.getRoot(data);
            
            if (root) {
                total = root.length;
            }

          if (me.totalProperty) {
                value = parseInt(me.getTotal(data), 10);
                if (!isNaN(value)) {
                    total = value;
                }
            }

           if (root) {
                records = me.extractData(root);
                recordCount = records.length;
            }
        }

        return new Ext.data.ResultSet({
            total  : total || recordCount,
            count  : recordCount,
            records: records,
            success: success,
            message: message
        });
    },

    
    extractData : function(root) {
        var me = this,
            records = [],
            Model   = me.model,
            length  = root.length,
            convertedValues, node, record, i;
            
        if (!root.length && Ext.isObject(root)) {
            root = [root];
            length = 1;
        }

        for (i = 0; i < length; i++) {
            node = root[i];
            if (!node.isModel) { 
                
                
                record = new Model(undefined, me.getId(node), node, convertedValues = {});

                
                
                record.phantom = false;

                
                me.convertRecordData(convertedValues, node, record);

                records.push(record);
                
                if (me.implicitIncludes) {
                    me.readAssociated(record, node);
                }
            } else {
                
                
                records.push(node);
            }
        }

        return records;
    },
    
    
    readAssociated: function(record, data) {
        var associations = record.associations.items,
            i            = 0,
            length       = associations.length,
            association, associationData, proxy, reader;
        
        for (; i < length; i++) {
            association     = associations[i];
            associationData = this.getAssociatedDataRoot(data, association.associationKey || association.name);
            
            if (associationData) {
                reader = association.getReader();
                if (!reader) {
                    proxy = association.associatedModel.proxy;
                    
                    if (proxy) {
                        reader = proxy.getReader();
                    } else {
                        reader = new this.constructor({
                            model: association.associatedName
                        });
                    }
                }
                association.read(record, reader, associationData);
            }  
        }
    },
    
    
    getAssociatedDataRoot: function(data, associationName) {
        return data[associationName];
    },
    
    getFields: function() {
        return this.model.prototype.fields.items;
    },

    
    getData: function(data) {
        return data;
    },

    
    getRoot: function(data) {
        return data;
    },

    
    getResponseData: function(response) {
    },

    
    onMetaChange : function(meta) {
        var me = this,
            fields = meta.fields || me.getFields(),
            newModel,
            clientIdProperty;
        
        
        me.metaData = meta;
        
        
        me.root = meta.root || me.root;
        me.idProperty = meta.idProperty || me.idProperty;
        me.totalProperty = meta.totalProperty || me.totalProperty;
        me.successProperty = meta.successProperty || me.successProperty;
        me.messageProperty = meta.messageProperty || me.messageProperty;
        clientIdProperty = meta.clientIdProperty;

        if (me.model) {
            me.model.setFields(fields, me.idProperty, clientIdProperty);
            me.setModel(me.model, true);
        }
        else {
            newModel = Ext.define("Ext.data.reader.Json-Model" + Ext.id(), {
                extend: 'Ext.data.Model',
                fields: fields,
                clientIdProperty: clientIdProperty
            });
            if (me.idProperty) {
                
                
                
                
                newModel.idProperty = me.idProperty;
            }
            me.setModel(newModel, true);
        }
    },
    
    
    getIdProperty: function(){
        return this.idProperty || this.model.prototype.idProperty;
    },

    
    buildExtractors: function(force) {
        var me          = this,
            idProp      = me.getIdProperty(),
            totalProp   = me.totalProperty,
            successProp = me.successProperty,
            messageProp = me.messageProperty,
            accessor,
            idField,
            map;
            
        if (force === true) {
            delete me.convertRecordData;
        }
        
        if (me.convertRecordData) {
            return;
        }   

        
        if (totalProp) {
            me.getTotal = me.createAccessor(totalProp);
        }

        if (successProp) {
            me.getSuccess = me.createAccessor(successProp);
        }

        if (messageProp) {
            me.getMessage = me.createAccessor(messageProp);
        }

        if (idProp) {
            idField = me.model.prototype.fields.get(idProp);
            if (idField) {
                map = idField.mapping;
                idProp = (map !== undefined && map !== null) ? map : idProp;
            }
            accessor = me.createAccessor(idProp);

            me.getId = function(record) {
                var id = accessor.call(me, record);
                return (id === undefined || id === '') ? null : id;
            };
        } else {
            me.getId = function() {
                return null;
            };
        }
        me.convertRecordData = me.buildRecordDataExtractor();
        me.lastFieldGeneration = me.model.prototype.fields.generation;
    },

    recordDataExtractorTemplate : [
        'var me = this\n',
        '    ,fields = me.model.prototype.fields\n',
        '    ,value\n',
        '    ,internalId\n',
        '<tpl for="fields">',
        '    ,__field{#} = fields.get("{name}")\n',
        '</tpl>', ';\n',

        'return function(dest, source, record) {\n',
        '<tpl for="fields">',
        
        '    value = {[ this.createFieldAccessExpression(values, "__field" + xindex, "source") ]};\n',

        
            '<tpl if="hasCustomConvert">',
        '    dest["{name}"] = value === undefined ? __field{#}.convert(__field{#}.defaultValue, record) : __field{#}.convert(value, record);\n',

        
            '<tpl elseif="defaultValue !== undefined">',
        '    if (value === undefined) {\n',
        '        if (me.applyDefaults) {\n',
                '<tpl if="convert">',
        '            dest["{name}"] = __field{#}.convert(__field{#}.defaultValue, record);\n',
                '<tpl else>',
        '            dest["{name}"] = __field{#}.defaultValue\n',
                '</tpl>',
        '        };\n',
        '    } else {\n',
                '<tpl if="convert">',
        '        dest["{name}"] = __field{#}.convert(value, record);\n',
                '<tpl else>',
        '        dest["{name}"] = value;\n',
                '</tpl>',
        '    };',

        
            '<tpl else>',
        '    if (value !== undefined) {\n',
                '<tpl if="convert">',
        '        dest["{name}"] = __field{#}.convert(value, record);\n',
                '<tpl else>',
        '        dest["{name}"] = value;\n',
                '</tpl>',
        '    }\n',
            '</tpl>',

        '</tpl>',

        
        
        
        '<tpl if="clientIdProp">',
        '    if (record && (internalId = {[ this.createFieldAccessExpression(\{mapping: values.clientIdProp\}, null, "source") ]})) {\n',
        '        record.{["internalId"]} = internalId;\n',
        '    }\n',
        '</tpl>',

        '};'
    ],

    
    buildRecordDataExtractor: function() {
        var me = this,
            modelProto = me.model.prototype,
            templateData = {
                clientIdProp: modelProto.clientIdProperty,
                fields: modelProto.fields.items
            };

        me.recordDataExtractorTemplate.createFieldAccessExpression = me.accessExpressionFn;
        
        
        
        
        return Ext.functionFactory(me.recordDataExtractorTemplate.apply(templateData)).call(me);
    },

    destroyReader: function() {
        var me = this;
        delete me.proxy;
        delete me.model;
        delete me.convertRecordData;
        delete me.getId;
        delete me.getTotal;
        delete me.getSuccess;
        delete me.getMessage;
    }
}, function() {
    var proto = this.prototype;
    Ext.apply(proto, {
        
        nullResultSet: new Ext.data.ResultSet({
            total  : 0,
            count  : 0,
            records: [],
            success: true
        }),
        recordDataExtractorTemplate: new Ext.XTemplate(proto.recordDataExtractorTemplate)
    });
});


Ext.define('Ext.data.reader.Json', {
    extend: 'Ext.data.reader.Reader',
    alternateClassName: 'Ext.data.JsonReader',
    alias : 'reader.json',

    root: '',

    

    
    useSimpleAccessors: false,

    
    readRecords: function(data) {
        
        if (data.metaData) {
            this.onMetaChange(data.metaData);
        }

        
        this.jsonData = data;
        return this.callParent([data]);
    },

    
    getResponseData: function(response) {
        var data, error;
 
        try {
            data = Ext.decode(response.responseText);
            return this.readRecords(data);
        } catch (ex) {
            error = new Ext.data.ResultSet({
                total  : 0,
                count  : 0,
                records: [],
                success: false,
                message: ex.message
            });

            this.fireEvent('exception', this, response, error);

            Ext.Logger.warn('Unable to parse the JSON returned by the server');

            return error;
        }
    },

    
    buildExtractors : function() {
        var me = this;

        me.callParent(arguments);

        if (me.root) {
            me.getRoot = me.createAccessor(me.root);
        } else {
            me.getRoot = function(root) {
                return root;
            };
        }
    },

    
    extractData: function(root) {
        var recordName = this.record,
            data = [],
            length, i;

        if (recordName) {
            length = root.length;
            
            if (!length && Ext.isObject(root)) {
                length = 1;
                root = [root];
            }

            for (i = 0; i < length; i++) {
                data[i] = root[i][recordName];
            }
        } else {
            data = root;
        }
        return this.callParent([data]);
    },

    
    createAccessor: (function() {
        var re = /[\[\.]/;

        return function(expr) {
            if (Ext.isEmpty(expr)) {
                return Ext.emptyFn;
            }
            if (Ext.isFunction(expr)) {
                return expr;
            }
            if (this.useSimpleAccessors !== true) {
                var i = String(expr).search(re);
                if (i >= 0) {
                    return Ext.functionFactory('obj', 'return obj' + (i > 0 ? '.' : '') + expr);
                }
            }
            return function(obj) {
                return obj[expr];
            };
        };
    }()),

    
    createFieldAccessExpression: (function() {
        var re = /[\[\.]/;

        return function(field, fieldVarName, dataName) {
            var me     = this,
                hasMap = (field.mapping !== null),
                map    = hasMap ? field.mapping : field.name,
                result,
                operatorSearch;

            if (typeof map === 'function') {
                result = fieldVarName + '.mapping(' + dataName + ', this)';
            } else if (this.useSimpleAccessors === true || ((operatorSearch = String(map).search(re)) < 0)) {
                if (!hasMap || isNaN(map)) {
                    
                    map = '"' + map + '"';
                }
                result = dataName + "[" + map + "]";
            } else {
                result = dataName + (operatorSearch > 0 ? '.' : '') + map;
            }
            return result;
        };
    }())
});


Ext.define('Ext.data.reader.Array', {
    extend: 'Ext.data.reader.Json',
    alternateClassName: 'Ext.data.ArrayReader',
    alias : 'reader.array',

    
    totalProperty: undefined,
    successProperty: undefined,

    
    createFieldAccessExpression: function(field, fieldVarName, dataName) {
            
            
        var index  = (field.mapping == null) ? field.originalIndex : field.mapping,
            result;

        if (typeof index === 'function') {
            result = fieldVarName + '.mapping(' + dataName + ', this)';
        } else {
            if (isNaN(index)) {
                index = '"' + index + '"';
            }
            result = dataName + "[" + index + "]";
        }
        return result;
    }
});


Ext.define('Ext.data.reader.Xml', {
    extend: 'Ext.data.reader.Reader',
    alternateClassName: 'Ext.data.XmlReader',
    alias : 'reader.xml',

    

    
    createAccessor: function(expr) {
        var me = this;

        if (Ext.isEmpty(expr)) {
            return Ext.emptyFn;
        }

        if (Ext.isFunction(expr)) {
            return expr;
        }

        return function(root) {
            return me.getNodeValue(Ext.DomQuery.selectNode(expr, root));
        };
    },

    getNodeValue: function(node) {
        if (node && node.firstChild) {
            return node.firstChild.nodeValue;
        }
        return undefined;
    },

    
    getResponseData: function(response) {
        var xml = response.responseXML,
            error,
            msg;

        if (!xml) {
            msg = 'XML data not found in the response';               

            error = new Ext.data.ResultSet({
                total  : 0,
                count  : 0,
                records: [],
                success: false,
                message: msg
            });

            this.fireEvent('exception', this, response, error);

            Ext.Logger.warn(msg);

            return error;
        }

        return this.readRecords(xml);
    },

    
    getData: function(data) {
        return data.documentElement || data;
    },

    
    getRoot: function(data) {
        var nodeName = data.nodeName,
            root     = this.root;

        if (!root || (nodeName && nodeName == root)) {
            return data;
        } else if (Ext.DomQuery.isXml(data)) {
            
            
            
            return Ext.DomQuery.selectNode(root, data);
        }
    },

    
    extractData: function(root) {
        var recordName = this.record;


        if (recordName != root.nodeName) {
            root = Ext.DomQuery.select(recordName, root);
        } else {
            root = [root];
        }
        return this.callParent([root]);
    },

    
    getAssociatedDataRoot: function(data, associationName) {
        return Ext.DomQuery.select(associationName, data)[0];
    },

    
    readRecords: function(doc) {
        
        
        if (Ext.isArray(doc)) {
            doc = doc[0];
        }

        
        this.xmlData = doc;
        return this.callParent([doc]);
    },

    
    createFieldAccessExpression: function(field, fieldVarName, dataName) {
        var selector = field.mapping || field.name,
            result;

        if (typeof selector === 'function') {
            result = fieldVarName + '.mapping(' + dataName + ', this)';
        } else {
            result = 'me.getNodeValue(Ext.DomQuery.selectNode("' + selector + '", ' + dataName + '))';
        }
        return result;
    }
});


Ext.define('Ext.data.writer.Json', {
    extend: 'Ext.data.writer.Writer',
    alternateClassName: 'Ext.data.JsonWriter',
    alias: 'writer.json',
    
    
    root: undefined,
    
    
    encode: false,
    
    
    allowSingle: true,
    
    
    writeRecords: function(request, data) {
        var root = this.root;
        
        if (this.allowSingle && data.length == 1) {
            
            data = data[0];
        }
        
        if (this.encode) {
            if (root) {
                
                request.params[root] = Ext.encode(data);
            } else {
            }
        } else {
            
            request.jsonData = request.jsonData || {};
            if (root) {
                request.jsonData[root] = data;
            } else {
                request.jsonData = data;
            }
        }
        return request;
    }
});


Ext.define('Ext.direct.Provider', {

    

   alias: 'direct.provider',

    mixins: {
        observable: 'Ext.util.Observable'
    },

    

   

    constructor : function(config){
        var me = this;

        Ext.apply(me, config);
        me.addEvents(
            
            'connect',
            
            'disconnect',
            
            'data',
            
            'exception'
        );
        me.mixins.observable.constructor.call(me, config);
    },

    
    isConnected: function(){
        return false;
    },

    
    connect: Ext.emptyFn,

    
    disconnect: Ext.emptyFn
});



Ext.define('Ext.direct.JsonProvider', {

    

    extend: 'Ext.direct.Provider',

    alias: 'direct.jsonprovider',

    uses: ['Ext.direct.ExceptionEvent'],

    

   
   parseResponse: function(response){
        if (!Ext.isEmpty(response.responseText)) {
            if (Ext.isObject(response.responseText)) {
                return response.responseText;
            }
            return Ext.decode(response.responseText);
        }
        return null;
    },

    
    createEvents: function(response){
        var data = null,
            events = [],
            event,
            i = 0,
            len;

        try{
            data = this.parseResponse(response);
        } catch(e) {
            event = new Ext.direct.ExceptionEvent({
                data: e,
                xhr: response,
                code: Ext.direct.Manager.exceptions.PARSE,
                message: 'Error parsing json response: \n\n ' + data
            });
            return [event];
        }

        if (Ext.isArray(data)) {
            for (len = data.length; i < len; ++i) {
                events.push(this.createEvent(data[i]));
            }
        } else {
            events.push(this.createEvent(data));
        }
        return events;
    },

    
    createEvent: function(response){
        return Ext.create('direct.' + response.type, response);
    }
});

Ext.define('Ext.direct.PollingProvider', {
    
    
    
    extend: 'Ext.direct.JsonProvider',
    
    alias: 'direct.pollingprovider',
    
    uses: ['Ext.direct.ExceptionEvent'],
    
    requires: ['Ext.Ajax', 'Ext.util.DelayedTask'],
    
    
    
    
    interval: 3000,

    
    
    

    
    constructor : function(config){
        this.callParent(arguments);
        this.addEvents(
            
            'beforepoll',            
            
            'poll'
        );
    },

    
    isConnected: function(){
        return !!this.pollTask;
    },

    
    connect: function(){
        var me = this, url = me.url;
        
        if (url && !me.pollTask) {
            me.pollTask = Ext.TaskManager.start({
                run: function(){
                    if (me.fireEvent('beforepoll', me) !== false) {
                        if (Ext.isFunction(url)) {
                            url(me.baseParams);
                        } else {
                            Ext.Ajax.request({
                                url: url,
                                callback: me.onData,
                                scope: me,
                                params: me.baseParams
                            });
                        }
                    }
                },
                interval: me.interval,
                scope: me
            });
            me.fireEvent('connect', me);
        } else if (!url) {
        }
    },

    
    disconnect: function(){
        var me = this;
        
        if (me.pollTask) {
            Ext.TaskManager.stop(me.pollTask);
            delete me.pollTask;
            me.fireEvent('disconnect', me);
        }
    },

    
    onData: function(opt, success, response){
        var me = this, 
            i = 0, 
            len,
            events;
        
        if (success) {
            events = me.createEvents(response);
            for (len = events.length; i < len; ++i) {
                me.fireEvent('data', me, events[i]);
            }
        } else {
            me.fireEvent('data', me, new Ext.direct.ExceptionEvent({
                data: null,
                code: Ext.direct.Manager.exceptions.TRANSPORT,
                message: 'Unable to connect to the server.',
                xhr: response
            }));
        }
    }
});

Ext.ns('Ext.fx');

Ext.require('Ext.fx.CubicBezier', function() {
    var math = Math,
        pi = math.PI,
        pow = math.pow,
        sin = math.sin,
        sqrt = math.sqrt,
        abs = math.abs,
        backInSeed = 1.70158;
    Ext.fx.Easing = {
        
        
        
        
        
        
        
        
    };

    Ext.apply(Ext.fx.Easing, {
        linear: function(n) {
            return n;
        },
        ease: function(n) {
            var q = 0.07813 - n / 2,
                alpha = -0.25,
                Q = sqrt(0.0066 + q * q),
                x = Q - q,
                X = pow(abs(x), 1/3) * (x < 0 ? -1 : 1),
                y = -Q - q,
                Y = pow(abs(y), 1/3) * (y < 0 ? -1 : 1),
                t = X + Y + 0.25;
            return pow(1 - t, 2) * 3 * t * 0.1 + (1 - t) * 3 * t * t + t * t * t;
        },
        easeIn: function (n) {
            return pow(n, 1.7);
        },
        easeOut: function (n) {
            return pow(n, 0.48);
        },
        easeInOut: function(n) {
            var q = 0.48 - n / 1.04,
                Q = sqrt(0.1734 + q * q),
                x = Q - q,
                X = pow(abs(x), 1/3) * (x < 0 ? -1 : 1),
                y = -Q - q,
                Y = pow(abs(y), 1/3) * (y < 0 ? -1 : 1),
                t = X + Y + 0.5;
            return (1 - t) * 3 * t * t + t * t * t;
        },
        backIn: function (n) {
            return n * n * ((backInSeed + 1) * n - backInSeed);
        },
        backOut: function (n) {
            n = n - 1;
            return n * n * ((backInSeed + 1) * n + backInSeed) + 1;
        },
        elasticIn: function (n) {
            if (n === 0 || n === 1) {
                return n;
            }
            var p = 0.3,
                s = p / 4;
            return pow(2, -10 * n) * sin((n - s) * (2 * pi) / p) + 1;
        },
        elasticOut: function (n) {
            return 1 - Ext.fx.Easing.elasticIn(1 - n);
        },
        bounceIn: function (n) {
            return 1 - Ext.fx.Easing.bounceOut(1 - n);
        },
        bounceOut: function (n) {
            var s = 7.5625,
                p = 2.75,
                l;
            if (n < (1 / p)) {
                l = s * n * n;
            } else {
                if (n < (2 / p)) {
                    n -= (1.5 / p);
                    l = s * n * n + 0.75;
                } else {
                    if (n < (2.5 / p)) {
                        n -= (2.25 / p);
                        l = s * n * n + 0.9375;
                    } else {
                        n -= (2.625 / p);
                        l = s * n * n + 0.984375;
                    }
                }
            }
            return l;
        }
    });
    Ext.apply(Ext.fx.Easing, {
        'back-in': Ext.fx.Easing.backIn,
        'back-out': Ext.fx.Easing.backOut,
        'ease-in': Ext.fx.Easing.easeIn,
        'ease-out': Ext.fx.Easing.easeOut,
        'elastic-in': Ext.fx.Easing.elasticIn,
        'elastic-out': Ext.fx.Easing.elasticIn,
        'bounce-in': Ext.fx.Easing.bounceIn,
        'bounce-out': Ext.fx.Easing.bounceOut,
        'ease-in-out': Ext.fx.Easing.easeInOut
    });
});

Ext.define('Ext.fx.target.Component', {

    
   
    extend: 'Ext.fx.target.Target',
    
    

    type: 'component',

    
    getPropMethod: {
        top: function() {
            return this.getPosition(true)[1];
        },
        left: function() {
            return this.getPosition(true)[0];
        },
        x: function() {
            return this.getPosition()[0];
        },
        y: function() {
            return this.getPosition()[1];
        },
        height: function() {
            return this.getHeight();
        },
        width: function() {
            return this.getWidth();
        },
        opacity: function() {
            return this.el.getStyle('opacity');
        }
    },

    compMethod: {
        top: 'setPosition',
        left: 'setPosition',
        x: 'setPagePosition',
        y: 'setPagePosition',
        height: 'setSize',
        width: 'setSize',
        opacity: 'setOpacity'
    },

    
    getAttr: function(attr, val) {
        return [[this.target, val !== undefined ? val : this.getPropMethod[attr].call(this.target)]];
    },

    setAttr: function(targetData, isFirstFrame, isLastFrame) {
        var me = this,
            target = me.target,
            ln = targetData.length,
            attrs, attr, o, i, j, meth, targets, left, top, w, h;
        for (i = 0; i < ln; i++) {
            attrs = targetData[i].attrs;
            for (attr in attrs) {
                targets = attrs[attr].length;
                meth = {
                    setPosition: {},
                    setPagePosition: {},
                    setSize: {},
                    setOpacity: {}
                };
                for (j = 0; j < targets; j++) {
                    o = attrs[attr][j];
                    
                    
                    
                    
                    meth[me.compMethod[attr]].target = o[0];
                    meth[me.compMethod[attr]][attr] = o[1];
                }
                if (meth.setPosition.target) {
                    o = meth.setPosition;
                    left = (o.left === undefined) ? undefined : parseFloat(o.left);
                    top = (o.top === undefined) ? undefined : parseFloat(o.top);
                    o.target.setPosition(left, top);
                }
                if (meth.setPagePosition.target) {
                    o = meth.setPagePosition;
                    o.target.setPagePosition(o.x, o.y);
                }
                if (meth.setSize.target) {
                    o = meth.setSize;
                    
                    w = (o.width === undefined) ? o.target.getWidth() : parseFloat(o.width);
                    h = (o.height === undefined) ? o.target.getHeight() : parseFloat(o.height);

                    
                    
                    
                    
                    
                    
                    
                    if (isLastFrame || me.dynamic) {
                        o.target.setSize(w, h);
                    } else {
                        o.target.el.setSize(w, h);
                    }
                }
                if (meth.setOpacity.target) {
                    o = meth.setOpacity;
                    o.target.el.setStyle('opacity', o.opacity);
                }
            }
        }
    }
});


Ext.define('Ext.fx.target.Element', {

    
    
    extend: 'Ext.fx.target.Target',
    
    

    type: 'element',

    getElVal: function(el, attr, val) {
        if (val == undefined) {
            if (attr === 'x') {
                val = el.getX();
            }
            else if (attr === 'y') {
                val = el.getY();
            }
            else if (attr === 'scrollTop') {
                val = el.getScroll().top;
            }
            else if (attr === 'scrollLeft') {
                val = el.getScroll().left;
            }
            else if (attr === 'height') {
                val = el.getHeight();
            }
            else if (attr === 'width') {
                val = el.getWidth();
            }
            else {
                val = el.getStyle(attr);
            }
        }
        return val;
    },

    getAttr: function(attr, val) {
        var el = this.target;
        return [[ el, this.getElVal(el, attr, val)]];
    },

    setAttr: function(targetData) {
        var target = this.target,
            ln = targetData.length,
            attrs, attr, o, i, j, ln2, element, value;
        for (i = 0; i < ln; i++) {
            attrs = targetData[i].attrs;
            for (attr in attrs) {
                if (attrs.hasOwnProperty(attr)) {
                    ln2 = attrs[attr].length;
                    for (j = 0; j < ln2; j++) {
                        o = attrs[attr][j];
                        element = o[0];
                        value = o[1];
                        if (attr === 'x') {
                            element.setX(value);
                        } else if (attr === 'y') {
                            element.setY(value);
                        } else if (attr === 'scrollTop') {
                            element.scrollTo('top', value);
                        } else if (attr === 'scrollLeft') {
                            element.scrollTo('left',value);
                        } else if (attr === 'width') {
                            element.setWidth(value);
                        } else if (attr === 'height') {
                            element.setHeight(value);
                        } else {
                            element.setStyle(attr, value);
                        }
                    }
                }
            }
        }
    }
});


Ext.define('Ext.fx.target.CompositeElement', {

    

    extend: 'Ext.fx.target.Element',

    

    
    isComposite: true,
    
    constructor: function(target) {
        target.id = target.id || Ext.id(null, 'ext-composite-');
        this.callParent([target]);
    },

    getAttr: function(attr, val) {
        var out      = [],
            elements = this.target.elements,
            length   = elements.length,
            i,
            el;

        for (i = 0; i < length; i++) {
            el = elements[i];

            if (el) {
                el = this.target.getElement(el);
                out.push([el, this.getElVal(el, attr, val)]);
            }
        }

        return out;
    }
});


Ext.define('Ext.fx.target.ElementCSS', {

    

    extend: 'Ext.fx.target.Element',

    

    setAttr: function(targetData, isFirstFrame) {
        var cssArr = {
                attrs: [],
                duration: [],
                easing: []
            },
            ln = targetData.length,
            attributes,
            attrs,
            attr,
            easing,
            duration,
            o,
            i,
            j,
            ln2;
        for (i = 0; i < ln; i++) {
            attrs = targetData[i];
            duration = attrs.duration;
            easing = attrs.easing;
            attrs = attrs.attrs;
            for (attr in attrs) {
                if (Ext.Array.indexOf(cssArr.attrs, attr) == -1) {
                    cssArr.attrs.push(attr.replace(/[A-Z]/g, function(v) {
                        return '-' + v.toLowerCase();
                    }));
                    cssArr.duration.push(duration + 'ms');
                    cssArr.easing.push(easing);
                }
            }
        }
        attributes = cssArr.attrs.join(',');
        duration = cssArr.duration.join(',');
        easing = cssArr.easing.join(', ');
        for (i = 0; i < ln; i++) {
            attrs = targetData[i].attrs;
            for (attr in attrs) {
                ln2 = attrs[attr].length;
                for (j = 0; j < ln2; j++) {
                    o = attrs[attr][j];
                    o[0].setStyle(Ext.supports.CSS3Prefix + 'TransitionProperty', isFirstFrame ? '' : attributes);
                    o[0].setStyle(Ext.supports.CSS3Prefix + 'TransitionDuration', isFirstFrame ? '' : duration);
                    o[0].setStyle(Ext.supports.CSS3Prefix + 'TransitionTimingFunction', isFirstFrame ? '' : easing);
                    o[0].setStyle(attr, o[1]);

                    
                    if (isFirstFrame) {
                        o = o[0].dom.offsetWidth;
                    }
                    else {
                        
                        o[0].on(Ext.supports.CSS3TransitionEnd, function() {
                            this.setStyle(Ext.supports.CSS3Prefix + 'TransitionProperty', null);
                            this.setStyle(Ext.supports.CSS3Prefix + 'TransitionDuration', null);
                            this.setStyle(Ext.supports.CSS3Prefix + 'TransitionTimingFunction', null);
                        }, o[0], { single: true });
                    }
                }
            }
        }
    }
});

Ext.define('Ext.fx.target.CompositeElementCSS', {

    

    extend: 'Ext.fx.target.CompositeElement',

    requires: ['Ext.fx.target.ElementCSS'],

    
    setAttr: function() {
        return Ext.fx.target.ElementCSS.prototype.setAttr.apply(this, arguments);
    }
});


Ext.define('Ext.fx.target.Sprite', {

    

    extend: 'Ext.fx.target.Target',

    

    type: 'draw',

    getFromPrim: function (sprite, attr) {
        var obj;
        switch (attr) {
            case 'rotate':
            case 'rotation':
                obj = sprite.attr.rotation;
                return {
                    x: obj.x || 0,
                    y: obj.y || 0,
                    degrees: obj.degrees || 0
                };
            case 'scale':
            case 'scaling':
                obj = sprite.attr.scaling;
                return {
                    x: obj.x || 1,
                    y: obj.y || 1,
                    cx: obj.cx || 0,
                    cy: obj.cy || 0
                };
            case 'translate':
            case 'translation':
                obj = sprite.attr.translation;
                return {
                    x: obj.x || 0,
                    y: obj.y || 0
                };
            default:
                return sprite.attr[attr];
        }
    },

    getAttr: function (attr, val) {
        return [
            [this.target, val != undefined ? val : this.getFromPrim(this.target, attr)]
        ];
    },

    setAttr: function (targetData) {
        var ln = targetData.length,
            spriteArr = [],
            attrsConf, attr, attrArr, attrs, sprite, idx, value, i, j, x, y, ln2;
        for (i = 0; i < ln; i++) {
            attrsConf = targetData[i].attrs;
            for (attr in attrsConf) {
                attrArr = attrsConf[attr];
                ln2 = attrArr.length;
                for (j = 0; j < ln2; j++) {
                    sprite = attrArr[j][0];
                    attrs = attrArr[j][1];
                    if (attr === 'translate' || attr === 'translation') {
                        value = {
                            x: attrs.x,
                            y: attrs.y
                        };
                    }
                    else if (attr === 'rotate' || attr === 'rotation') {
                        x = attrs.x;
                        if (isNaN(x)) {
                            x = null;
                        }
                        y = attrs.y;
                        if (isNaN(y)) {
                            y = null;
                        }
                        value = {
                            degrees: attrs.degrees,
                            x: x,
                            y: y
                        };
                    } else if (attr === 'scale' || attr === 'scaling') {
                        x = attrs.x;
                        if (isNaN(x)) {
                            x = null;
                        }
                        y = attrs.y;
                        if (isNaN(y)) {
                            y = null;
                        }
                        value = {
                            x: x,
                            y: y,
                            cx: attrs.cx,
                            cy: attrs.cy
                        };
                    }
                    else if (attr === 'width' || attr === 'height' || attr === 'x' || attr === 'y') {
                        value = parseFloat(attrs);
                    }
                    else {
                        value = attrs;
                    }
                    idx = Ext.Array.indexOf(spriteArr, sprite);
                    if (idx == -1) {
                        spriteArr.push([sprite, {}]);
                        idx = spriteArr.length - 1;
                    }
                    spriteArr[idx][1][attr] = value;
                }
            }
        }
        ln = spriteArr.length;
        for (i = 0; i < ln; i++) {
            spriteArr[i][0].setAttributes(spriteArr[i][1]);
        }
        this.target.redraw();
    }
});



Ext.define('Ext.fx.target.CompositeSprite', {

    

    extend: 'Ext.fx.target.Sprite',

    

    getAttr: function(attr, val) {
        var out     = [],
            sprites = [].concat(this.target.items),
            length  = sprites.length,
            i,
            sprite;

        for (i = 0; i < length; i++) {
            sprite = sprites[i];
            out.push([sprite, val != undefined ? val : this.getFromPrim(sprite, attr)]);
        }

        return out;
    }
});


Ext.define('Ext.layout.Layout', {

    requires: [
        'Ext.XTemplate'
    ],

    uses: [ 'Ext.layout.Context' ],

    
    isLayout: true,
    initialized: false,
    running: false,

    autoSizePolicy: {
        setsWidth: 0,
        setsHeight: 0
    },

    statics: {
        layoutsByType: {},

        create: function(layout, defaultType) {
            var ClassManager = Ext.ClassManager,
                layoutsByType = this.layoutsByType,
                alias, className, config, layoutClass, type, load;

            if (!layout || typeof layout === 'string') {
                type = layout || defaultType;
                config = {};                    
            } else if (layout.isLayout) {
                return layout;
            } else {
                config = layout;
                type = layout.type || defaultType;
            }

            if (!(layoutClass = layoutsByType[type])) {
                alias = 'layout.' + type;
                className = ClassManager.getNameByAlias(alias);

                
                if (!className) {
                    load = true;
                }
                
                layoutClass = ClassManager.get(className);
                if (load || !layoutClass) {
                    return ClassManager.instantiateByAlias(alias, config || {});
                }
                layoutsByType[type] = layoutClass;
            }

            return new layoutClass(config);
        }
    },

    constructor : function(config) {
        var me = this;

        me.id = Ext.id(null, me.type + '-');
        Ext.apply(me, config);
        me.layoutCount = 0;
    },

    

    
    beginLayout: Ext.emptyFn,

    
    beginLayoutCycle: function (ownerContext) {
        var me = this,
            context = me.context,
            changed;

        if (me.lastWidthModel != ownerContext.widthModel) {
            if (me.lastWidthModel) {
                changed = true;
            }
            me.lastWidthModel = ownerContext.widthModel;
        }

        if (me.lastHeightModel != ownerContext.heightModel) {
            if (me.lastWidthModel) {
                changed = true;
            }
            me.lastHeightModel = ownerContext.heightModel;
        }

        if (changed) {
            (context = ownerContext.context).clearTriggers(me, false);
            context.clearTriggers(me, true);
            me.triggerCount = 0;
        }
    },

    

    

    

    
    finishedLayout: function () {
        this.ownerContext = null;
    },
    
    
    
    redoLayout: Ext.emptyFn,
    undoLayout: Ext.emptyFn,

    getAnimatePolicy: function() {
        return this.animatePolicy;
    },

    
    getItemSizePolicy: function (item) {
        return this.autoSizePolicy;
    },

    isItemBoxParent: function (itemContext) {
        return false;
    },

    isItemLayoutRoot: function (item) {
        var sizeModel = item.getSizeModel(),
            width = sizeModel.width,
            height = sizeModel.height;

        
        
        if (!item.componentLayout.lastComponentSize && (width.calculated || height.calculated)) {
            return false;
        }

        
        return !width.shrinkWrap && !height.shrinkWrap;
    },

    isItemShrinkWrap: function (item) {
        return item.shrinkWrap;
    },

    isRunning: function () {
        return !!this.ownerContext;
    },

    
    
    

    getItemsRenderTree: function (items, renderCfgs) {
        var length = items.length,
            i, item, itemConfig, result;

        if (length) {
            result = [];
            for (i = 0; i < length; ++i) {
                item = items[i];

                
                
                if (!item.rendered) {

                    
                    
                    
                    
                    
                    if (renderCfgs && (renderCfgs[item.id] !== undefined)) {
                        itemConfig = renderCfgs[item.id];
                    } else {
                        
                        this.configureItem(item);
                        itemConfig = item.getRenderTree();
                        if (renderCfgs) {
                            renderCfgs[item.id] = itemConfig;
                        }
                    }

                    
                    if (itemConfig) {
                        result.push(itemConfig);
                    }
                }
            }
        }

        return result;
    },

    finishRender: Ext.emptyFn,

    finishRenderItems: function (target, items) {
        var length = items.length,
            i, item;

        for (i = 0; i < length; i++) {
            item = items[i];

            
            if (item.rendering) {

                
                item.finishRender(i);

                this.afterRenderItem(item);
            }
        }
    },

    renderChildren: function () {
        var me = this,
            items = me.getLayoutItems(),
            target = me.getRenderTarget();

        me.renderItems(items, target);
    },

    
    renderItems : function(items, target) {
        var me = this,
            ln = items.length,
            i = 0,
            item;

        if (ln) {
            Ext.suspendLayouts();
            for (; i < ln; i++) {
                item = items[i];
                if (item && !item.rendered) {
                    me.renderItem(item, target, i);
                } else if (!me.isValidParent(item, target, i)) {
                    me.moveItem(item, target, i);
                } else {
                    
                    me.configureItem(item);
                }
            }
            Ext.resumeLayouts(true);
        }
    },

    
    isValidParent : function(item, target, position) {
        var itemDom = item.el ? item.el.dom : Ext.getDom(item),
            targetDom = (target && target.dom) || target;

        
        if (itemDom.parentNode && itemDom.parentNode.className.indexOf(Ext.baseCSSPrefix + 'resizable-wrap') !== -1) {
            itemDom = itemDom.parentNode;
        }

        
        if (itemDom && targetDom) {
            if (typeof position == 'number') {
                return itemDom === targetDom.childNodes[position];
            }
            return itemDom.parentNode === targetDom;
        }

        return false;
    },

    
    configureItem: function(item) {
        item.ownerLayout = this;
    },

    
    renderItem : function(item, target, position) {
        var me = this;
        if (!item.rendered) {
            me.configureItem(item);
            item.render(target, position);
            me.afterRenderItem(item);
        }
    },

    
    moveItem : function(item, target, position) {
        target = target.dom || target;
        if (typeof position == 'number') {
            position = target.childNodes[position];
        }
        target.insertBefore(item.el.dom, position || null);
        item.container = Ext.get(target);
        this.configureItem(item);
    },

    
    onContentChange: function () {
        this.owner.updateLayout();
        return true;
    },

    
    initLayout : function() {
        this.initialized = true;
    },

    
    setOwner : function(owner) {
        this.owner = owner;
    },

    
    getLayoutItems : function() {
        return [];
    },

    
    afterRenderItem: Ext.emptyFn,
    onAdd : Ext.emptyFn,
    onRemove : Ext.emptyFn,
    onDestroy : Ext.emptyFn,

    
    afterRemove : function(item) {
        var me = this,
            el = item.el,
            owner = me.owner,
            removeClasses;

        if (item.rendered) {
            removeClasses = [].concat(me.itemCls || []);
            if (owner.itemCls) {
                removeClasses = Ext.Array.push(removeClasses, owner.itemCls);
            }
            if (removeClasses.length) {
                el.removeCls(removeClasses);
            }
        }

        delete item.ownerLayout;
    },

    
    destroy : function() {
        var me = this,
            target;

        if (me.targetCls) {
            target = me.getTarget();
            if (target) {
                target.removeCls(me.targetCls);
            }
        }

        me.onDestroy();
    },

    sortWeightedItems: function (items, reverseProp) {
        for (var i = 0, length = items.length; i < length; ++i) {
            items[i].$i = i;
        }

        Ext.Array.sort(items, function (item1, item2) {
            var ret = item2.weight - item1.weight;

            if (!ret) {
                ret = item1.$i - item2.$i;
                if (item1[reverseProp]) {
                    ret = -ret;
                }
            }

            return ret;
        });

        for (i = 0; i < length; ++i) {
            delete items[i].$i;
        }
    }
}, function () {
    var Layout = this,
        sizeModels = {},
        sizeModelsArray = [],
        i, j, n, pairs, sizeModel;

    Layout.prototype.sizeModels = Layout.sizeModels = sizeModels;

    
    var SizeModel = function (config) {
        var me = this,
            name = config.name;

        Ext.apply(Ext.apply(me, defaults), config);

        me[name] = true; 
        SizeModel[name] = sizeModels[name] = me;

        me.fixed = !(me.auto = me.natural || me.shrinkWrap);

        
        me.ordinal = sizeModelsArray.length;
        sizeModelsArray.push(me);
    };

    Ext.layout.SizeModel = SizeModel;

    var defaults = {
        

        

        
        calculated: false,

        
        configured: false,

        
        constrainedMax: false,

        
        constrainedMin: false,

        

        
        natural: false,

        
        shrinkWrap: false,

        
        calculatedFromConfigured: false,

        
        calculatedFromNatural: false,

        
        calculatedFromShrinkWrap: false,

        
        names: null
    };

    
    

    new SizeModel({
        name: 'calculated'
    });

    new SizeModel({
        name: 'configured',
        names: { width: 'width', height: 'height' }
    });

    new SizeModel({
        name: 'natural'
    });

    new SizeModel({
        name: 'shrinkWrap'
    });

    
    
    

    new SizeModel({
        name: 'calculatedFromConfigured',
        configured: true,
        names: { width: 'width', height: 'height' }
    });

    new SizeModel({
        name: 'calculatedFromNatural',
        natural: true
    });

    new SizeModel({
        name: 'calculatedFromShrinkWrap',
        shrinkWrap: true
    });

    new SizeModel({
        name: 'constrainedMax',
        configured: true,
        constrained: true,
        names: { width: 'maxWidth', height: 'maxHeight' }
    });

    new SizeModel({
        name: 'constrainedMin',
        configured: true,
        constrained: true,
        names: { width: 'minWidth', height: 'minHeight' }
    });

    for (i = 0, n = sizeModelsArray.length; i < n; ++i) {
        sizeModel = sizeModelsArray[i];
        
        sizeModel.pairsByHeightOrdinal = pairs = [];

        for (j = 0; j < n; ++j) {
            pairs.push({
                width: sizeModel,
                height: sizeModelsArray[j]
            });
        }
    }
});


Ext.define('Ext.layout.component.Component', {

    

    extend: 'Ext.layout.Layout',

    

    type: 'component',

    isComponentLayout: true,

    nullBox: {},

    usesContentHeight: true,
    usesContentWidth: true,
    usesHeight: true,
    usesWidth: true,

    beginLayoutCycle: function (ownerContext, firstCycle) {
        var me = this,
            owner = me.owner,
            ownerCtContext = ownerContext.ownerCtContext,
            heightModel = ownerContext.heightModel,
            widthModel = ownerContext.widthModel,
            body = owner.el.dom === document.body,
            lastBox = owner.lastBox || me.nullBox,
            lastSize = owner.el.lastBox || me.nullBox,
            dirty = !body,
            ownerLayout, v, widthName, heightName;

        me.callParent(arguments);

        if (firstCycle) {
            if (me.usesContentWidth) {
                ++ownerContext.consumersContentWidth;
            }
            if (me.usesContentHeight) {
                ++ownerContext.consumersContentHeight;
            }
            if (me.usesWidth) {
                ++ownerContext.consumersWidth;
            }
            if (me.usesHeight) {
                ++ownerContext.consumersHeight;
            }

            if (ownerCtContext && !ownerCtContext.hasRawContent) {
                ownerLayout = owner.ownerLayout;

                if (ownerLayout.usesWidth) {
                    ++ownerContext.consumersWidth;
                }
                if (ownerLayout.usesHeight) {
                    ++ownerContext.consumersHeight;
                }
            }
        }

        
        

        if (widthModel.configured) {
            
            
            
            
            widthName = widthModel.names.width;

            if (!body) {
                dirty = firstCycle ? owner[widthName] !== lastSize.width
                                   : widthModel.constrained;
            }
            
            ownerContext.setWidth(owner[widthName], dirty);
        } else if (ownerContext.isTopLevel) {
            if (widthModel.calculated) {
                v = lastBox.width;
                ownerContext.setWidth(v, v != lastSize.width);
            }

            v = lastBox.x;
            ownerContext.setProp('x', v, v != lastSize.x);
        }

        if (heightModel.configured) {
            heightName = heightModel.names.height;

            if (!body) {
                dirty = firstCycle ? owner[heightName] !== lastSize.height
                                   : heightModel.constrained;
            }

            ownerContext.setHeight(owner[heightName], dirty);
        } else if (ownerContext.isTopLevel) {
            if (heightModel.calculated) {
                v = lastBox.height;
                ownerContext.setHeight(v, v != lastSize.height);
            }

            v = lastBox.y;
            ownerContext.setProp('y', v, v != lastSize.y);
        }
    },

    finishedLayout: function(ownerContext) {
        var me = this,
            elementChildren = ownerContext.children,
            owner = me.owner,
            len, i, elContext, lastBox, props, v;

        

        
        
        if (elementChildren) {
            len = elementChildren.length;
            for (i = 0; i < len; i++) {
                elContext = elementChildren[i];
                elContext.el.lastBox = elContext.props;
            }
        }

        
        ownerContext.previousSize = me.lastComponentSize;

        
        me.lastComponentSize = owner.el.lastBox = props = ownerContext.props;

        
        
        owner.lastBox = lastBox = {};

        v = props.x;
        if (v !== undefined) {
            lastBox.x = v;
        }
        v = props.y;
        if (v !== undefined) {
            lastBox.y = v;
        }
        v = props.width;
        if (v !== undefined) {
            lastBox.width = v;
        }
        v = props.height;
        if (v !== undefined) {
            lastBox.height = v;
        }

        me.callParent(arguments);
    },
    
    notifyOwner: function(ownerContext) {
        var me = this,
            currentSize = me.lastComponentSize,
            prevSize = ownerContext.previousSize,
            args = [currentSize.width, currentSize.height];

        if (prevSize) {
            args.push(prevSize.width, prevSize.height);
        }

        
        me.owner.afterComponentLayout.apply(me.owner, args);
    },

    
    getTarget : function() {
        return this.owner.el;
    },

    
    getRenderTarget : function() {
        return this.owner.el;
    },

    cacheTargetInfo: function(ownerContext) {
        var me = this,
            targetInfo = me.targetInfo,
            target;

        if (!targetInfo) {
            target = ownerContext.getEl('getTarget', me);

            me.targetInfo = targetInfo = {
                padding: target.getPaddingInfo(),
                border: target.getBorderInfo()
            };
        }

        return targetInfo;
    },

    measureAutoDimensions: function (ownerContext, dimensions) {
        
        
        
        
        

        var me = this,
            owner = me.owner,
            containerLayout = owner.layout,
            heightModel = ownerContext.heightModel,
            widthModel = ownerContext.widthModel,
            boxParent = ownerContext.boxParent,
            isBoxParent = ownerContext.isBoxParent,
            props = ownerContext.props,
            isContainer,
            ret = {
                gotWidth: false,
                gotHeight: false,
                isContainer: (isContainer = !ownerContext.hasRawContent)
            },
            hv = dimensions || 3,
            zeroWidth, zeroHeight,
            needed = 0,
            got = 0,
            ready, size, temp;

        
        

        
        

        if (widthModel.shrinkWrap && ownerContext.consumersContentWidth) {
            ++needed;
            zeroWidth = !(hv & 1);

            if (isContainer) {
                
                
                if (zeroWidth) {
                    ret.contentWidth = 0;
                    ret.gotWidth = true;
                    ++got;
                } else if ((ret.contentWidth = ownerContext.getProp('contentWidth')) !== undefined) {
                    ret.gotWidth = true;
                    ++got;
                }
            } else {
                size = props.contentWidth;

                if (typeof size == 'number') { 
                    ret.contentWidth = size;
                    ret.gotWidth = true;
                    ++got;
                } else {
                    if (zeroWidth) {
                        ready = true;
                    } else if (!ownerContext.hasDomProp('containerChildrenDone')) {
                        ready = false;
                    } else if (isBoxParent || !boxParent || boxParent.widthModel.shrinkWrap) {
                        
                        
                        
                        ready = true;
                    } else {
                        
                        
                        
                        ready = boxParent.hasDomProp('width');
                    }

                    if (ready) {
                        if (zeroWidth) {
                            temp = 0;
                        } else if (containerLayout && containerLayout.measureContentWidth) {
                            
                            
                            temp = containerLayout.measureContentWidth(ownerContext);
                        } else {
                            temp = me.measureContentWidth(ownerContext);
                        }

                        if (!isNaN(ret.contentWidth = temp)) {
                            ownerContext.setContentWidth(temp, true);
                            ret.gotWidth = true;
                            ++got;
                        }
                    }
                }
            }
        } else if (widthModel.natural && ownerContext.consumersWidth) {
            ++needed;
            size = props.width;
            

            if (typeof size == 'number') { 
                ret.width = size;
                ret.gotWidth = true;
                ++got;
            } else {
                if (isBoxParent || !boxParent) {
                    ready = true;
                } else {
                    
                    
                    
                    ready = boxParent.hasDomProp('width');
                }

                if (ready) {
                    if (!isNaN(ret.width = me.measureOwnerWidth(ownerContext))) {
                        ownerContext.setWidth(ret.width, false);
                        ret.gotWidth = true;
                        ++got;
                    }
                }
            }
        }

        
        

        if (heightModel.shrinkWrap && ownerContext.consumersContentHeight) {
            ++needed;
            zeroHeight = !(hv & 2);

            if (isContainer) {
                
                if (zeroHeight) {
                    ret.contentHeight = 0;
                    ret.gotHeight = true;
                    ++got;
                } else if ((ret.contentHeight = ownerContext.getProp('contentHeight')) !== undefined) {
                    ret.gotHeight = true;
                    ++got;
                }
            } else {
                size = props.contentHeight;

                if (typeof size == 'number') { 
                    ret.contentHeight = size;
                    ret.gotHeight = true;
                    ++got;
                } else {
                    if (zeroHeight) {
                        ready = true;
                    } else if (!ownerContext.hasDomProp('containerChildrenDone')) {
                        ready = false;
                    } else if (owner.noWrap) {
                        ready = true;
                    } else if (!widthModel.shrinkWrap) {
                        
                        ready = (ownerContext.bodyContext || ownerContext).hasDomProp('width');
                    } else if (isBoxParent || !boxParent || boxParent.widthModel.shrinkWrap) {
                        
                        
                        
                        ready = true;
                    } else {
                        
                        
                        
                        ready = boxParent.hasDomProp('width');
                    }

                    if (ready) {
                        if (zeroHeight) {
                            temp = 0;
                        } else if (containerLayout && containerLayout.measureContentHeight) {
                            
                            
                            temp = containerLayout.measureContentHeight(ownerContext);
                        } else {
                            temp = me.measureContentHeight(ownerContext);
                        }

                        if (!isNaN(ret.contentHeight = temp)) {
                            ownerContext.setContentHeight(temp, true);
                            ret.gotHeight = true;
                            ++got;
                        }
                    }
                }
            }
        } else if (heightModel.natural && ownerContext.consumersHeight) {
            ++needed;
            size = props.height;
            

            if (typeof size == 'number') { 
                ret.height = size;
                ret.gotHeight = true;
                ++got;
            } else {
                if (isBoxParent || !boxParent) {
                    ready = true;
                } else {
                    
                    
                    
                    ready = boxParent.hasDomProp('width');
                }

                if (ready) {
                    if (!isNaN(ret.height = me.measureOwnerHeight(ownerContext))) {
                        ownerContext.setHeight(ret.height, false);
                        ret.gotHeight = true;
                        ++got;
                    }
                }
            }
        }

        if (boxParent) {
            ownerContext.onBoxMeasured();
        }

        ret.gotAll = got == needed;
        
        return ret;
    },

    measureContentWidth: function (ownerContext) {
        
        return ownerContext.el.getWidth() - ownerContext.getFrameInfo().width;
    },

    measureContentHeight: function (ownerContext) {
        
        return ownerContext.el.getHeight() - ownerContext.getFrameInfo().height;
    },

    measureOwnerHeight: function (ownerContext) {
        return ownerContext.el.getHeight();
    },

    measureOwnerWidth: function (ownerContext) {
        return ownerContext.el.getWidth();
    }
});


Ext.define('Ext.layout.component.Auto', {

    

    alias: 'layout.autocomponent',

    extend: 'Ext.layout.component.Component',

    

    type: 'autocomponent',

    
    setHeightInDom: false,

    
    setWidthInDom: false,

    waitForOuterHeightInDom: false,
    waitForOuterWidthInDom: false,
    
    beginLayoutCycle: function(ownerContext, firstCycle){
        var me = this,
            lastWidthModel = me.lastWidthModel,
            lastHeightModel = me.lastHeightModel,
            owner = me.owner;
            
        me.callParent(arguments);
            
        if (lastWidthModel && lastWidthModel.fixed && ownerContext.widthModel.shrinkWrap) {
            owner.el.setWidth(null);
        }
            
        if (lastHeightModel && lastHeightModel.fixed && ownerContext.heightModel.shrinkWrap) {
            owner.el.setHeight(null);
        }    
    },

    calculate: function(ownerContext) {
        var me = this,
            measurement = me.measureAutoDimensions(ownerContext),
            heightModel = ownerContext.heightModel,
            widthModel = ownerContext.widthModel,
            width, height;

        
        
        if (measurement.gotWidth) {
            if (widthModel.shrinkWrap) {
                me.publishOwnerWidth(ownerContext, measurement.contentWidth);
            } else if (me.publishInnerWidth) {
                me.publishInnerWidth(ownerContext, measurement.width);
            }
        } else if (!widthModel.auto && me.publishInnerWidth) {
            width = me.waitForOuterWidthInDom ? ownerContext.getDomProp('width')
                        : ownerContext.getProp('width');
            if (width === undefined) {
                me.done = false;
            } else {
                me.publishInnerWidth(ownerContext, width);
            }
        }

        if (measurement.gotHeight) {
            if (heightModel.shrinkWrap) {
                me.publishOwnerHeight(ownerContext, measurement.contentHeight);
            } else if (me.publishInnerHeight) {
                me.publishInnerHeight(ownerContext, measurement.height);
            }
        } else if (!heightModel.auto && me.publishInnerHeight) {
            height = me.waitForOuterHeightInDom ? ownerContext.getDomProp('height')
                        : ownerContext.getProp('height');
            if (height === undefined) {
                me.done = false;
            } else {
               me.publishInnerHeight(ownerContext, height);
            }
        }

        if (!measurement.gotAll) {
            me.done = false;
        }
    },

    calculateOwnerHeightFromContentHeight: function (ownerContext, contentHeight) {
        return contentHeight + ownerContext.getFrameInfo().height;
    },

    calculateOwnerWidthFromContentWidth: function (ownerContext, contentWidth) {
        return contentWidth + ownerContext.getFrameInfo().width;
    },

    publishOwnerHeight: function (ownerContext, contentHeight) {
        var me = this,
            owner = me.owner,
            height = me.calculateOwnerHeightFromContentHeight(ownerContext, contentHeight),
            constrainedHeight, dirty, heightModel;

        if (isNaN(height)) {
            me.done = false;
        } else {
            constrainedHeight = Ext.Number.constrain(height, owner.minHeight, owner.maxHeight);

            if (constrainedHeight == height) {
                dirty = me.setHeightInDom;
            } else {
                heightModel = me.sizeModels[
                    (constrainedHeight < height) ? 'constrainedMax' : 'constrainedMin'];
                height = constrainedHeight;

                if (ownerContext.heightModel.calculatedFromShrinkWrap) {
                    
                    
                    
                    ownerContext.heightModel = heightModel;
                } else {
                    ownerContext.invalidate({ heightModel: heightModel });
                }
            }
            
            ownerContext.setHeight(height, dirty);
        }
    },

    publishOwnerWidth: function (ownerContext, contentWidth) {
        var me = this,
            owner = me.owner,
            width = me.calculateOwnerWidthFromContentWidth(ownerContext, contentWidth),
            constrainedWidth, dirty, widthModel;

        if (isNaN(width)) {
            me.done = false;
        } else {
            constrainedWidth = Ext.Number.constrain(width, owner.minWidth, owner.maxWidth);

            if (constrainedWidth == width) {
                dirty = me.setWidthInDom;
            } else {
                widthModel = me.sizeModels[
                    (constrainedWidth < width) ? 'constrainedMax' : 'constrainedMin'];
                width = constrainedWidth;

                if (ownerContext.widthModel.calculatedFromShrinkWrap) {
                    
                    
                    
                    ownerContext.widthModel = widthModel;
                } else {
                    ownerContext.invalidate({ widthModel: widthModel });
                }
            }

            ownerContext.setWidth(width, dirty);
        }
    }
});



Ext.define('Ext.layout.component.Draw', {

    

    alias: 'layout.draw',

    extend: 'Ext.layout.component.Auto',

    

    type: 'draw',
    
    measureContentWidth : function (ownerContext) {
        var target = ownerContext.target,
            paddingInfo = ownerContext.getPaddingInfo(),
            bbox = this.getBBox(ownerContext);
            
        if (!target.viewBox) {
            if (target.autoSize) {
                return bbox.width + paddingInfo.width;
            } else {
                return bbox.x + bbox.width + paddingInfo.width;
            }
        } else {
            if (ownerContext.heightModel.shrinkWrap) {
                return paddingInfo.width;
            } else {
                return bbox.width / bbox.height * (ownerContext.getProp('contentHeight') - paddingInfo.height) + paddingInfo.width;
            }
        }
    },
    
    measureContentHeight : function (ownerContext) {
        var target = ownerContext.target,
            paddingInfo = ownerContext.getPaddingInfo(),
            bbox = this.getBBox(ownerContext);
            
        if (!ownerContext.target.viewBox) {
            if (target.autoSize) {
                return bbox.height + paddingInfo.height;
            } else {
                return bbox.y + bbox.height + paddingInfo.height;
            }
        } else {
            if (ownerContext.widthModel.shrinkWrap) {
                return paddingInfo.height;
            } else {
                return bbox.height / bbox.width * (ownerContext.getProp('contentWidth') - paddingInfo.width) + paddingInfo.height;
            }
        }
    },
    
    getBBox: function(ownerContext) {
        var bbox = ownerContext.surfaceBBox;
        if (!bbox) {
            bbox = ownerContext.target.surface.items.getBBox();
            
            if (bbox.width === -Infinity && bbox.height === -Infinity) {
                bbox.width = bbox.height = bbox.x = bbox.y = 0;
            }
            ownerContext.surfaceBBox = bbox;
        }
        return bbox;
    },

    publishInnerWidth: function (ownerContext, width) {
        ownerContext.setContentWidth(width - ownerContext.getFrameInfo().width, true);
    },
    
    publishInnerHeight: function (ownerContext, height) {
        ownerContext.setContentHeight(height - ownerContext.getFrameInfo().height, true);
    },
    
    finishedLayout: function (ownerContext) {
        
        var props = ownerContext.props,
            paddingInfo = ownerContext.getPaddingInfo();

        
        
        this.owner.setSurfaceSize(props.contentWidth - paddingInfo.width, props.contentHeight - paddingInfo.height);
        
        
        this.callParent(arguments);
    }
});


Ext.define('Ext.state.Provider', {
    mixins: {
        observable: 'Ext.util.Observable'
    },
    
    
    prefix: 'ext-',
    
    constructor : function(config){
        config = config || {};
        var me = this;
        Ext.apply(me, config);
        
        me.addEvents("statechange");
        me.state = {};
        me.mixins.observable.constructor.call(me);
    },
    
    
    get : function(name, defaultValue){
        return typeof this.state[name] == "undefined" ?
            defaultValue : this.state[name];
    },

    
    clear : function(name){
        var me = this;
        delete me.state[name];
        me.fireEvent("statechange", me, name, null);
    },

    
    set : function(name, value){
        var me = this;
        me.state[name] = value;
        me.fireEvent("statechange", me, name, value);
    },

    
    decodeValue : function(value){

        
        
        
        
        
        
        

        var me = this,
            re = /^(a|n|d|b|s|o|e)\:(.*)$/,
            matches = re.exec(unescape(value)),
            all,
            type,
            keyValue,
            values,
            vLen,
            v;
            
        if(!matches || !matches[1]){
            return; 
        }
        
        type = matches[1];
        value = matches[2];
        switch (type) {
            case 'e':
                return null;
            case 'n':
                return parseFloat(value);
            case 'd':
                return new Date(Date.parse(value));
            case 'b':
                return (value == '1');
            case 'a':
                all = [];
                if(value != ''){
                    values = value.split('^');
                    vLen   = values.length;

                    for (v = 0; v < vLen; v++) {
                        value = values[v];
                        all.push(me.decodeValue(value));
                    }
                }
                return all;
           case 'o':
                all = {};
                if(value != ''){
                    values = value.split('^');
                    vLen   = values.length;

                    for (v = 0; v < vLen; v++) {
                        value = values[v];
                        keyValue         = value.split('=');
                        all[keyValue[0]] = me.decodeValue(keyValue[1]);
                    }
                }
                return all;
           default:
                return value;
        }
    },

    
    encodeValue : function(value){
        var flat = '',
            i = 0,
            enc,
            len,
            key;
            
        if (value == null) {
            return 'e:1';    
        } else if(typeof value == 'number') {
            enc = 'n:' + value;
        } else if(typeof value == 'boolean') {
            enc = 'b:' + (value ? '1' : '0');
        } else if(Ext.isDate(value)) {
            enc = 'd:' + value.toGMTString();
        } else if(Ext.isArray(value)) {
            for (len = value.length; i < len; i++) {
                flat += this.encodeValue(value[i]);
                if (i != len - 1) {
                    flat += '^';
                }
            }
            enc = 'a:' + flat;
        } else if (typeof value == 'object') {
            for (key in value) {
                if (typeof value[key] != 'function' && value[key] !== undefined) {
                    flat += key + '=' + this.encodeValue(value[key]) + '^';
                }
            }
            enc = 'o:' + flat.substring(0, flat.length-1);
        } else {
            enc = 's:' + value;
        }
        return escape(enc);
    }
});

Ext.define('Ext.state.CookieProvider', {
    extend: 'Ext.state.Provider',

    

    

    

    

    
    constructor : function(config){
        var me = this;
        me.path = "/";
        me.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); 
        me.domain = null;
        me.secure = false;
        me.callParent(arguments);
        me.state = me.readCookies();
    },

    
    set : function(name, value){
        var me = this;

        if(typeof value == "undefined" || value === null){
            me.clear(name);
            return;
        }
        me.setCookie(name, value);
        me.callParent(arguments);
    },

    
    clear : function(name){
        this.clearCookie(name);
        this.callParent(arguments);
    },

    
    readCookies : function(){
        var cookies = {},
            c = document.cookie + ";",
            re = /\s?(.*?)=(.*?);/g,
            prefix = this.prefix,
            len = prefix.length,
            matches,
            name,
            value;

        while((matches = re.exec(c)) != null){
            name = matches[1];
            value = matches[2];
            if (name && name.substring(0, len) == prefix){
                cookies[name.substr(len)] = this.decodeValue(value);
            }
        }
        return cookies;
    },

    
    setCookie : function(name, value){
        var me = this;

        document.cookie = me.prefix + name + "=" + me.encodeValue(value) +
           ((me.expires == null) ? "" : ("; expires=" + me.expires.toGMTString())) +
           ((me.path == null) ? "" : ("; path=" + me.path)) +
           ((me.domain == null) ? "" : ("; domain=" + me.domain)) +
           ((me.secure == true) ? "; secure" : "");
    },

    
    clearCookie : function(name){
        var me = this;

        document.cookie = me.prefix + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
           ((me.path == null) ? "" : ("; path=" + me.path)) +
           ((me.domain == null) ? "" : ("; domain=" + me.domain)) +
           ((me.secure == true) ? "; secure" : "");
    }
});



Ext.define('Ext.state.LocalStorageProvider', {
    
    
    extend: 'Ext.state.Provider',
    
    alias: 'state.localstorage',
    
    
   
    constructor: function(){
        var me = this;
        me.callParent(arguments);
        me.store = me.getStorageObject();
        me.state = me.readLocalStorage();
    },
    
    readLocalStorage: function(){
        var store = this.store,
            i = 0,
            len = store.length,
            prefix = this.prefix,
            prefixLen = prefix.length,
            data = {},
            key;
            
        for (; i < len; ++i) {
            key = store.key(i);
            if (key.substring(0, prefixLen) == prefix) {
                data[key.substr(prefixLen)] = this.decodeValue(store.getItem(key));
            }            
        }
        return data;
    },
    
    set : function(name, value){
        var me = this;
        
        me.clear(name);
        if (typeof value == "undefined" || value === null) {
            return;
        }
        me.store.setItem(me.prefix + name, me.encodeValue(value));
        me.callParent(arguments);
    },

    
    clear : function(name){
        this.store.removeItem(this.prefix + name);
        this.callParent(arguments);
    },
    
    getStorageObject: function(){
        try {
            var supports = 'localStorage' in window && window['localStorage'] !== null;
            if (supports) {
                return window.localStorage;
            }
        } catch (e) {
            return false;
        }
    }    
});


Ext.define('Ext.state.Manager', {
    singleton: true,
    requires: ['Ext.state.Provider'],
    constructor: function() {
        this.provider = new Ext.state.Provider();
    },
    
    
    
    setProvider : function(stateProvider){
        this.provider = stateProvider;
    },

    
    get : function(key, defaultValue){
        return this.provider.get(key, defaultValue);
    },

    
     set : function(key, value){
        this.provider.set(key, value);
    },

    
    clear : function(key){
        this.provider.clear(key);
    },

    
    getProvider : function(){
        return this.provider;
    }
});

Ext.define('Ext.state.Stateful', {

    

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: ['Ext.state.Manager'],

    

    
    stateful: false,

    

    

    
    saveDelay: 100,

    constructor: function(config) {
        var me = this;

        config = config || {};
        if (config.stateful !== undefined) {
            me.stateful = config.stateful;
        }
        if (config.saveDelay !== undefined) {
            me.saveDelay = config.saveDelay;
        }
        me.stateId = me.stateId || config.stateId;

        if (!me.stateEvents) {
            me.stateEvents = [];
        }
        if (config.stateEvents) {
            me.stateEvents.concat(config.stateEvents);
        }
        this.addEvents(
            
            'beforestaterestore',

            
            'staterestore',

            
            'beforestatesave',

            
            'statesave'
        );
        me.mixins.observable.constructor.call(me);

        if (me.stateful !== false) {
            me.addStateEvents(me.stateEvents);
            me.initState();
        }
    },

    
    addStateEvents: function (events) {
        var me = this,
            i, event, stateEventsByName;

        if (me.stateful && me.getStateId()) {
            if (typeof events == 'string') {
                events = Array.prototype.slice.call(arguments, 0);
            }

            stateEventsByName = me.stateEventsByName || (me.stateEventsByName = {});

            for (i = events.length; i--; ) {
                event = events[i];

                if (!stateEventsByName[event]) {
                    stateEventsByName[event] = 1;
                    me.on(event, me.onStateChange, me);
                }
            }
        }
    },

    
    onStateChange: function(){
        var me = this,
            delay = me.saveDelay,
            statics, runner;

        if (!me.stateful) {
            return;
        }

        if (delay) {
            if (!me.stateTask) {
                statics = Ext.state.Stateful;
                runner = statics.runner || (statics.runner = new Ext.util.TaskRunner());

                me.stateTask = runner.newTask({
                    run: me.saveState,
                    scope: me,
                    interval: delay,
                    repeat: 1
                });
            }

            me.stateTask.start();
        } else {
            me.saveState();
        }
    },

    
    saveState: function() {
        var me = this,
            id = me.stateful && me.getStateId(),
            hasListeners = me.hasListeners,
            state;

        if (id) {
            state = me.getState() || {};    
            if (!hasListeners.beforestatesave || me.fireEvent('beforestatesave', me, state) !== false) {
                Ext.state.Manager.set(id, state);
                if (hasListeners.statesave) {
                    me.fireEvent('statesave', me, state);
                }
            }
        }
    },

    
    getState: function(){
        return null;
    },

    
    applyState: function(state) {
        if (state) {
            Ext.apply(this, state);
        }
    },

    
    getStateId: function() {
        var me = this;
        return me.stateId || (me.autoGenId ? null : me.id);
    },

    
    initState: function(){
        var me = this,
            id = me.stateful && me.getStateId(),
            hasListeners = me.hasListeners,
            state;

        if (id) {
            state = Ext.state.Manager.get(id);
            if (state) {
                state = Ext.apply({}, state);
                if (!hasListeners.beforestaterestore || me.fireEvent('beforestaterestore', me, state) !== false) {
                    me.applyState(state);
                    if (hasListeners.staterestore) {
                        me.fireEvent('staterestore', me, state);
                    }
                }
            }
        }
    },

    
    savePropToState: function (propName, state, stateName) {
        var me = this,
            value = me[propName],
            config = me.initialConfig;

        if (me.hasOwnProperty(propName)) {
            if (!config || config[propName] !== value) {
                if (state) {
                    state[stateName || propName] = value;
                }
                return true;
            }
        }
        return false;
    },

    
    savePropsToState: function (propNames, state) {
        var me = this,
            i, n;

        if (typeof propNames == 'string') {
            me.savePropToState(propNames, state);
        } else {
            for (i = 0, n = propNames.length; i < n; ++i) {
                me.savePropToState(propNames[i], state);
            }
        }

        return state;
    },

    
    destroy: function(){
        var me = this,
            task = me.stateTask;

        if (task) {
            task.destroy();
            me.stateTask = null;
        }

        me.clearListeners();
    }
});


Ext.define('Ext.util.AbstractMixedCollection', {
    requires: ['Ext.util.Filter'],

    mixins: {
        observable: 'Ext.util.Observable'
    },

    
    isMixedCollection: true,

    
    generation: 0,

    constructor: function(allowFunctions, keyFn) {
        var me = this;

        me.items = [];
        me.map = {};
        me.keys = [];
        me.length = 0;

            

            

            
            

        me.allowFunctions = allowFunctions === true;

        if (keyFn) {
            me.getKey = keyFn;
        }

        me.mixins.observable.constructor.call(me);
    },

    
    allowFunctions : false,

    
    add : function(key, obj){
        var me = this,
            myObj = obj,
            myKey = key,
            old;

        if (arguments.length == 1) {
            myObj = myKey;
            myKey = me.getKey(myObj);
        }
        if (typeof myKey != 'undefined' && myKey !== null) {
            old = me.map[myKey];
            if (typeof old != 'undefined') {
                return me.replace(myKey, myObj);
            }
            me.map[myKey] = myObj;
        }
        me.generation++;
        me.length++;
        me.items.push(myObj);
        me.keys.push(myKey);
        if (me.hasListeners.add) {
            me.fireEvent('add', me.length - 1, myObj, myKey);
        }
        return myObj;
    },

    
    getKey : function(o){
         return o.id;
    },

    
    replace : function(key, o){
        var me = this,
            old,
            index;

        if (arguments.length == 1) {
            o = arguments[0];
            key = me.getKey(o);
        }
        old = me.map[key];
        if (typeof key == 'undefined' || key === null || typeof old == 'undefined') {
             return me.add(key, o);
        }
        me.generation++;
        index = me.indexOfKey(key);
        me.items[index] = o;
        me.map[key] = o;
        if (me.hasListeners.replace) {
            me.fireEvent('replace', key, old, o);
        }
        return o;
    },

    
    addAll : function(objs){
        var me = this,
            i = 0,
            args,
            len,
            key;

        if (arguments.length > 1 || Ext.isArray(objs)) {
            args = arguments.length > 1 ? arguments : objs;
            for (len = args.length; i < len; i++) {
                me.add(args[i]);
            }
        } else {
            for (key in objs) {
                if (objs.hasOwnProperty(key)) {
                    if (me.allowFunctions || typeof objs[key] != 'function') {
                        me.add(key, objs[key]);
                    }
                }
            }
        }
    },

    
    each : function(fn, scope){
        var items = [].concat(this.items), 
            i = 0,
            len = items.length,
            item;

        for (; i < len; i++) {
            item = items[i];
            if (fn.call(scope || item, item, i, len) === false) {
                break;
            }
        }
    },

    
    eachKey : function(fn, scope){
        var keys = this.keys,
            items = this.items,
            i = 0,
            len = keys.length;

        for (; i < len; i++) {
            fn.call(scope || window, keys[i], items[i], i, len);
        }
    },

    
    findBy : function(fn, scope) {
        var keys = this.keys,
            items = this.items,
            i = 0,
            len = items.length;

        for (; i < len; i++) {
            if (fn.call(scope || window, items[i], keys[i])) {
                return items[i];
            }
        }
        return null;
    },

    find : function() {
        if (Ext.isDefined(Ext.global.console)) {
            Ext.global.console.warn('Ext.util.MixedCollection: find has been deprecated. Use findBy instead.');
        }
        return this.findBy.apply(this, arguments);
    },

    
    insert : function(index, key, obj){
        var me = this,
            myKey = key,
            myObj = obj;

        if (arguments.length == 2) {
            myObj = myKey;
            myKey = me.getKey(myObj);
        }
        if (me.containsKey(myKey)) {
            me.suspendEvents();
            me.removeAtKey(myKey);
            me.resumeEvents();
        }
        if (index >= me.length) {
            return me.add(myKey, myObj);
        }
        me.generation++;
        me.length++;
        Ext.Array.splice(me.items, index, 0, myObj);
        if (typeof myKey != 'undefined' && myKey !== null) {
            me.map[myKey] = myObj;
        }
        Ext.Array.splice(me.keys, index, 0, myKey);
        if (me.hasListeners.add) {
            me.fireEvent('add', index, myObj, myKey);
        }
        return myObj;
    },

    
    remove : function(o) {
        this.generation++;
        return this.removeAt(this.indexOf(o));
    },

    
    removeAll : function(items) {
        items = [].concat(items);
        var i, iLen = items.length;
        for (i = 0; i < iLen; i++) {
            this.remove(items[i]);
        }

        return this;
    },

    
    removeAt : function(index) {
        var me = this,
            o,
            key;

        if (index < me.length && index >= 0) {
            me.length--;
            o = me.items[index];
            Ext.Array.erase(me.items, index, 1);
            key = me.keys[index];
            if (typeof key != 'undefined') {
                delete me.map[key];
            }
            Ext.Array.erase(me.keys, index, 1);
            if (me.hasListeners.remove) {
                me.fireEvent('remove', o, key);
            }
            me.generation++;
            return o;
        }
        return false;
    },

    
    removeAtKey : function(key){
        return this.removeAt(this.indexOfKey(key));
    },

    
    getCount : function(){
        return this.length;
    },

    
    indexOf : function(o){
        return Ext.Array.indexOf(this.items, o);
    },

    
    indexOfKey : function(key){
        return Ext.Array.indexOf(this.keys, key);
    },

    
    get : function(key) {
        var me = this,
            mk = me.map[key],
            item = mk !== undefined ? mk : (typeof key == 'number') ? me.items[key] : undefined;
        return typeof item != 'function' || me.allowFunctions ? item : null; 
    },

    
    getAt : function(index) {
        return this.items[index];
    },

    
    getByKey : function(key) {
        return this.map[key];
    },

    
    contains : function(o){
        return typeof this.map[this.getKey(o)] != 'undefined';
    },

    
    containsKey : function(key){
        return typeof this.map[key] != 'undefined';
    },

    
    clear : function(){
        var me = this;

        me.length = 0;
        me.items = [];
        me.keys = [];
        me.map = {};
        me.generation++;
        if (me.hasListeners.clear) {
            me.fireEvent('clear');
        }
    },

    
    first : function() {
        return this.items[0];
    },

    
    last : function() {
        return this.items[this.length - 1];
    },

    
    sum: function(property, root, start, end) {
        var values = this.extractValues(property, root),
            length = values.length,
            sum    = 0,
            i;

        start = start || 0;
        end   = (end || end === 0) ? end : length - 1;

        for (i = start; i <= end; i++) {
            sum += values[i];
        }

        return sum;
    },

    
    collect: function(property, root, allowNull) {
        var values = this.extractValues(property, root),
            length = values.length,
            hits   = {},
            unique = [],
            value, strValue, i;

        for (i = 0; i < length; i++) {
            value = values[i];
            strValue = String(value);

            if ((allowNull || !Ext.isEmpty(value)) && !hits[strValue]) {
                hits[strValue] = true;
                unique.push(value);
            }
        }

        return unique;
    },

    
    extractValues: function(property, root) {
        var values = this.items;

        if (root) {
            values = Ext.Array.pluck(values, root);
        }

        return Ext.Array.pluck(values, property);
    },

    
    getRange : function(start, end){
        var me = this,
            items = me.items,
            range = [],
            i;

        if (items.length < 1) {
            return range;
        }

        start = start || 0;
        end = Math.min(typeof end == 'undefined' ? me.length - 1 : end, me.length - 1);
        if (start <= end) {
            for (i = start; i <= end; i++) {
                range[range.length] = items[i];
            }
        } else {
            for (i = start; i >= end; i--) {
                range[range.length] = items[i];
            }
        }
        return range;
    },

    
    filter : function(property, value, anyMatch, caseSensitive) {
        var filters = [],
            filterFn;

        
        if (Ext.isString(property)) {
            filters.push(new Ext.util.Filter({
                property     : property,
                value        : value,
                anyMatch     : anyMatch,
                caseSensitive: caseSensitive
            }));
        } else if (Ext.isArray(property) || property instanceof Ext.util.Filter) {
            filters = filters.concat(property);
        }

        
        
        filterFn = function(record) {
            var isMatch = true,
                length = filters.length,
                i,
                filter,
                fn,
                scope;
                

            for (i = 0; i < length; i++) {
                filter = filters[i];
                fn     = filter.filterFn;
                scope  = filter.scope;

                isMatch = isMatch && fn.call(scope, record);
            }

            return isMatch;
        };

        return this.filterBy(filterFn);
    },

    
    filterBy : function(fn, scope) {
        var me = this,
            newMC  = new this.self(),
            keys   = me.keys,
            items  = me.items,
            length = items.length,
            i;

        newMC.getKey = me.getKey;

        for (i = 0; i < length; i++) {
            if (fn.call(scope || me, items[i], keys[i])) {
                newMC.add(keys[i], items[i]);
            }
        }

        return newMC;
    },

    
    findIndex : function(property, value, start, anyMatch, caseSensitive){
        if(Ext.isEmpty(value, false)){
            return -1;
        }
        value = this.createValueMatcher(value, anyMatch, caseSensitive);
        return this.findIndexBy(function(o){
            return o && value.test(o[property]);
        }, null, start);
    },

    
    findIndexBy : function(fn, scope, start){
        var me = this,
            keys = me.keys,
            items = me.items,
            i = start || 0,
            len = items.length;

        for (; i < len; i++) {
            if (fn.call(scope || me, items[i], keys[i])) {
                return i;
            }
        }
        return -1;
    },

    
    createValueMatcher : function(value, anyMatch, caseSensitive, exactMatch) {
        if (!value.exec) { 
            var er = Ext.String.escapeRegex;
            value = String(value);

            if (anyMatch === true) {
                value = er(value);
            } else {
                value = '^' + er(value);
                if (exactMatch === true) {
                    value += '$';
                }
            }
            value = new RegExp(value, caseSensitive ? '' : 'i');
        }
        return value;
    },

    
    clone : function() {
        var me = this,
            copy = new this.self(),
            keys = me.keys,
            items = me.items,
            i = 0,
            len = items.length;

        for(; i < len; i++){
            copy.add(keys[i], items[i]);
        }
        copy.getKey = me.getKey;
        return copy;
    }
});


 
Ext.define('Ext.util.Grouper', {

    

    extend: 'Ext.util.Sorter',

    
   
   isGrouper: true,

    
    getGroupString: function(instance) {
        return instance.get(this.property);
    }
});

Ext.define('Ext.util.HashMap', {
    mixins: {
        observable: 'Ext.util.Observable'
    },

    

    
    constructor: function(config) {
        config = config || {};

        var me = this,
            keyFn = config.keyFn;

        me.addEvents(
            
            'add',
            
            'clear',
            
            'remove',
            
            'replace'
        );

        me.mixins.observable.constructor.call(me, config);
        me.clear(true);

        if (keyFn) {
            me.getKey = keyFn;
        }
    },

    
    getCount: function() {
        return this.length;
    },

    
    getData: function(key, value) {
        
        if (value === undefined) {
            value = key;
            key = this.getKey(value);
        }

        return [key, value];
    },

    
    getKey: function(o) {
        return o.id;
    },

    
    add: function(key, value) {
        var me = this;

        if (value === undefined) {
            value = key;
            key = me.getKey(value);
        }

        if (me.containsKey(key)) {
            return me.replace(key, value);
        }

        me.map[key] = value;
        ++me.length;
        if (me.hasListeners.add) {
            me.fireEvent('add', me, key, value);
        }
        return value;
    },

    
    replace: function(key, value) {
        var me = this,
            map = me.map,
            old;

        if (value === undefined) {
            value = key;
            key = me.getKey(value);
        }

        if (!me.containsKey(key)) {
            me.add(key, value);
        }
        old = map[key];
        map[key] = value;
        if (me.hasListeners.replace) {
            me.fireEvent('replace', me, key, value, old);
        }
        return value;
    },

    
    remove: function(o) {
        var key = this.findKey(o);
        if (key !== undefined) {
            return this.removeAtKey(key);
        }
        return false;
    },

    
    removeAtKey: function(key) {
        var me = this,
            value;

        if (me.containsKey(key)) {
            value = me.map[key];
            delete me.map[key];
            --me.length;
            if (me.hasListeners.remove) {
                me.fireEvent('remove', me, key, value);
            }
            return true;
        }
        return false;
    },

    
    get: function(key) {
        return this.map[key];
    },

    
    clear: function( initial) {
        var me = this;
        me.map = {};
        me.length = 0;
        if (initial !== true && me.hasListeners.clear) {
            me.fireEvent('clear', me);
        }
        return me;
    },

    
    containsKey: function(key) {
        return this.map[key] !== undefined;
    },

    
    contains: function(value) {
        return this.containsKey(this.findKey(value));
    },

    
    getKeys: function() {
        return this.getArray(true);
    },

    
    getValues: function() {
        return this.getArray(false);
    },

    
    getArray: function(isKey) {
        var arr = [],
            key,
            map = this.map;
        for (key in map) {
            if (map.hasOwnProperty(key)) {
                arr.push(isKey ? key: map[key]);
            }
        }
        return arr;
    },

    
    each: function(fn, scope) {
        
        var items = Ext.apply({}, this.map),
            key,
            length = this.length;

        scope = scope || this;
        for (key in items) {
            if (items.hasOwnProperty(key)) {
                if (fn.call(scope, key, items[key], length) === false) {
                    break;
                }
            }
        }
        return this;
    },

    
    clone: function() {
        var hash = new this.self(),
            map = this.map,
            key;

        hash.suspendEvents();
        for (key in map) {
            if (map.hasOwnProperty(key)) {
                hash.add(key, map[key]);
            }
        }
        hash.resumeEvents();
        return hash;
    },

    
    findKey: function(value) {
        var key,
            map = this.map;

        for (key in map) {
            if (map.hasOwnProperty(key) && map[key] === value) {
                return key;
            }
        }
        return undefined;
    }
});


Ext.define('Ext.AbstractManager', {

    

    requires: ['Ext.util.HashMap'],

    

    typeName: 'type',

    constructor: function(config) {
        Ext.apply(this, config || {});

        
        this.all = new Ext.util.HashMap();

        this.types = {};
    },

    
    get : function(id) {
        return this.all.get(id);
    },

    
    register: function(item) {
        this.all.add(item);
    },

    
    unregister: function(item) {
        this.all.remove(item);
    },

    
    registerType : function(type, cls) {
        this.types[type] = cls;
        cls[this.typeName] = type;
    },

    
    isRegistered : function(type){
        return this.types[type] !== undefined;
    },

    
    create: function(config, defaultType) {
        var type        = config[this.typeName] || config.type || defaultType,
            Constructor = this.types[type];


        return new Constructor(config);
    },

    
    onAvailable : function(id, fn, scope){
        var all = this.all,
            item,
            callback;
        
        if (all.containsKey(id)) {
            item = all.get(id);
            fn.call(scope || item, item);
        } else {
            callback = function(map, key, item){
                if (key == id) {
                    fn.call(scope || item, item);
                    all.un('add', callback);
                }
            }; 
            all.on('add', callback);
        }
    },
    
    
    each: function(fn, scope){
        this.all.each(fn, scope || this);    
    },
    
    
    getCount: function(){
        return this.all.getCount();
    }
});


Ext.define('Ext.ComponentManager', {
    extend: 'Ext.AbstractManager',
    alternateClassName: 'Ext.ComponentMgr',
    
    singleton: true,
    
    typeName: 'xtype',
    
    
    create: function(component, defaultType){
        if (typeof component == 'string') {
            return Ext.widget(component);
        }
        if (component.isComponent) {
            return component;
        }
        return Ext.widget(component.xtype || defaultType, component);
    },

    registerType: function(type, cls) {
        this.types[type] = cls;
        cls[this.typeName] = type;
        cls.prototype[this.typeName] = type;
    }
});

Ext.define('Ext.AbstractComponent', {

    
    requires: [
        'Ext.ComponentQuery',
        'Ext.ComponentManager',
        'Ext.util.ProtoElement'
    ],

    mixins: {
        observable: 'Ext.util.Observable',
        animate: 'Ext.util.Animate',
        elementCt: 'Ext.util.ElementContainer',
        renderable: 'Ext.util.Renderable',
        state: 'Ext.state.Stateful'
    },

    
    
    uses: [
        'Ext.PluginManager',
        'Ext.Element',
        'Ext.DomHelper',
        'Ext.XTemplate',
        'Ext.ComponentQuery',
        'Ext.ComponentLoader',
        'Ext.EventManager',
        'Ext.layout.Context',
        'Ext.layout.Layout',
        'Ext.layout.component.Auto',
        'Ext.LoadMask',
        'Ext.ZIndexManager'
    ],

    statics: {
        AUTO_ID: 1000,

        pendingLayouts: null,

        layoutSuspendCount: 0,

        
        cancelLayout: function(comp, isDestroying) {
            var context = this.runningLayoutContext || this.pendingLayouts;

            if (context) {
                context.cancelComponent(comp, false, isDestroying);
            }
        },

        
        flushLayouts: function () {
            var me = this,
                context = me.pendingLayouts;

            if (context && context.invalidQueue.length) {
                me.pendingLayouts = null;
                me.runningLayoutContext = context;

                Ext.override(context, {
                    runComplete: function () {
                        
                        
                        
                        me.runningLayoutContext = null;

                        return this.callParent(); 
                    }
                });

                context.run();
            }
        },

        
        resumeLayouts: function (flush) {
            if (this.layoutSuspendCount && ! --this.layoutSuspendCount) {
                if (flush) {
                    this.flushLayouts();
                }
            }
        },

        
        suspendLayouts: function () {
            ++this.layoutSuspendCount;
        },

        
        updateLayout: function (comp, defer) {
            var me = this,
                running = me.runningLayoutContext,
                pending;

            if (running) {
                running.queueInvalidate(comp);
            } else {
                pending = me.pendingLayouts || (me.pendingLayouts = new Ext.layout.Context());
                pending.queueInvalidate(comp);

                if (!defer && !me.layoutSuspendCount && !comp.isLayoutSuspended()) {
                    me.flushLayouts();
                }
            }
        }
    },

    

    
    isComponent: true,

    
    getAutoId: function() {
        this.autoGenId = true;
        return ++Ext.AbstractComponent.AUTO_ID;
    },

    deferLayouts: false,

    

     
    autoGenId: false,

    

    

    

    
    renderTpl: '{%this.renderContent(out,values)%}',

    

    

    

    

    

    
    frameSize: { left: 0, top: 0, right: 0, bottom: 0, width: 0, height: 0 },

    

    

    

    

    
    tplWriteMode: 'overwrite',

    
    baseCls: Ext.baseCSSPrefix + 'component',

    

    

    

    
    disabledCls: Ext.baseCSSPrefix + 'item-disabled',

    
    ui: 'default',

    
    uiCls: [],

    

    

    

    

    

    

    
    hidden: false,

    
    disabled: false,

    

    
    draggable: false,

    
    floating: false,

    
    hideMode: 'display',

    

    

    
    styleHtmlContent: false,

    
    styleHtmlCls: Ext.baseCSSPrefix + 'html',

    
    
    
    

    

    

    
    autoShow: false,

    
    autoRender: false,

    
    allowDomMove: true,

    

    
    rendered: false,

    
    componentLayoutCounter: 0,

    
    shrinkWrap: 2,

    weight: 0,

    
    maskOnDisable: true,

    
    _isLayoutRoot: false,

    
    constructor : function(config) {
        var me = this,
            i, len, xhooks;

        if (config) {
            Ext.apply(me, config);

            xhooks = me.xhooks;
            if (xhooks) {
                delete me.xhooks;
                Ext.override(me, xhooks);
            }
        } else {
            config = {};
        }

        me.initialConfig = config;

        me.mixins.elementCt.constructor.call(me);

        me.addEvents(
            
            'beforeactivate',
            
            'activate',
            
            'beforedeactivate',
            
            'deactivate',
            
            'added',
            
            'disable',
            
            'enable',
            
            'beforeshow',
            
            'show',
            
            'beforehide',
            
            'hide',
            
            'removed',
            
            'beforerender',
            
            'render',
            
            'afterrender',
            
            'boxready',
            
            'beforedestroy',
            
            'destroy',
            
            'resize',
            
             'move',
            
            'focus',
            
            'blur'
        );

        me.getId();

        me.setupProtoEl();

        
        
        if (me.cls) {
            me.initialCls = me.cls;
            me.protoEl.addCls(me.cls);
        }
        if (me.style) {
            me.initialStyle = me.style;
            me.protoEl.setStyle(me.style);
        }

        me.mons = [];
        me.renderData = me.renderData || {};
        me.renderSelectors = me.renderSelectors || {};

        if (me.plugins) {
            me.plugins = me.constructPlugins();
        }

        
        if (!me.hasListeners) {
            me.hasListeners = new me.HasListeners();
        }

        me.initComponent();

        
        Ext.ComponentManager.register(me);

        
        me.mixins.observable.constructor.call(me);
        me.mixins.state.constructor.call(me, config);

        
        this.addStateEvents('resize');

        
        if (me.plugins) {
            for (i = 0, len = me.plugins.length; i < len; i++) {
                me.plugins[i] = me.initPlugin(me.plugins[i]);
            }
        }

        me.loader = me.getLoader();

        if (me.renderTo) {
            me.render(me.renderTo);
            
            
            
        }

        
        
        if (me.autoShow && !me.isContained) {
            me.show();
        }

    },

    initComponent: function () {
        
        
        this.plugins = this.constructPlugins();

        
        
        this.setSize(this.width, this.height);
    },

    
    getState: function() {
        var me = this,
            state = null,
            sizeModel = me.getSizeModel();

        if (sizeModel.width.configured) {
            state = me.addPropertyToState(state, 'width');
        }
        if (sizeModel.height.configured) {
            state = me.addPropertyToState(state, 'height');
        }

        return state;
    },

    
    addPropertyToState: function (state, propName, value) {
        var me = this,
            len = arguments.length;

        
        
        if (len == 3 || me.hasOwnProperty(propName)) {
            if (len < 3) {
                value = me[propName];
            }

            
            
            if (value !== me.initialConfig[propName]) {
                (state || (state = {}))[propName] = value;
            }
        }

        return state;
    },

    show: Ext.emptyFn,

    animate: function(animObj) {
        var me = this,
            hasToWidth,
            hasToHeight,
            toHeight,
            toWidth,
            to,
            clearWidth,
            clearHeight,
            curWidth, w, curHeight, h, needsResize;

        animObj = animObj || {};
        to = animObj.to || {};

        if (Ext.fx.Manager.hasFxBlock(me.id)) {
            return me;
        }

        hasToWidth = Ext.isDefined(to.width);
        if (hasToWidth) {
            toWidth = Ext.Number.constrain(to.width, me.minWidth, me.maxWidth);
        }

        hasToHeight = Ext.isDefined(to.height);
        if (hasToHeight) {
            toHeight = Ext.Number.constrain(to.height, me.minHeight, me.maxHeight);
        }

        
        if (!animObj.dynamic && (hasToWidth || hasToHeight)) {
            curWidth = (animObj.from ? animObj.from.width : undefined) || me.getWidth();
            w = curWidth;
            curHeight = (animObj.from ? animObj.from.height : undefined) || me.getHeight();
            h = curHeight;
            needsResize = false;

            if (hasToHeight && toHeight > curHeight) {
                h = toHeight;
                needsResize = true;
            }
            if (hasToWidth && toWidth > curWidth) {
                w = toWidth;
                needsResize = true;
            }

            
            
            
            if (needsResize) {
                clearWidth = !Ext.isNumber(me.width);
                clearHeight = !Ext.isNumber(me.height);

                me.setSize(w, h);
                me.el.setSize(curWidth, curHeight);
                if (clearWidth) {
                    delete me.width;
                }
                if (clearHeight) {
                    delete me.height;
                }
            }
            if (hasToWidth) {
                to.width = toWidth;
            }

            if (hasToHeight) {
                to.height = toHeight;
            }
        }
        return me.mixins.animate.animate.apply(me, arguments);
    },

    onHide: function() {
        this.updateLayout({ isRoot: false });
    },

    onShow : function() {
        this.updateLayout({ isRoot: false });
    },

    constructPlugin: function(plugin) {
        
        
        if (plugin.ptype && typeof plugin.init != 'function') {
            plugin.cmp = this;
            plugin = Ext.PluginManager.create(plugin);
        }
        
        else if (typeof plugin == 'string') {
            plugin = Ext.PluginManager.create({
                ptype: plugin,
                cmp: this
            });
        }
        return plugin;
    },

    
    constructPlugins: function() {
        var me = this,
            plugins,
            result = [],
            i, len;

        if (me.plugins) {
            plugins = Ext.isArray(me.plugins) ? me.plugins : [ me.plugins ];
            for (i = 0, len = plugins.length; i < len; i++) {
                
                result[i] = me.constructPlugin(plugins[i]);
            }
            return result;
        }
    },

    
    initPlugin : function(plugin) {
        plugin.init(this);

        return plugin;
    },

    
    updateAria: Ext.emptyFn,

    
    registerFloatingItem: function(cmp) {
        var me = this;
        if (!me.floatingDescendants) {
            me.floatingDescendants = new Ext.ZIndexManager(me);
        }
        me.floatingDescendants.register(cmp);
    },

    unregisterFloatingItem: function(cmp) {
        var me = this;
        if (me.floatingDescendants) {
            me.floatingDescendants.unregister(cmp);
        }
    },

    layoutSuspendCount: 0,

    suspendLayouts: function () {
        var me = this;
        if (!me.rendered) {
            return;
        }
        if (++me.layoutSuspendCount == 1) {
            me.suspendLayout = true;
        }
    },

    resumeLayouts: function (flushOptions) {
        var me = this;
        if (!me.rendered) {
            return;
        }
        if (! --me.layoutSuspendCount) {
            me.suspendLayout = false;
            if (flushOptions && !me.isLayoutSuspended()) {
                me.updateLayout(flushOptions);
            }
        }
    },

    setupProtoEl: function() {
        var me = this,
            cls = [ me.baseCls, me.getComponentLayout().targetCls ];

        if (Ext.isDefined(me.cmpCls)) {
            if (Ext.isDefined(Ext.global.console)) {
                Ext.global.console.warn('Ext.Component: cmpCls has been deprecated. Please use componentCls.');
            }
            me.componentCls = me.cmpCls;
            delete me.cmpCls;
        }

        if (me.componentCls) {
            cls.push(me.componentCls);
        } else {
            me.componentCls = me.baseCls;
        }

        me.protoEl = new Ext.util.ProtoElement({
            cls: cls.join(' ') 
        });
    },

    
    setUI: function(ui) {
        var me = this,
            oldUICls = Ext.Array.clone(me.uiCls),
            newUICls = [],
            classes = [],
            cls,
            i;

        
        for (i = 0; i < oldUICls.length; i++) {
            cls = oldUICls[i];

            classes = classes.concat(me.removeClsWithUI(cls, true));
            newUICls.push(cls);
        }

        if (classes.length) {
            me.removeCls(classes);
        }

        
        me.removeUIFromElement();

        
        me.ui = ui;

        
        me.addUIToElement();

        
        classes = [];
        for (i = 0; i < newUICls.length; i++) {
            cls = newUICls[i];
            classes = classes.concat(me.addClsWithUI(cls, true));
        }

        if (classes.length) {
            me.addCls(classes);
        }

        
        
        
        if (me.rendered) {
            me.updateLayout();
        }
    },

    
    addClsWithUI: function(classes, skip) {
        var me = this,
            clsArray = [],
            length,
            i = 0,
            cls;

        if (typeof classes === "string") {
            classes = (classes.indexOf(' ') < 0) ? [classes] : Ext.String.splitWords(classes);
        }

        length = classes.length;

        me.uiCls = Ext.Array.clone(me.uiCls);

        for (; i < length; i++) {
            cls = classes[i];
            if (cls && !me.hasUICls(cls)) {
                me.uiCls.push(cls);
                clsArray = clsArray.concat(me.addUIClsToElement(cls));
            }
        }

        if (skip !== true) {
            me.addCls(clsArray);
        }

        return clsArray;
    },

    
    removeClsWithUI: function(classes, skip) {
        var me = this,
            clsArray = [],
            i = 0,
            length, cls;

        if (typeof classes === "string") {
            classes = (classes.indexOf(' ') < 0) ? [classes] : Ext.String.splitWords(classes);
        }

        length = classes.length;

        for (i = 0; i < length; i++) {
            cls = classes[i];
            if (cls && me.hasUICls(cls)) {
                me.uiCls = Ext.Array.remove(me.uiCls, cls);
                clsArray = clsArray.concat(me.removeUIClsFromElement(cls));
            }
        }

        if (skip !== true) {
            me.removeCls(clsArray);
        }

        return clsArray;
    },

    
    hasUICls: function(cls) {
        var me = this,
            uiCls = me.uiCls || [];

        return Ext.Array.contains(uiCls, cls);
    },

    frameElementsArray: ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],

    
    addUIClsToElement: function(cls) {
        var me = this,
            baseClsUi = me.baseCls + '-' + me.ui + '-' + cls,
            result = [Ext.baseCSSPrefix + cls, me.baseCls + '-' + cls, baseClsUi],
            frameElementCls = me.frameElementCls,
            frameElementsArray, frameElementsLength, i, el, frameElement, c;

        if (me.frame && !Ext.supports.CSS3BorderRadius) {
            
            frameElementsArray = me.frameElementsArray;
            frameElementsLength = frameElementsArray.length;
            i = 0;

            
            for (; i < frameElementsLength; i++) {
                frameElement = frameElementsArray[i];
                el = me['frame' + frameElement.toUpperCase()];
                c = baseClsUi + '-' + frameElement;
                if (el && el.dom) {
                    el.addCls(c);
                } else if (Ext.Array.indexOf(frameElementCls[frameElement], c) == -1) {
                    frameElementCls[frameElement].push(c);
                }
            }
        }

        me.frameElementCls = frameElementCls;

        return result;
    },

    
    removeUIClsFromElement: function(cls) {
        var me = this,
            baseClsUi = me.baseCls + '-' + me.ui + '-' + cls,
            result = [Ext.baseCSSPrefix + cls, me.baseCls + '-' + cls, baseClsUi],
            frameElementCls = me.frameElementCls,
            frameElementsArray, frameElementsLength, i, el, frameElement, c;

        if (me.frame && !Ext.supports.CSS3BorderRadius) {
            
            frameElementsArray = me.frameElementsArray;
            frameElementsLength = frameElementsArray.length;
            i = 0;

            
            for (; i < frameElementsLength; i++) {
                frameElement = frameElementsArray[i];
                el = me['frame' + frameElement.toUpperCase()];
                c = baseClsUi + '-' + frameElement;
                if (el && el.dom) {
                    el.addCls(c);
                } else {
                    Ext.Array.remove(frameElementCls[frameElement], c);
                }
            }
        }

        me.frameElementCls = frameElementCls;

        return result;
    },

    
    addUIToElement: function() {
        var me = this,
            baseClsUI = me.baseCls + '-' + me.ui,
            frameElementCls = me.frameElementCls,
            frameElementsArray, frameElementsLength, i, el, frameElement, c;

        me.addCls(baseClsUI);

        if (me.frame && !Ext.supports.CSS3BorderRadius) {
            
            frameElementsArray = me.frameElementsArray;
            frameElementsLength = frameElementsArray.length;
            i = 0;

            
            for (; i < frameElementsLength; i++) {
                frameElement = frameElementsArray[i];
                el = me['frame' + frameElement.toUpperCase()];
                c = baseClsUI + '-' + frameElement;
                if (el) {
                    el.addCls(c);
                } else {
                    if (!Ext.Array.contains(frameElementCls[frameElement], c)) {
                        frameElementCls[frameElement].push(c);
                    }
                }
            }
        }
    },

    
    removeUIFromElement: function() {
        var me = this,
            baseClsUI = me.baseCls + '-' + me.ui,
            frameElementCls = me.frameElementCls,
            frameElementsArray, frameElementsLength, i, el, frameElement, c;

        me.removeCls(baseClsUI);

        if (me.frame && !Ext.supports.CSS3BorderRadius) {
            
            frameElementsArray = me.frameElementsArray;
            frameElementsLength = frameElementsArray.length;
            i = 0;

            for (; i < frameElementsLength; i++) {
                frameElement = frameElementsArray[i];
                el = me['frame' + frameElement.toUpperCase()];
                c = baseClsUI + '-' + frameElement;
                if (el) {
                    el.removeCls(c);
                } else {
                    Ext.Array.remove(frameElementCls[frameElement], c);
                }
            }
        }
    },

    
    getTpl: function(name) {
        return Ext.XTemplate.getTpl(this, name);
    },

    
    initStyles: function(targetEl) {
        var me = this,
            Element = Ext.Element,
            padding = me.padding,
            margin = me.margin,
            x = me.x,
            y = me.y,
            width, height;

        
        
        if (padding !== undefined) {
            targetEl.setStyle('padding', Element.unitizeBox((padding === true) ? 5 : padding));
        }

        if (margin !== undefined) {
            targetEl.setStyle('margin', Element.unitizeBox((margin === true) ? 5 : margin));
        }

        if (me.border !== undefined) {
            me.setBorder(me.border, targetEl);
        }

        
        
        if (me.cls && me.cls != me.initialCls) {
            targetEl.addCls(me.cls);
            delete me.cls;
            delete me.initialCls;
        }
        if (me.style && me.style != me.initialStyle) {
            targetEl.setStyle(me.style);
            delete me.style;
            delete me.initialStyle;
        }

        if (x !== undefined) {
            targetEl.setStyle('left', (typeof x == 'number') ? (x + 'px') : x);
        }
        if (y !== undefined) {
            targetEl.setStyle('top', (typeof y == 'number') ? (y + 'px') : y);
        }

        
        
        if (!me.getFrameInfo()) {
            width = me.width;
            height = me.height;

            
            if (width !== undefined) {
                if (typeof width === 'number') {
                    if (Ext.isBorderBox) {
                        targetEl.setStyle('width', width + 'px');
                    }
                } else {
                    targetEl.setStyle('width', width);
                }
            }
            if (height !== undefined) {
                if (typeof height === 'number') {
                    if (Ext.isBorderBox) {
                        targetEl.setStyle('height', height + 'px');
                    }
                } else {
                    targetEl.setStyle('height', height);
                }
            }
        }
    },

    
    initEvents : function() {
        var me = this,
            afterRenderEvents = me.afterRenderEvents,
            el,
            property,
            fn = function(listeners){
                me.mon(el, listeners);
            };

        if (afterRenderEvents) {
            for (property in afterRenderEvents) {
                if (afterRenderEvents.hasOwnProperty(property)) {
                    el = me[property];
                    if (el && el.on) {
                        Ext.each(afterRenderEvents[property], fn);
                    }
                }
            }
        }

        
        
        
        me.addFocusListener();
    },

    
    addFocusListener: function() {
        var me = this,
            focusEl = me.getFocusEl(),
            needsTabIndex;

        
        
        
        
        
        

        
        if (focusEl) {
            
            
            if (focusEl.isComponent) {
                return focusEl.addFocusListener();
            }

            
            
            
            needsTabIndex = focusEl.needsTabIndex();
            if (!me.focusListenerAdded && (!needsTabIndex || Ext.FocusManager.enabled)) {
                if (needsTabIndex) {
                    focusEl.dom.tabIndex = -1;
                }
                focusEl.on({
                    focus: me.onFocus,
                    blur: me.onBlur,
                    scope: me
                });
                me.focusListenerAdded = true;
            }
        }
    },

    
    getFocusEl: Ext.emptyFn,

    isFocusable: function(c) {
        var me = this,
            focusEl;
        if ((me.focusable !== false) && (focusEl = me.getFocusEl()) && me.rendered && !me.destroying && !me.isDestroyed && !me.disabled && me.isVisible(true)) {

            
            
            if (focusEl.isComponent) {
                return focusEl.isFocusable();
            }

            return focusEl && focusEl.dom && focusEl.isVisible();
        }
    },

    
    preFocus: Ext.emptyFn,

    
    onFocus: function(e) {
        var me = this,
            focusCls = me.focusCls,
            focusEl = me.getFocusEl();

        if (!me.disabled) {
            me.preFocus(e);
            if (focusCls && focusEl) {
                focusEl.addCls(me.addClsWithUI(focusCls, true));
            }
            if (!me.hasFocus) {
                me.hasFocus = true;
                me.fireEvent('focus', me, e);
            }
        }
    },

    
    beforeBlur : Ext.emptyFn,

    
    onBlur : function(e) {
        var me = this,
            focusCls = me.focusCls,
            focusEl = me.getFocusEl();

        if (me.destroying) {
            return;
        }

        me.beforeBlur(e);
        if (focusCls && focusEl) {
            focusEl.removeCls(me.removeClsWithUI(focusCls, true));
        }
        if (me.validateOnBlur) {
            me.validate();
        }
        me.hasFocus = false;
        me.fireEvent('blur', me, e);
        me.postBlur(e);
    },

    
    postBlur : Ext.emptyFn,

    
    is: function(selector) {
        return Ext.ComponentQuery.is(this, selector);
    },

    
    up: function(selector) {
        
        
        
        var result = this.getBubbleTarget();
        if (selector) {
            for (; result; result = result.getBubbleTarget()) {
                if (Ext.ComponentQuery.is(result, selector)) {
                    return result;
                }
            }
        }
        return result;
    },

    
    nextSibling: function(selector) {
        var o = this.ownerCt, it, last, idx, c;
        if (o) {
            it = o.items;
            idx = it.indexOf(this) + 1;
            if (idx) {
                if (selector) {
                    for (last = it.getCount(); idx < last; idx++) {
                        if ((c = it.getAt(idx)).is(selector)) {
                            return c;
                        }
                    }
                } else {
                    if (idx < it.getCount()) {
                        return it.getAt(idx);
                    }
                }
            }
        }
        return null;
    },

    
    previousSibling: function(selector) {
        var o = this.ownerCt, it, idx, c;
        if (o) {
            it = o.items;
            idx = it.indexOf(this);
            if (idx != -1) {
                if (selector) {
                    for (--idx; idx >= 0; idx--) {
                        if ((c = it.getAt(idx)).is(selector)) {
                            return c;
                        }
                    }
                } else {
                    if (idx) {
                        return it.getAt(--idx);
                    }
                }
            }
        }
        return null;
    },

    
    previousNode: function(selector,  includeSelf) {
        var node = this,
            ownerCt = node.ownerCt,
            result,
            it, i, sib;

        
        if (includeSelf && node.is(selector)) {
            return node;
        }

        if (ownerCt) {
            for (it = ownerCt.items.items, i = Ext.Array.indexOf(it, node) - 1; i > -1; i--) {
                sib = it[i];
                if (sib.query) {
                    result = sib.query(selector);
                    result = result[result.length - 1];
                    if (result) {
                        return result;
                    }
                }
                if (sib.is(selector)) {
                    return sib;
                }
            }
            return ownerCt.previousNode(selector, true);
        }
        return null;
    },

    
    nextNode: function(selector,  includeSelf) {
        var node = this,
            ownerCt = node.ownerCt,
            result,
            it, len, i, sib;

        
        if (includeSelf && node.is(selector)) {
            return node;
        }

        if (ownerCt) {
            for (it = ownerCt.items.items, i = Ext.Array.indexOf(it, node) + 1, len = it.length; i < len; i++) {
                sib = it[i];
                if (sib.is(selector)) {
                    return sib;
                }
                if (sib.down) {
                    result = sib.down(selector);
                    if (result) {
                        return result;
                    }
                }
            }
            return ownerCt.nextNode(selector);
        }
        return null;
    },

    
    getId : function() {
        return this.id || (this.id = 'ext-comp-' + (this.getAutoId()));
    },

    
    getItemId : function() {
        return this.itemId || this.id;
    },

    
    getEl : function() {
        return this.el;
    },

    
    getTargetEl: function() {
        return this.frameBody || this.el;
    },

    
    getOverflowStyle: function() {
        var me = this,
            result = null;

        if (typeof me.autoScroll == 'boolean') {
            result = {
                overflow: me.autoScroll ? 'auto' : ''
            };
        } else if (me.overflowX !== undefined || me.overflowY !== undefined) {
            result = {
                'overflow-x':  (me.overflowX||''),
                'overflow-y':  (me.overflowY||'')
            };
        }

        
        
        if (result && (Ext.isIE6 || Ext.isIE7)) {
            result.position = 'relative';
        }

        return result;
    },

    
    isXType: function(xtype, shallow) {
        if (shallow) {
            return this.xtype === xtype;
        }
        else {
            return this.xtypesMap[xtype];
        }
    },

    
    getXTypes: function() {
        var self = this.self,
            xtypes, parentPrototype, parentXtypes;

        if (!self.xtypes) {
            xtypes = [];
            parentPrototype = this;

            while (parentPrototype) {
                parentXtypes = parentPrototype.xtypes;

                if (parentXtypes !== undefined) {
                    xtypes.unshift.apply(xtypes, parentXtypes);
                }

                parentPrototype = parentPrototype.superclass;
            }

            self.xtypeChain = xtypes;
            self.xtypes = xtypes.join('/');
        }

        return self.xtypes;
    },

    
    update : function(htmlOrData, loadScripts, cb) {
        var me = this;

        if (me.tpl && !Ext.isString(htmlOrData)) {
            me.data = htmlOrData;
            if (me.rendered) {
                me.tpl[me.tplWriteMode](me.getTargetEl(), htmlOrData || {});
            }
        } else {
            me.html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData;
            if (me.rendered) {
                me.getTargetEl().update(me.html, loadScripts, cb);
            }
        }

        if (me.rendered) {
            me.updateLayout();
        }
    },

    
    setVisible : function(visible) {
        return this[visible ? 'show': 'hide']();
    },

    
    isVisible: function(deep) {
        var me = this,
            child = me,
            visible = me.rendered && !me.hidden,
            ancestor = me.ownerCt;

        
        me.hiddenAncestor = false;
        if (me.destroyed) {
            return false;
        }

        if (deep && visible && ancestor) {
            while (ancestor) {
                
                
                
                
                if (ancestor.hidden || (ancestor.collapsed &&
                        !(ancestor.getDockedItems && Ext.Array.contains(ancestor.getDockedItems(), child)))) {
                    
                    me.hiddenAncestor = ancestor;
                    visible = false;
                    break;
                }
                child = ancestor;
                ancestor = ancestor.ownerCt;
            }
        }
        return visible;
    },

    onBoxReady: function(){
        var me = this;

        if (me.disableOnBoxReady) {
            me.onDisable();
        } else if (me.enableOnBoxReady) {
            me.onEnable();
        }
        if (me.resizable) {
            me.initResizable(me.resizable);
        }

        
        
        if (me.draggable) {
            me.initDraggable();
        }
    },

    
    enable: function(silent) {
        var me = this;

        delete me.disableOnBoxReady;
        me.removeCls(me.disabledCls);
        if (me.rendered) {
            me.onEnable();
        } else {
            me.enableOnBoxReady = true;
        }

        me.disabled = false;
        delete me.resetDisable;

        if (silent !== true) {
            me.fireEvent('enable', me);
        }

        return me;
    },

    
    disable: function(silent) {
        var me = this;

        delete me.enableOnBoxReady;
        me.addCls(me.disabledCls);
        if (me.rendered) {
            me.onDisable();
        } else {
            me.disableOnBoxReady = true;
        }

        me.disabled = true;

        if (silent !== true) {
            delete me.resetDisable;
            me.fireEvent('disable', me);
        }

        return me;
    },

    
    onEnable: function() {
        if (this.maskOnDisable) {
            this.el.dom.disabled = false;
            this.unmask();
        }
    },

    
    onDisable : function() {
        var me = this,
            focusCls = me.focusCls,
            focusEl = me.getFocusEl();
            
        if (focusCls && focusEl) {
            focusEl.removeCls(me.removeClsWithUI(focusCls, true));
        }
        
        if (me.maskOnDisable) {
            me.el.dom.disabled = true;
            me.mask();
        }
    },

    mask: function() {
        var box = this.lastBox,
            target = this.getMaskTarget(),
            args = [];

        
        if (box) {
            args[2] = box.height;
        }
        target.mask.apply(target, args);
    },

    unmask: function() {
        this.getMaskTarget().unmask();
    },

    getMaskTarget: function(){
        return this.el;
    },

    
    isDisabled : function() {
        return this.disabled;
    },

    
    setDisabled : function(disabled) {
        return this[disabled ? 'disable': 'enable']();
    },

    
    isHidden : function() {
        return this.hidden;
    },

    
    addCls : function(cls) {
        var me = this,
            el = me.rendered ? me.el : me.protoEl;

        el.addCls.apply(el, arguments);
        return me;
    },

    
    addClass : function() {
        return this.addCls.apply(this, arguments);
    },

    
    hasCls: function (cls) {
        var me = this,
            el = me.rendered ? me.el : me.protoEl;

        return el.hasCls.apply(el, arguments);
    },

    
    removeCls : function(cls) {
        var me = this,
            el = me.rendered ? me.el : me.protoEl;

        el.removeCls.apply(el, arguments);
        return me;
    },


    addOverCls: function() {
        var me = this;
        if (!me.disabled) {
            me.el.addCls(me.overCls);
        }
    },

    removeOverCls: function() {
        this.el.removeCls(this.overCls);
    },

    addListener : function(element, listeners, scope, options) {
        var me = this,
            fn,
            option;

        if (Ext.isString(element) && (Ext.isObject(listeners) || options && options.element)) {
            if (options.element) {
                fn = listeners;

                listeners = {};
                listeners[element] = fn;
                element = options.element;
                if (scope) {
                    listeners.scope = scope;
                }

                for (option in options) {
                    if (options.hasOwnProperty(option)) {
                        if (me.eventOptionsRe.test(option)) {
                            listeners[option] = options[option];
                        }
                    }
                }
            }

            
            
            if (me[element] && me[element].on) {
                me.mon(me[element], listeners);
            } else {
                me.afterRenderEvents = me.afterRenderEvents || {};
                if (!me.afterRenderEvents[element]) {
                    me.afterRenderEvents[element] = [];
                }
                me.afterRenderEvents[element].push(listeners);
            }
        }

        return me.mixins.observable.addListener.apply(me, arguments);
    },

    
    removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
        var me = this,
            element = managedListener.options ? managedListener.options.element : null;

        if (element) {
            element = me[element];
            if (element && element.un) {
                if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) {
                    element.un(managedListener.ename, managedListener.fn, managedListener.scope);
                    if (!isClear) {
                        Ext.Array.remove(me.managedListeners, managedListener);
                    }
                }
            }
        } else {
            return me.mixins.observable.removeManagedListenerItem.apply(me, arguments);
        }
    },

    
    getBubbleTarget : function() {
        return this.ownerCt;
    },

    
    isFloating : function() {
        return this.floating;
    },

    
    isDraggable : function() {
        return !!this.draggable;
    },

    
    isDroppable : function() {
        return !!this.droppable;
    },

    
    onAdded : function(container, pos) {
        var me = this;
        me.ownerCt = container;
        if (me.hasListeners.added) {
            me.fireEvent('added', me, container, pos);
        }
    },

    
    onRemoved : function(destroying) {
        var me = this;
        if (me.hasListeners.removed) {
            me.fireEvent('removed', me, me.ownerCt);
        }
        delete me.ownerCt;
        delete me.ownerLayout;
    },

    
    beforeDestroy : Ext.emptyFn,

    
    onResize : Ext.emptyFn,

    
    setSize : function(width, height) {
        var me = this;

        
        if (width && typeof width == 'object') {
            height = width.height;
            width  = width.width;
        }

        
        if (typeof width == 'number') {
            me.width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
        } else if (width === null) {
            delete me.width;
        }
        
        if (typeof height == 'number') {
            me.height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
        } else if (height === null) {
            delete me.height;
        }

        
        
        if (me.rendered && me.isVisible()) {

            
            me.updateLayout({
                isRoot: false
            });
        }

        return me;
    },

    
    isLayoutRoot: function() {
        var me = this,
            ownerLayout = me.ownerLayout;

        
        
        
        
        if (!ownerLayout || me._isLayoutRoot || me.floating) {
            return true;
        }

        return ownerLayout.isItemLayoutRoot(me);
    },

    
    isLayoutSuspended: function () {
        var comp = this,
            ownerLayout;

        while (comp) {
            if (comp.layoutSuspendCount || comp.suspendLayout) {
                return true;
            }

            ownerLayout = comp.ownerLayout;
            if (!ownerLayout) {
                break;
            }

            

            
            
            
            comp = ownerLayout.owner;
        }

        return false;
    },

    
    updateLayout: function (options) {
        var me = this,
            defer,
            isRoot = options && options.isRoot;

        if (!me.rendered || me.layoutSuspendCount || me.suspendLayout) {
            return;
        }

        if (me.hidden) {
            Ext.AbstractComponent.cancelLayout(me);
        } else if (typeof isRoot != 'boolean') {
            isRoot = me.isLayoutRoot();
        }

        
        if (isRoot || !me.ownerLayout || !me.ownerLayout.onContentChange(me)) {
            
            if (!me.isLayoutSuspended()) {
                
                defer = (options && options.hasOwnProperty('defer')) ? options.defer : me.deferLayouts;
                Ext.AbstractComponent.updateLayout(me, defer);
            }
        }
    },

    
    getSizeModel: function (ownerCtSizeModel) {
        var me = this,
            models = Ext.layout.SizeModel,
            ownerContext = me.componentLayout.ownerContext,
            width = me.width,
            height = me.height,
            typeofWidth, typeofHeight,
            hasPixelWidth, hasPixelHeight,
            heightModel, ownerLayout, policy, shrinkWrap, topLevel, widthModel;

        if (ownerContext) {
            
            
            
            
            widthModel = ownerContext.widthModel;
            heightModel = ownerContext.heightModel;
        }

        if (!widthModel || !heightModel) {
            hasPixelWidth = ((typeofWidth = typeof width) == 'number');
            hasPixelHeight = ((typeofHeight = typeof height) == 'number');
            topLevel = me.floating || !(ownerLayout = me.ownerLayout);

            
            if (topLevel) {
                policy = Ext.layout.Layout.prototype.autoSizePolicy;
                shrinkWrap = me.floating ? 3 : me.shrinkWrap;

                if (hasPixelWidth) {
                    widthModel = models.configured;
                }

                if (hasPixelHeight) {
                    heightModel = models.configured;
                }
            } else {
                policy = ownerLayout.getItemSizePolicy(me, ownerCtSizeModel);
                shrinkWrap = ownerLayout.isItemShrinkWrap(me);
            }

            shrinkWrap = (shrinkWrap === true) ? 3 : (shrinkWrap || 0); 

            
            
            
            
            if (topLevel && shrinkWrap) {
                if (width && typeofWidth == 'string') {
                    shrinkWrap &= 2; 
                }
                if (height && typeofHeight == 'string') {
                    shrinkWrap &= 1; 
                }
            }

            if (shrinkWrap !== 3) {
                if (!ownerCtSizeModel) {
                    ownerCtSizeModel = me.ownerCt && me.ownerCt.getSizeModel();
                }

                if (ownerCtSizeModel) {
                    shrinkWrap |= (ownerCtSizeModel.width.shrinkWrap ? 1 : 0) | (ownerCtSizeModel.height.shrinkWrap ? 2 : 0);
                }
            }

            if (!widthModel) {
                if (!policy.setsWidth) {
                    if (hasPixelWidth) {
                        widthModel = models.configured;
                    } else {
                        widthModel = (shrinkWrap & 1) ? models.shrinkWrap : models.natural;
                    }
                } else if (policy.readsWidth) {
                    if (hasPixelWidth) {
                        widthModel = models.calculatedFromConfigured;
                    } else {
                        widthModel = (shrinkWrap & 1) ? models.calculatedFromShrinkWrap :
                                    models.calculatedFromNatural;
                    }
                } else {
                    widthModel = models.calculated;
                }
            }

            if (!heightModel) {
                if (!policy.setsHeight) {
                    if (hasPixelHeight) {
                        heightModel = models.configured;
                    } else {
                        heightModel = (shrinkWrap & 2) ? models.shrinkWrap : models.natural;
                    }
                } else if (policy.readsHeight) {
                    if (hasPixelHeight) {
                        heightModel = models.calculatedFromConfigured;
                    } else {
                        heightModel = (shrinkWrap & 2) ? models.calculatedFromShrinkWrap :
                                    models.calculatedFromNatural;
                    }
                } else {
                    heightModel = models.calculated;
                }
            }
        }

        
        
        return widthModel.pairsByHeightOrdinal[heightModel.ordinal];
    },

    isDescendant: function(ancestor) {
        if (ancestor.isContainer) {
            for (var c = this.ownerCt; c; c = c.ownerCt) {
                if (c === ancestor) {
                    return true;
                }
            }
        }
        return false;
    },

    
    doComponentLayout : function() {
        this.updateLayout();
        return this;
    },

    
    forceComponentLayout: function () {
        this.updateLayout();
    },

    
    setComponentLayout : function(layout) {
        var currentLayout = this.componentLayout;
        if (currentLayout && currentLayout.isLayout && currentLayout != layout) {
            currentLayout.setOwner(null);
        }
        this.componentLayout = layout;
        layout.setOwner(this);
    },

    getComponentLayout : function() {
        var me = this;

        if (!me.componentLayout || !me.componentLayout.isLayout) {
            me.setComponentLayout(Ext.layout.Layout.create(me.componentLayout, 'autocomponent'));
        }
        return me.componentLayout;
    },

    
    afterComponentLayout: function(width, height, oldWidth, oldHeight) {
        var me = this,
            floaters, len, i, floater;

        if (++me.componentLayoutCounter === 1) {
            me.afterFirstLayout(width, height);
        }

        
        if (me.floatingItems) {
            floaters = me.floatingItems.items;
            len = floaters.length;
            for (i = 0; i < len; i++) {
                floater = floaters[i];
                if (!floater.rendered && floater.autoShow) {
                    floater.show();
                }
            }
        }
        if (me.hasListeners.resize && (width !== oldWidth || height !== oldHeight)) {
            me.fireEvent('resize', me, width, height, oldWidth, oldHeight);
        }
    },

    
    beforeComponentLayout: function(width, height) {
        return true;
    },

    
    setPosition : function(x, y, animate) {
        var me = this,
            pos = me.beforeSetPosition.apply(me, arguments);

        if (pos && me.rendered) {
            
            pos = me.convertPosition(pos);

            
            if (pos.left !== me.el.getLeft() || pos.top !== me.el.getTop()) {
                if (animate) {
                    me.stopAnimation();
                    me.animate(Ext.apply({
                        duration: 1000,
                        listeners: {
                            afteranimate: Ext.Function.bind(me.afterSetPosition, me, [pos.left, pos.top])
                        },
                        to: pos
                    }, animate));
                } else {
                    
                    
                    if (pos.left !== undefined && pos.top !== undefined) {
                        me.el.setLeftTop(pos.left, pos.top);
                    } else if (pos.left !== undefined) {
                        me.el.setLeft(pos.left);
                    } else if (pos.top !==undefined) {
                        me.el.setTop(pos.top);
                    }
                    me.afterSetPosition(pos.left, pos.top);
                }
            }
        }
        return me;
    },

    
    beforeSetPosition: function (x, y, animate) {
        var pos, x0;

        
        if (!x || Ext.isNumber(x)) {
            pos = { x: x, y : y, anim: animate };
        } else if (Ext.isNumber(x0 = x[0])) { 
            pos = { x : x0, y : x[1], anim: y };
        } else {
            pos = { x: x.x, y: x.y, anim: y }; 
        }

        pos.hasX = Ext.isNumber(pos.x);
        pos.hasY = Ext.isNumber(pos.y);

        
        this.x = pos.x;
        this.y = pos.y;

        return (pos.hasX || pos.hasY) ? pos : null;
    },

    
    afterSetPosition: function(x, y) {
        var me = this;
        me.onPosition(x, y);
        if (me.hasListeners.move) {
            me.fireEvent('move', me, x, y);
        }
    },

    
    convertPosition: function (pos, withUnits) {
        var ret = {},
            El = Ext.Element;

        if (pos.hasX) {
            ret.left = withUnits ? El.addUnits(pos.x) : pos.x;
        }
        if (pos.hasY) {
            ret.top = withUnits ? El.addUnits(pos.y) : pos.y;
        }

        return ret;
    },

    
    onPosition: Ext.emptyFn,

    
    setWidth : function(width) {
        return this.setSize(width);
    },

    
    setHeight : function(height) {
        return this.setSize(undefined, height);
    },

    
    getSize : function() {
        return this.el.getSize();
    },

    
    getWidth : function() {
        return this.el.getWidth();
    },

    
    getHeight : function() {
        return this.el.getHeight();
    },

    
    getLoader: function(){
        var me = this,
            autoLoad = me.autoLoad ? (Ext.isObject(me.autoLoad) ? me.autoLoad : {url: me.autoLoad}) : null,
            loader = me.loader || autoLoad;

        if (loader) {
            if (!loader.isLoader) {
                me.loader = new Ext.ComponentLoader(Ext.apply({
                    target: me,
                    autoLoad: autoLoad
                }, loader));
            } else {
                loader.setTarget(me);
            }
            return me.loader;

        }
        return null;
    },

    
    setDocked : function(dock, layoutParent) {
        var me = this;

        me.dock = dock;
        if (layoutParent && me.ownerCt && me.rendered) {
            me.ownerCt.updateLayout();
        }
        return me;
    },

    
    setBorder: function(border,  targetEl) {
        var me = this,
            initial = !!targetEl;

        if (me.rendered || initial) {
            if (!initial) {
                targetEl = me.el;
            }

            if (!border) {
                border = 0;
            } else {
                border = Ext.Element.unitizeBox((border === true) ? 1 : border);
            }
            targetEl.setStyle('border-width', border);
            if (!initial) {
                me.updateLayout();
            }
        }
        me.border = border;
    },

    onDestroy : function() {
        var me = this;

        if (me.monitorResize && Ext.EventManager.resizeEvent) {
            Ext.EventManager.resizeEvent.removeListener(me.setSize, me);
        }

        
        Ext.destroy(
            me.componentLayout,
            me.loadMask,
            me.floatingDescendants
        );
    },

    
    destroy : function() {
        var me = this,
            selectors = me.renderSelectors,
            selector,
            el;

        if (!me.isDestroyed) {
            if (!me.hasListeners.beforedestroy || me.fireEvent('beforedestroy', me) !== false) {
                me.destroying = true;
                me.beforeDestroy();

                if (me.floating) {
                    delete me.floatParent;
                    
                    
                    if (me.zIndexManager) {
                        me.zIndexManager.unregister(me);
                    }
                } else if (me.ownerCt && me.ownerCt.remove) {
                    me.ownerCt.remove(me, false);
                }

                me.onDestroy();

                
                Ext.destroy(me.plugins);

                if (me.hasListeners.destroy) {
                    me.fireEvent('destroy', me);
                }
                Ext.ComponentManager.unregister(me);

                me.mixins.state.destroy.call(me);

                me.clearListeners();
                
                if (me.rendered) {
                    if (!me.preserveElOnDestroy) {
                        me.el.remove();
                    }
                    me.mixins.elementCt.destroy.call(me); 
                    if (selectors) {
                        for (selector in selectors) {
                            if (selectors.hasOwnProperty(selector)) {
                                el = me[selector];
                                if (el) { 
                                    delete me[selector];
                                    el.remove();
                                }
                            }
                        }
                    }

                    delete me.el;
                    delete me.frameBody;
                    delete me.rendered;
                }

                me.destroying = false;
                me.isDestroyed = true;
            }
        }
    },

    
    getPlugin: function(pluginId) {
        var i = 0,
            plugins = this.plugins,
            ln = plugins.length;
        for (; i < ln; i++) {
            if (plugins[i].pluginId === pluginId) {
                return plugins[i];
            }
        }
    },

    
    isDescendantOf: function(container) {
        return !!this.findParentBy(function(p){
            return p === container;
        });
    }
}, function() {
    var AbstractComponent = this;

    AbstractComponent.createAlias({
        on: 'addListener',
        prev: 'previousSibling',
        next: 'nextSibling'
    });

    
    Ext.resumeLayouts = function (flush) {
        AbstractComponent.resumeLayouts(flush);
    };

    
    Ext.suspendLayouts = function () {
        AbstractComponent.suspendLayouts();
    };

    
    Ext.batchLayouts = function(fn, scope) {
        AbstractComponent.suspendLayouts();
        
        fn.call(scope);
        AbstractComponent.resumeLayouts(true);
    };
});


Ext.define('Ext.ModelManager', {
    extend: 'Ext.AbstractManager',
    alternateClassName: 'Ext.ModelMgr',
    requires: ['Ext.data.association.Association'],
    
    singleton: true,

    typeName: 'mtype',

    
    associationStack: [],

    
    registerType: function(name, config) {
        var proto = config.prototype,
            model;
        if (proto && proto.isModel) {
            
            model = config;
        } else {
            
            if (!config.extend) {
                config.extend = 'Ext.data.Model';
            }
            model = Ext.define(name, config);
        }
        this.types[name] = model;
        return model;
    },

    
    onModelDefined: function(model) {
        var stack  = this.associationStack,
            length = stack.length,
            create = [],
            association, i, created;

        for (i = 0; i < length; i++) {
            association = stack[i];

            if (association.associatedModel == model.modelName) {
                create.push(association);
            }
        }

        for (i = 0, length = create.length; i < length; i++) {
            created = create[i];
            this.types[created.ownerModel].prototype.associations.add(Ext.data.association.Association.create(created));
            Ext.Array.remove(stack, created);
        }
    },

    
    registerDeferredAssociation: function(association){
        this.associationStack.push(association);
    },

    
    getModel: function(id) {
        var model = id;
        if (typeof model == 'string') {
            model = this.types[model];
        }
        return model;
    },

    
    create: function(config, name, id) {
        var Con = typeof name == 'function' ? name : this.types[name || config.name];

        return new Con(config, id);
    }
}, function() {

    
    Ext.regModel = function() {
        return this.ModelManager.registerType.apply(this.ModelManager, arguments);
    };
});


Ext.define('Ext.PluginManager', {
    extend: 'Ext.AbstractManager',
    alternateClassName: 'Ext.PluginMgr',
    singleton: true,
    typeName: 'ptype',

    
    create : function(config, defaultType){
        if (config.init) {
            return config;
        } else {
            return Ext.createByAlias('plugin.' + (config.ptype || defaultType), config);
        }

        
        
        
        
        
        
        
    },

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    
    findByType: function(type, defaultsOnly) {
        var matches = [],
            types   = this.types,
            name,
            item;

        for (name in types) {
            if (!types.hasOwnProperty(name)) {
                continue;
            }
            item = types[name];

            if (item.type == type && (!defaultsOnly || (defaultsOnly === true && item.isDefault))) {
                matches.push(item);
            }
        }

        return matches;
    }
}, function() {
    
    Ext.preg = function() {
        return Ext.PluginManager.registerType.apply(Ext.PluginManager, arguments);
    };
});



Ext.define('Ext.fx.Queue', {

    requires: ['Ext.util.HashMap'],

    constructor: function() {
        this.targets = new Ext.util.HashMap();
        this.fxQueue = {};
    },

    
    getFxDefaults: function(targetId) {
        var target = this.targets.get(targetId);
        if (target) {
            return target.fxDefaults;
        }
        return {};
    },

    
    setFxDefaults: function(targetId, obj) {
        var target = this.targets.get(targetId);
        if (target) {
            target.fxDefaults = Ext.apply(target.fxDefaults || {}, obj);
        }
    },

    
    stopAnimation: function(targetId) {
        var me = this,
            queue = me.getFxQueue(targetId),
            ln = queue.length;
        while (ln) {
            queue[ln - 1].end();
            ln--;
        }
    },

    
    getActiveAnimation: function(targetId) {
        var queue = this.getFxQueue(targetId);
        return (queue && !!queue.length) ? queue[0] : false;
    },

    
    hasFxBlock: function(targetId) {
        var queue = this.getFxQueue(targetId);
        return queue && queue[0] && queue[0].block;
    },

    
    getFxQueue: function(targetId) {
        if (!targetId) {
            return false;
        }
        var me = this,
            queue = me.fxQueue[targetId],
            target = me.targets.get(targetId);

        if (!target) {
            return false;
        }

        if (!queue) {
            me.fxQueue[targetId] = [];
            
            if (target.type != 'element') {
                target.target.on('destroy', function() {
                    me.fxQueue[targetId] = [];
                });
            }
        }
        return me.fxQueue[targetId];
    },

    
    queueFx: function(anim) {
        var me = this,
            target = anim.target,
            queue, ln;

        if (!target) {
            return;
        }

        queue = me.getFxQueue(target.getId());
        ln = queue.length;

        if (ln) {
            if (anim.concurrent) {
                anim.paused = false;
            }
            else {
                queue[ln - 1].on('afteranimate', function() {
                    anim.paused = false;
                });
            }
        }
        else {
            anim.paused = false;
        }
        anim.on('afteranimate', function() {
            Ext.Array.remove(queue, anim);
            if (anim.remove) {
                if (target.type == 'element') {
                    var el = Ext.get(target.id);
                    if (el) {
                        el.remove();
                    }
                }
            }
        }, this);
        queue.push(anim);
    }
});

Ext.define('Ext.util.LruCache', {
    extend: 'Ext.util.HashMap',

    

    constructor: function(config) {
        Ext.apply(this, config);
        this.callParent([config]);
    },

    
    add: function(key, newValue) {
        var me = this,
            existingKey = me.findKey(newValue),
            entry;

        
        if (existingKey) {
            me.unlinkEntry(entry = me.map[existingKey]);
            entry.prev = me.last;
            entry.next = null;
        }
        
        else {
            entry = {
                prev: me.last,
                next: null,
                key: key,
                value: newValue
            };
        }

        
        if (me.last) {
            me.last.next = entry;
        }
        
        else {
            me.first = entry;
        }
        me.last = entry;
        me.callParent([key, entry]);
        me.prune();
        return newValue;
    },

    
    insertBefore: function(key, newValue, sibling) {
        var me = this,
            existingKey,
            entry;

        
        
        if (sibling = this.map[this.findKey(sibling)]) {
            existingKey = me.findKey(newValue);

            
            if (existingKey) {
                me.unlinkEntry(entry = me.map[existingKey]);
            }
            
            else {
                entry = {
                    prev: sibling.prev,
                    next: sibling,
                    key: key,
                    value: newValue
                };
            }

            if (sibling.prev) {
                entry.prev.next = entry;
            } else {
                me.first = entry;
            }
            entry.next = sibling;
            sibling.prev = entry;
            me.prune();
            return newValue;
        }
        
        else {
            return me.add(key, newValue);
        }
    },

    
    get: function(key) {
        var entry = this.map[key];
        if (entry) {

            
            if (entry.next) {
                this.moveToEnd(entry);
            }
            return entry.value;
        }
    },

    
    removeAtKey: function(key) {
        this.unlinkEntry(this.map[key]);
        return this.callParent(arguments);
    },

    
    clear: function( initial) {
        this.first = this.last = null;
        return this.callParent(arguments);
    },

    
    unlinkEntry: function(entry) {
        
        if (entry) {
            if (entry.next) {
                entry.next.prev = entry.prev;
            } else {
                this.last = entry.prev;
            }
            if (entry.prev) {
                entry.prev.next = entry.next;
            } else {
                this.first = entry.next;
            }
            entry.prev = entry.next = null;
        }
    },

    
    moveToEnd: function(entry) {
        this.unlinkEntry(entry);

        
        
        if (entry.prev = this.last) {
            this.last.next = entry;
        }
        
        else {
            this.first = entry;
        }
        this.last = entry;
    },

    
    getArray: function(isKey) {
        var arr = [],
            entry = this.first;

        while (entry) {
            arr.push(isKey ? entry.key: entry.value);
            entry = entry.next;
        }
        return arr;
    },

    
    each: function(fn, scope, reverse) {
        var me = this,
            entry = reverse ? me.last : me.first,
            length = me.length;

        scope = scope || me;
        while (entry) {
            if (fn.call(scope, entry.key, entry.value, length) === false) {
                break;
            }
            entry = reverse ? entry.prev : entry.next;
        }
        return me;
    },

    
    findKey: function(value) {
        var key,
            map = this.map;

        for (key in map) {
            if (map.hasOwnProperty(key) && map[key].value === value) {
                return key;
            }
        }
        return undefined;
    },

    
    prune: function() {
        var me = this,
            purgeCount = me.maxSize ? (me.length - me.maxSize) : 0;

        if (purgeCount > 0) {
            for (; me.first && purgeCount; purgeCount--) {
                me.removeAtKey(me.first.key);
            }
        }
    }

  
  
  
  
});

Ext.define('Ext.util.Point', {

    
    extend: 'Ext.util.Region',

    statics: {

        
        fromEvent: function(e) {
            e = (e.changedTouches && e.changedTouches.length > 0) ? e.changedTouches[0] : e;
            return new this(e.pageX, e.pageY);
        }
    },

    

    
    constructor: function(x, y) {
        this.callParent([y, x, y, x]);
    },

    
    toString: function() {
        return "Point[" + this.x + "," + this.y + "]";
    },

    
    equals: function(p) {
        return (this.x == p.x && this.y == p.y);
    },

    
    isWithin: function(p, threshold) {
        if (!Ext.isObject(threshold)) {
            threshold = {
                x: threshold,
                y: threshold
            };
        }

        return (this.x <= p.x + threshold.x && this.x >= p.x - threshold.x &&
                this.y <= p.y + threshold.y && this.y >= p.y - threshold.y);
    },

    
    roundedEquals: function(p) {
        return (Math.round(this.x) == Math.round(p.x) && Math.round(this.y) == Math.round(p.y));
    }
}, function() {
    
    this.prototype.translate = Ext.util.Region.prototype.translateBy;
});


Ext.define("Ext.util.Sortable", {
    
    isSortable: true,

    
    defaultSortDirection: "ASC",

    requires: [
        'Ext.util.Sorter'
    ],

    

    
    initSortable: function() {
        var me = this,
            sorters = me.sorters;

        
        me.sorters = new Ext.util.AbstractMixedCollection(false, function(item) {
            return item.id || item.property;
        });

        if (sorters) {
            me.sorters.addAll(me.decodeSorters(sorters));
        }
    },

    
    sort: function(sorters, direction, where, doSort) {
        var me = this,
            sorter, sorterFn,
            newSorters;

        if (Ext.isArray(sorters)) {
            doSort = where;
            where = direction;
            newSorters = sorters;
        }
        else if (Ext.isObject(sorters)) {
            doSort = where;
            where = direction;
            newSorters = [sorters];
        }
        else if (Ext.isString(sorters)) {
            sorter = me.sorters.get(sorters);

            if (!sorter) {
                sorter = {
                    property : sorters,
                    direction: direction
                };
                newSorters = [sorter];
            }
            else if (direction === undefined) {
                sorter.toggle();
            }
            else {
                sorter.setDirection(direction);
            }
        }

        if (newSorters && newSorters.length) {
            newSorters = me.decodeSorters(newSorters);
            if (Ext.isString(where)) {
                if (where === 'prepend') {
                    sorters = me.sorters.clone().items;

                    me.sorters.clear();
                    me.sorters.addAll(newSorters);
                    me.sorters.addAll(sorters);
                }
                else {
                    me.sorters.addAll(newSorters);
                }
            }
            else {
                me.sorters.clear();
                me.sorters.addAll(newSorters);
            }
        }

        if (doSort !== false) {
            me.onBeforeSort(newSorters);
            
            sorters = me.sorters.items;
            if (sorters.length) {
                
                me.doSort(me.generateComparator());
            }
        }

        return sorters;
    },

    
    generateComparator: function() {
        var sorters = this.sorters.getRange();
        return sorters.length ? this.createComparator(sorters) : this.emptyComparator;
    },
    
    createComparator: function(sorters) {
        return function(r1, r2) {
            var result = sorters[0].sort(r1, r2),
                length = sorters.length,
                i = 1;

            
            for (; i < length; i++) {
                result = result || sorters[i].sort.call(this, r1, r2);
            }
            return result;
        };
    },
    
    emptyComparator: function(){
        return 0;
    },

    onBeforeSort: Ext.emptyFn,

    
    decodeSorters: function(sorters) {
        if (!Ext.isArray(sorters)) {
            if (sorters === undefined) {
                sorters = [];
            } else {
                sorters = [sorters];
            }
        }

        var length = sorters.length,
            Sorter = Ext.util.Sorter,
            fields = this.model ? this.model.prototype.fields : null,
            field,
            config, i;

        for (i = 0; i < length; i++) {
            config = sorters[i];

            if (!(config instanceof Sorter)) {
                if (Ext.isString(config)) {
                    config = {
                        property: config
                    };
                }

                Ext.applyIf(config, {
                    root     : this.sortRoot,
                    direction: "ASC"
                });

                
                if (config.fn) {
                    config.sorterFn = config.fn;
                }

                
                if (typeof config == 'function') {
                    config = {
                        sorterFn: config
                    };
                }

                
                if (fields && !config.transform) {
                    field = fields.get(config.property);
                    config.transform = field ? field.sortType : undefined;
                }
                sorters[i] = new Ext.util.Sorter(config);
            }
        }

        return sorters;
    },

    getSorters: function() {
        return this.sorters.items;
    },
    
    
    getFirstSorter: function(){
        var sorters = this.sorters.items,
            len = sorters.length,
            i = 0,
            sorter;
            
        for (; i < len; ++i) {
            sorter = sorters[i];
            if (!sorter.isGrouper) {
                return sorter;    
            }
        }
        return null;
    }
});

Ext.define('Ext.util.MixedCollection', {
    extend: 'Ext.util.AbstractMixedCollection',
    mixins: {
        sortable: 'Ext.util.Sortable'
    },

    
    constructor: function() {
        var me = this;
        me.callParent(arguments);
        me.addEvents('sort');
        me.mixins.sortable.initSortable.call(me);
    },

    doSort: function(sorterFn) {
        this.sortBy(sorterFn);
    },

    
    _sort : function(property, dir, fn){
        var me = this,
            i, len,
            dsc   = String(dir).toUpperCase() == 'DESC' ? -1 : 1,

            
            c     = [],
            keys  = me.keys,
            items = me.items;

        
        fn = fn || function(a, b) {
            return a - b;
        };

        
        for(i = 0, len = items.length; i < len; i++){
            c[c.length] = {
                key  : keys[i],
                value: items[i],
                index: i
            };
        }

        
        Ext.Array.sort(c, function(a, b){
            var v = fn(a[property], b[property]) * dsc;
            if(v === 0){
                v = (a.index < b.index ? -1 : 1);
            }
            return v;
        });

        
        for(i = 0, len = c.length; i < len; i++){
            items[i] = c[i].value;
            keys[i]  = c[i].key;
        }

        me.fireEvent('sort', me);
    },

    
    sortBy: function(sorterFn) {
        var me     = this,
            items  = me.items,
            keys   = me.keys,
            length = items.length,
            temp   = [],
            i;

        
        for (i = 0; i < length; i++) {
            temp[i] = {
                key  : keys[i],
                value: items[i],
                index: i
            };
        }

        Ext.Array.sort(temp, function(a, b) {
            var v = sorterFn(a.value, b.value);
            if (v === 0) {
                v = (a.index < b.index ? -1 : 1);
            }

            return v;
        });

        
        for (i = 0; i < length; i++) {
            items[i] = temp[i].value;
            keys[i]  = temp[i].key;
        }

        me.fireEvent('sort', me, items, keys);
    },

    
    findInsertionIndex: function(newItem, sorterFn) {
        var me    = this,
            items = me.items,
            start = 0,
            end   = items.length - 1,
            middle,
            comparison;

        if (!sorterFn) {
            sorterFn = me.generateComparator();
        }
        while (start <= end) {
            middle = (start + end) >> 1;
            comparison = sorterFn(newItem, items[middle]);
            if (comparison >= 0) {
                start = middle + 1;
            } else if (comparison < 0) {
                end = middle - 1;
            }
        }
        return start;
    },

    
    reorder: function(mapping) {
        var me = this,
            items = me.items,
            index = 0,
            length = items.length,
            order = [],
            remaining = [],
            oldIndex;

        me.suspendEvents();

        
        for (oldIndex in mapping) {
            order[mapping[oldIndex]] = items[oldIndex];
        }

        for (index = 0; index < length; index++) {
            if (mapping[index] == undefined) {
                remaining.push(items[index]);
            }
        }

        for (index = 0; index < length; index++) {
            if (order[index] == undefined) {
                order[index] = remaining.shift();
            }
        }

        me.clear();
        me.addAll(order);

        me.resumeEvents();
        me.fireEvent('sort', me);
    },

    
    sortByKey : function(dir, fn){
        this._sort('key', dir, fn || function(a, b){
            var v1 = String(a).toUpperCase(), v2 = String(b).toUpperCase();
            return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
        });
    }
});


Ext.define('Ext.container.DockingContainer', {

    

    requires: ['Ext.util.MixedCollection', 'Ext.Element' ],

    

    isDockingContainer: true,

    
    defaultDockWeights: {
        top:    { render: 1, visual: 1 },
        left:   { render: 3, visual: 5 },
        right:  { render: 5, visual: 7 },
        bottom: { render: 7, visual: 3 }
    },

    
    
    
    
    dockOrder: {
        top: -1,
        left: -1,
        right: 1,
        bottom: 1
    },

    
    addDocked : function(items, pos) {
        var me = this,
            i = 0,
            item, length;

        items = me.prepareItems(items);
        length = items.length;

        for (; i < length; i++) {
            item = items[i];
            item.dock = item.dock || 'top';

            if (pos !== undefined) {
                me.dockedItems.insert(pos + i, item);
            } else {
                me.dockedItems.add(item);
            }
            if (item.onAdded !== Ext.emptyFn) {
                item.onAdded(me, i);
            }
            if (me.onDockedAdd !== Ext.emptyFn) {
                me.onDockedAdd(item);
            }
        }

        if (me.rendered && !me.suspendLayout) {
            me.updateLayout();
        }
        return items;
    },

    destroyDockedItems: function(){
        var dockedItems = this.dockedItems,
            c;

        if (dockedItems) {
            while ((c = dockedItems.first())) {
                this.removeDocked(c, true);
            }
        }
    },

    doRenderDockedItems: function (out, renderData, after) {
        
        
        

        
        
        
        
        var me = renderData.$comp,
            layout = me.componentLayout,
            items,
            tree;

        if (layout.getDockedItems && !renderData.$skipDockedItems) {
            items = layout.getDockedItems('render', !after);
            tree = items && layout.getItemsRenderTree(items);

            if (tree) {
                Ext.DomHelper.generateMarkup(tree, out);
            }
        }
    },

    
    getDockedComponent: function(comp) {
        if (Ext.isObject(comp)) {
            comp = comp.getItemId();
        }
        return this.dockedItems.get(comp);
    },

    
    getDockedItems : function(selector, beforeBody) {
        var dockedItems = this.getComponentLayout().getDockedItems('render', beforeBody);

        if (selector && dockedItems.length) {
            dockedItems = Ext.ComponentQuery.query(selector, dockedItems);
        }

        return dockedItems;
    },

    getDockingRefItems: function(deep, containerItems) {
        
        var selector = deep && '*,* *',
            
            dockedItems = this.getDockedItems(selector, true),
            items;

        
        dockedItems.push.apply(dockedItems, containerItems);

        
        items = this.getDockedItems(selector, false);
        dockedItems.push.apply(dockedItems, items);

        return dockedItems;
    },

    initDockingItems: function() {
        var me = this,
            items = me.dockedItems;

        me.dockedItems = new Ext.util.AbstractMixedCollection(false, me.getComponentId);
        if (items) {
            me.addDocked(items);
        }
    },

    
    insertDocked : function(pos, items) {
        this.addDocked(items, pos);
    },

    
    
    onDockedAdd : Ext.emptyFn,
    
    onDockedRemove : Ext.emptyFn,

    
    removeDocked : function(item, autoDestroy) {
        var me = this,
            layout,
            hasLayout;

        if (!me.dockedItems.contains(item)) {
            return item;
        }

        layout = me.componentLayout;
        hasLayout = layout && me.rendered;

        if (hasLayout) {
            layout.onRemove(item);
        }

        me.dockedItems.remove(item);
        item.onRemoved();
        me.onDockedRemove(item);

        if (autoDestroy === true || (autoDestroy !== false && me.autoDestroy)) {
            item.destroy();
        } else if (hasLayout) {
            
            layout.afterRemove(item);
        }

        if (!me.destroying && !me.suspendLayout) {
            me.updateLayout();
        }

        return item;
    },

    setupDockingRenderTpl: function (renderTpl) {
        renderTpl.renderDockedItems = this.doRenderDockedItems;
    }
});


Ext.define('Ext.data.AbstractStore', {
	requires: [
        'Ext.util.MixedCollection',
        'Ext.data.proxy.Proxy',
        'Ext.data.Operation',
        'Ext.util.Filter'
    ],

    mixins: {
        observable: 'Ext.util.Observable',
        sortable: 'Ext.util.Sortable'
    },

    statics: {
        
        create: function(store) {
            if (!store.isStore) {
                if (!store.type) {
                    store.type = 'store';
                }
                store = Ext.createByAlias('store.' + store.type, store);
            }
            return store;
        }
    },

    
    remoteSort  : false,

    
    remoteFilter: false,

    

    
    autoLoad: undefined,

    
    autoSync: false,

    
    batchUpdateMode: 'operation',

    
    filterOnLoad: true,

    
    sortOnLoad: true,

    
    implicitModel: false,

    
    defaultProxyType: 'memory',

    
    isDestroyed: false,

    
    isStore: true,

    

    

    

    

    sortRoot: 'data',

    
    constructor: function(config) {
        var me = this,
            filters;

        

        

        

        
        
        

        

        

        

        
        
        

        Ext.apply(me, config);
        

        
        me.removed = [];

        me.mixins.observable.constructor.apply(me, arguments);


        me.model = Ext.ModelManager.getModel(me.model);

        
        Ext.applyIf(me, {
            modelDefaults: {}
        });

        
        if (!me.model && me.fields) {
            me.model = Ext.define('Ext.data.Store.ImplicitModel-' + (me.storeId || Ext.id()), {
                extend: 'Ext.data.Model',
                fields: me.fields,
                proxy: me.proxy || me.defaultProxyType
            });

            delete me.fields;

            me.implicitModel = true;
        }


        
        me.setProxy(me.proxy || me.model.getProxy());

        me.proxy.on('metachange', me.onMetaChange, me);

        if (me.id && !me.storeId) {
            me.storeId = me.id;
            delete me.id;
        }

        if (me.storeId) {
            Ext.data.StoreManager.register(me);
        }

        me.mixins.sortable.initSortable.call(me);

        
        filters = me.decodeFilters(me.filters);
        me.filters = new Ext.util.MixedCollection();
        me.filters.addAll(filters);
    },

    
    setProxy: function(proxy) {
        var me = this;

        if (proxy instanceof Ext.data.proxy.Proxy) {
            proxy.setModel(me.model);
        } else {
            if (Ext.isString(proxy)) {
                proxy = {
                    type: proxy
                };
            }
            Ext.applyIf(proxy, {
                model: me.model
            });

            proxy = Ext.createByAlias('proxy.' + proxy.type, proxy);
        }

        me.proxy = proxy;

        return me.proxy;
    },

    
    getProxy: function() {
        return this.proxy;
    },

    
    onMetaChange: function(proxy, meta) {
        this.fireEvent('metachange', this, meta);
    },

    
    create: function(data, options) {
        var me = this,
            instance = Ext.ModelManager.create(Ext.applyIf(data, me.modelDefaults), me.model.modelName),
            operation;

        options = options || {};

        Ext.applyIf(options, {
            action : 'create',
            records: [instance]
        });

        operation = new Ext.data.Operation(options);

        me.proxy.create(operation, me.onProxyWrite, me);

        return instance;
    },

    read: function() {
        return this.load.apply(this, arguments);
    },

    update: function(options) {
        var me = this,
            operation;
        options = options || {};

        Ext.applyIf(options, {
            action : 'update',
            records: me.getUpdatedRecords()
        });

        operation = new Ext.data.Operation(options);

        return me.proxy.update(operation, me.onProxyWrite, me);
    },

    
    onProxyWrite: function(operation) {
        var me = this,
            success = operation.wasSuccessful(),
            records = operation.getRecords();

        switch (operation.action) {
            case 'create':
                me.onCreateRecords(records, operation, success);
                break;
            case 'update':
                me.onUpdateRecords(records, operation, success);
                break;
            case 'destroy':
                me.onDestroyRecords(records, operation, success);
                break;
        }

        if (success) {
            me.fireEvent('write', me, operation);
            me.fireEvent('datachanged', me);
            me.fireEvent('refresh', me);
        }
        
        Ext.callback(operation.callback, operation.scope || me, [records, operation, success]);
    },
    
    
    onCreateRecords: Ext.emptyFn,
    
    
    onUpdateRecords: Ext.emptyFn,
    
    
    onDestroyRecords: function(records, operation, success) {
        if (success) {
            this.removed = [];
        }
    },

    
    destroy: function(options) {
        var me = this,
            operation;

        options = options || {};

        Ext.applyIf(options, {
            action : 'destroy',
            records: me.getRemovedRecords()
        });

        operation = new Ext.data.Operation(options);

        return me.proxy.destroy(operation, me.onProxyWrite, me);
    },

    
    onBatchOperationComplete: function(batch, operation) {
        return this.onProxyWrite(operation);
    },

    
    onBatchComplete: function(batch, operation) {
        var me = this,
            operations = batch.operations,
            length = operations.length,
            i;

        me.suspendEvents();

        for (i = 0; i < length; i++) {
            me.onProxyWrite(operations[i]);
        }

        me.resumeEvents();

        me.fireEvent('datachanged', me);
        me.fireEvent('refresh', me);
    },

    
    onBatchException: function(batch, operation) {
        
        
        
        
        
    },

    
    filterNew: function(item) {
        
        return item.phantom === true && item.isValid();
    },

    
    getNewRecords: function() {
        return [];
    },

    
    getUpdatedRecords: function() {
        return [];
    },

    
    getModifiedRecords : function(){
        return [].concat(this.getNewRecords(), this.getUpdatedRecords());
    },
    
    
    filterUpdated: function(item) {
        
        return item.dirty === true && item.phantom !== true && item.isValid();
    },

    
    getRemovedRecords: function() {
        return this.removed;
    },

    filter: function(filters, value) {

    },

    
    decodeFilters: function(filters) {
        if (!Ext.isArray(filters)) {
            if (filters === undefined) {
                filters = [];
            } else {
                filters = [filters];
            }
        }

        var length = filters.length,
            Filter = Ext.util.Filter,
            config, i;

        for (i = 0; i < length; i++) {
            config = filters[i];

            if (!(config instanceof Filter)) {
                Ext.apply(config, {
                    root: 'data'
                });

                
                if (config.fn) {
                    config.filterFn = config.fn;
                }

                
                if (typeof config == 'function') {
                    config = {
                        filterFn: config
                    };
                }

                filters[i] = new Filter(config);
            }
        }

        return filters;
    },

    clearFilter: function(supressEvent) {

    },

    isFiltered: function() {

    },

    filterBy: function(fn, scope) {

    },

    
    sync: function(options) {
        var me = this,
            operations = {},
            toCreate = me.getNewRecords(),
            toUpdate = me.getUpdatedRecords(),
            toDestroy = me.getRemovedRecords(),
            needsSync = false;

        if (toCreate.length > 0) {
            operations.create = toCreate;
            needsSync = true;
        }

        if (toUpdate.length > 0) {
            operations.update = toUpdate;
            needsSync = true;
        }

        if (toDestroy.length > 0) {
            operations.destroy = toDestroy;
            needsSync = true;
        }

        if (needsSync && me.fireEvent('beforesync', operations) !== false) {
            options = options || {};

            me.proxy.batch(Ext.apply(options, {
                operations: operations,
                listeners: me.getBatchListeners()
            }));
        }
        
        return me;
    },
    
    
    getBatchListeners: function() {
        var me = this,
            listeners = {
                scope: me,
                exception: me.onBatchException
            };

        if (me.batchUpdateMode == 'operation') {
            listeners.operationcomplete = me.onBatchOperationComplete;
        } else {
            listeners.complete = me.onBatchComplete;
        }

        return listeners;
    },

    
    save: function() {
        return this.sync.apply(this, arguments);
    },

    
    load: function(options) {
        var me = this,
            operation;

        options = Ext.apply({
            action: 'read',
            filters: me.filters.items,
            sorters: me.getSorters()
        }, options);
        me.lastOptions = options;

        operation = new Ext.data.Operation(options);

        if (me.fireEvent('beforeload', me, operation) !== false) {
            me.loading = true;
            me.proxy.read(operation, me.onProxyLoad, me);
        }

        return me;
    },

    
    reload: function(options) {
        return this.load(Ext.apply(this.lastOptions, options));
    },

    
    afterEdit : function(record, modifiedFieldNames) {
        var me = this,
            i, shouldSync;

        if (me.autoSync && !me.autoSyncSuspended) {
            for (i = modifiedFieldNames.length; i--;) {
                
                if (record.fields.get(modifiedFieldNames[i]).persist) {
                    shouldSync = true;
                    break;
                }
            }
            if (shouldSync) {
                me.sync();
            }
        }

        me.fireEvent('update', me, record, Ext.data.Model.EDIT, modifiedFieldNames);
    },

    
    afterReject : function(record) {
        
        
        
        
        
        this.fireEvent('update', this, record, Ext.data.Model.REJECT, null);
    },

    
    afterCommit : function(record) {
        
        
        
        
        
        this.fireEvent('update', this, record, Ext.data.Model.COMMIT, null);
    },

    
    destroyStore: function() {
        var me = this;

        if (!me.isDestroyed) {
            if (me.storeId) {
                Ext.data.StoreManager.unregister(me);
            }
            me.clearData();
            me.data = me.tree = me.sorters = me.filters = me.groupers = null;
            if (me.reader) {
                me.reader.destroyReader();
            }
            me.proxy = me.reader = me.writer = null;
            me.clearListeners();
            me.isDestroyed = true;

            if (me.implicitModel) {
                Ext.destroy(me.model);
            } else {
                me.model = null;
            }
        }
    },

    
    doSort: function(sorterFn) {
        var me = this;
        if (me.remoteSort) {
            
            me.load();
        } else {
            me.data.sortBy(sorterFn);
            me.fireEvent('datachanged', me);
            me.fireEvent('refresh', me);
        }
    },

    
    clearData: Ext.emptyFn,
    
    
    getCount: Ext.emptyFn,

    
    getById: Ext.emptyFn,

    
    removeAll: Ext.emptyFn,
    
    

    
    isLoading: function() {
        return !!this.loading;
    },

    
    suspendAutoSync: function() {
        this.autoSyncSuspended = true;
    },

    
    resumeAutoSync: function() {
        this.autoSyncSuspended = false;
    }

});


Ext.define('Ext.data.Errors', {
    extend: 'Ext.util.MixedCollection',

    
    isValid: function() {
        return this.length === 0;
    },

    
    getByField: function(fieldName) {
        var errors = [],
            error, field, i;

        for (i = 0; i < this.length; i++) {
            error = this.items[i];

            if (error.field == fieldName) {
                errors.push(error);
            }
        }

        return errors;
    }
});


Ext.define('Ext.data.Model', {
    alternateClassName: 'Ext.data.Record',

    mixins: {
        observable: 'Ext.util.Observable'
    },
    
    requires: [
        'Ext.ModelManager',
        'Ext.data.IdGenerator',
        'Ext.data.Field',
        'Ext.data.Errors',
        'Ext.data.Operation',
        'Ext.data.validations',
        'Ext.util.MixedCollection'
    ],

    compareConvertFields: function(f1, f2) {
        var f1SpecialConvert = f1.convert && f1.type && f1.convert !== f1.type.convert,
            f2SpecialConvert = f2.convert && f2.type && f2.convert !== f2.type.convert;

        if (f1SpecialConvert && !f2SpecialConvert) {
            return 1;
        }

        if (!f1SpecialConvert && f2SpecialConvert) {
            return -1;
        }
        return 0;
    },

    itemNameFn: function(item) {
        return item.name;
    },

    onClassExtended: function(cls, data, hooks) {
        var onBeforeClassCreated = hooks.onBeforeCreated;

        hooks.onBeforeCreated = function(cls, data) {
            var me = this,
                name = Ext.getClassName(cls),
                prototype = cls.prototype,
                superCls = cls.prototype.superclass,

                validations = data.validations || [],
                fields = data.fields || [],
                field,
                associationsConfigs = data.associations || [],
                addAssociations = function(items, type) {
                    var i = 0,
                        len,
                        item;

                    if (items) {
                        items = Ext.Array.from(items);

                        for (len = items.length; i < len; ++i) {
                            item = items[i];

                            if (!Ext.isObject(item)) {
                                item = {model: item};
                            }

                            item.type = type;
                            associationsConfigs.push(item);
                        }
                    }
                },
                idgen = data.idgen,

                fieldsMixedCollection = new Ext.util.MixedCollection(false, prototype.itemNameFn),

                associationsMixedCollection = new Ext.util.MixedCollection(false, prototype.itemNameFn),

                superValidations = superCls.validations,
                superFields = superCls.fields,
                superAssociations = superCls.associations,

                associationConfig, i, ln,
                dependencies = [],
                idProperty = data.idProperty || cls.prototype.idProperty,

                
                onFieldAddReplace = function(arg0, arg1, arg2) {
                    var newField,
                        pos;

                    if (fieldsMixedCollection.events.add.firing) {
                        
                        pos = arg0;
                        newField  = arg1;
                    } else {
                        
                        newField = arg2;
                        pos = arg1.originalIndex;
                    }

                    
                    
                    newField.originalIndex = pos;

                    
                    
                    
                    if (newField.mapping === idProperty || (newField.mapping == null && newField.name === idProperty)) {
                        newField.defaultValue = undefined;
                    }
                },

                
                clsProxy = data.proxy || cls.prototype.proxy || cls.prototype.defaultProxyType,

                
                fieldConvertSortFn = function() {
                    fieldsMixedCollection.sortBy(prototype.compareConvertFields);
                };

            
            cls.modelName = name;
            prototype.modelName = name;

            
            if (superValidations) {
                validations = superValidations.concat(validations);
            }

            data.validations = validations;

            
            if (superFields) {
                fields = superFields.items.concat(fields);
            }

            fieldsMixedCollection.on({
                add:     onFieldAddReplace,
                replace: onFieldAddReplace
            });  

            for (i = 0, ln = fields.length; i < ln; ++i) {
                field = fields[i];
                fieldsMixedCollection.add(field.isField ? field : new Ext.data.Field(field));
            }
            if (!fieldsMixedCollection.get(idProperty)) {
                fieldsMixedCollection.add(new Ext.data.Field(idProperty));
            }

            
            fieldConvertSortFn();
            fieldsMixedCollection.on({
                add:     fieldConvertSortFn,
                replace: fieldConvertSortFn
            });

            data.fields = fieldsMixedCollection;

            if (idgen) {
                data.idgen = Ext.data.IdGenerator.get(idgen);
            }

            
            
            addAssociations(data.belongsTo, 'belongsTo');
            delete data.belongsTo;
            addAssociations(data.hasMany, 'hasMany');
            delete data.hasMany;
            addAssociations(data.hasOne, 'hasOne');
            delete data.hasOne;

            if (superAssociations) {
                associationsConfigs = superAssociations.items.concat(associationsConfigs);
            }

            for (i = 0, ln = associationsConfigs.length; i < ln; ++i) {
                dependencies.push('association.' + associationsConfigs[i].type.toLowerCase());
            }

            
            if (clsProxy && !clsProxy.isProxy) {

                dependencies.push('proxy.' + (typeof clsProxy === 'string' ? clsProxy : clsProxy.type));
            }

            Ext.require(dependencies, function() {
                Ext.ModelManager.registerType(name, cls);

                for (i = 0, ln = associationsConfigs.length; i < ln; ++i) {
                    associationConfig = associationsConfigs[i];
                    if (associationConfig.isAssociation) {
                        associationConfig = Ext.applyIf({
                            ownerModel: name,
                            associatedModel: associationConfig.model
                        }, associationConfig.initialConfig);
                    } else {
                        Ext.apply(associationConfig, {
                            ownerModel: name,
                            associatedModel: associationConfig.model
                        });
                    }

                    if (Ext.ModelManager.getModel(associationConfig.model) === undefined) {
                        Ext.ModelManager.registerDeferredAssociation(associationConfig);
                    } else {
                        associationsMixedCollection.add(Ext.data.association.Association.create(associationConfig));
                    }
                }

                data.associations = associationsMixedCollection;

                
                
                
                
                
                onBeforeClassCreated.call(me, cls, data, hooks);

                cls.setProxy(clsProxy);

                
                Ext.ModelManager.onModelDefined(cls);
            });
        };
    },

    inheritableStatics: {
        
        setProxy: function(proxy) {
            
            if (!proxy.isProxy) {
                if (typeof proxy == "string") {
                    proxy = {
                        type: proxy
                    };
                }
                proxy = Ext.createByAlias("proxy." + proxy.type, proxy);
            }
            proxy.setModel(this);
            this.proxy = this.prototype.proxy = proxy;

            return proxy;
        },

        
        getProxy: function() {
            return this.proxy;
        },

        
        setFields: function(fields, idProperty, clientIdProperty) {
            var me = this,
                proto = me.prototype,
                prototypeFields = proto.fields,
                len = fields ? fields.length : 0,
                i = 0;


            if (idProperty) {
                proto.idProperty = idProperty;
            }
            if (clientIdProperty) {
                proto.clientIdProperty = clientIdProperty;
            }

            if (prototypeFields) {
                prototypeFields.clear();
            }
            else {
                prototypeFields = me.prototype.fields = new Ext.util.MixedCollection(false, function(field) {
                    return field.name;
                });
            }

            for (; i < len; i++) {
                prototypeFields.add(new Ext.data.Field(fields[i]));
            }
            if (!prototypeFields.get(proto.idProperty)) {
                prototypeFields.add(new Ext.data.Field(proto.idProperty));
            }

            me.fields = prototypeFields;

            return prototypeFields;
        },

        
        getFields: function() {
            return this.prototype.fields.items;
        },

        
        load: function(id, config) {
            config = Ext.apply({}, config);
            config = Ext.applyIf(config, {
                action: 'read',
                id    : id
            });

            var operation  = new Ext.data.Operation(config),
                scope      = config.scope || this,
                record     = null,
                callback;

            callback = function(operation) {
                if (operation.wasSuccessful()) {
                    record = operation.getRecords()[0];
                    Ext.callback(config.success, scope, [record, operation]);
                } else {
                    Ext.callback(config.failure, scope, [record, operation]);
                }
                Ext.callback(config.callback, scope, [record, operation]);
            };

            this.proxy.read(operation, callback, this);
        }
    },

    statics: {
        
        PREFIX : 'ext-record',
        
        AUTO_ID: 1,
        
        EDIT   : 'edit',
        
        REJECT : 'reject',
        
        COMMIT : 'commit',

        
        id: function(rec) {
            var id = [this.PREFIX, '-', this.AUTO_ID++].join('');
            rec.phantom = true;
            rec.internalId = id;
            return id;
        }
    },

    
    idgen: {
        isGenerator: true,
        type: 'default',

        generate: function () {
            return null;
        },
        getRecId: function (rec) {
            return rec.modelName + '-' + rec.internalId;
        }
    },

    
    editing : false,

    
    dirty : false,

    
    persistenceProperty: 'data',

    evented: false,

    
    isModel: true,

    
    phantom : false,

    
    idProperty: 'id',

    
    clientIdProperty: null,

    
    defaultProxyType: 'ajax',

    
    
    

    

    
    
    
    
    

    

    
    constructor: function(data, id, raw, convertedData) {
        
        
        
        
        data = data || {};

        var me = this,
            fields,
            length,
            field,
            name,
            value,
            newId,
            persistenceProperty,
            i;


        
        me.internalId = (id || id === 0) ? id : Ext.data.Model.id(me);

        
        me.raw = raw || data; 

        if (!me.data) {
            me.data = {};
        }

        
        me.modified = {};

        
        if (me.persistanceProperty) {
            me.persistenceProperty = me.persistanceProperty;
        }

        me[me.persistenceProperty] = convertedData || {};

        me.mixins.observable.constructor.call(me);

        if (!convertedData) {
            
            fields = me.fields.items;
            length = fields.length;
            i = 0;
            persistenceProperty = me[me.persistenceProperty];

            if (Ext.isArray(data)) {
                for (; i < length; i++) {
                    field = fields[i];
                    name  = field.name;

                    
                    
                    value = data[field.originalIndex];

                    if (value === undefined) {
                        value = field.defaultValue;
                    }
                    
                    
                    if (field.convert) {
                        value = field.convert(value, me);
                    }
                    
                    if (value !== undefined) {
                        persistenceProperty[name] = value;
                    }
                }

            } else {
               for (; i < length; i++) {
                    field = fields[i];
                    name  = field.name;
                    value = data[name];
                    if (value === undefined) {
                        value = field.defaultValue;
                    }
                    if (field.convert) {
                        value = field.convert(value, me);
                    }
                    
                    if (value !== undefined) {
                        persistenceProperty[name] = value;
                    }
               }
            }
        }

        
        me.stores = [];

        if (me.getId()) {
            me.phantom = false;
        } else if (me.phantom) {
            newId = me.idgen.generate();
            if (newId !== null) {
                me.setId(newId);
            }
        }

        
        me.dirty = false;
        me.modified = {};

        if (typeof me.init == 'function') {
            me.init();
        }

        me.id = me.idgen.getRecId(me);
    },

    
    get: function(field) {
        return this[this.persistenceProperty][field];
    },

    
    
    
    _singleProp: {},

    
    set: function (fieldName, newValue) {
        var me = this,
            data = me[me.persistenceProperty],
            fields = me.fields,
            modified = me.modified,
            single = (typeof fieldName == 'string'),
            currentValue, field, idChanged, key, modifiedFieldNames, name, oldId,
            newId, value, values;

        if (single) {
            values = me._singleProp;
            values[fieldName] = newValue;
        } else {
            values = fieldName;
        }

        for (name in values) {
            if (values.hasOwnProperty(name)) {
                value = values[name];

                if (fields && (field = fields.get(name)) && field.convert) {
                    value = field.convert(value, me);
                }

                currentValue = data[name];
                if (me.isEqual(currentValue, value)) {
                    continue; 
                }

                data[name] = value;
                (modifiedFieldNames || (modifiedFieldNames = [])).push(name);

                if (field && field.persist) {
                    if (modified.hasOwnProperty(name)) {
                        if (me.isEqual(modified[name], value)) {
                            
                            
                            delete modified[name];

                            
                            
                            
                            me.dirty = false;
                            for (key in modified) {
                                if (modified.hasOwnProperty(key)){
                                    me.dirty = true;
                                    break;
                                }
                            }
                        }
                    } else {
                        me.dirty = true;
                        modified[name] = currentValue;
                    }
                }

                if (name == me.idProperty) {
                    idChanged = true;
                    oldId = currentValue;
                    newId = value;
                }
            }
        }

        if (single) {
            
            
            delete values[fieldName];
        }

        if (idChanged) {
            me.fireEvent('idchanged', me, oldId, newId);
        }

        if (!me.editing && modifiedFieldNames) {
            me.afterEdit(modifiedFieldNames);
        }

        return modifiedFieldNames || null;
    },

    
    copyFrom: function(sourceRecord) {
        if (sourceRecord) {

            var me = this,
                fields = me.fields.items,
                fieldCount = fields.length,
                field, i = 0,
                myData = me[me.persistenceProperty],
                sourceData = sourceRecord[sourceRecord.persistenceProperty],
                value;

            for (; i < fieldCount; i++) {
                field = fields[i];

                
                
                
                
                
                value = sourceData[field.name];
                if (value !== undefined) {
                    myData[field.name] = value;
                }
            }

            
            if (me.phantom && !sourceRecord.phantom) {
                me.setId(sourceRecord.getId());
            }
        }
    },

    
    isEqual: function(a, b){
        if (Ext.isDate(a) && Ext.isDate(b)) {
            return Ext.Date.isEqual(a, b);
        }
        return a === b;
    },

    
    beginEdit : function(){
        var me = this;
        if (!me.editing) {
            me.editing = true;
            me.dirtySave = me.dirty;
            me.dataSave = Ext.apply({}, me[me.persistenceProperty]);
            me.modifiedSave = Ext.apply({}, me.modified);
        }
    },

    
    cancelEdit : function(){
        var me = this;
        if (me.editing) {
            me.editing = false;
            
            me.modified = me.modifiedSave;
            me[me.persistenceProperty] = me.dataSave;
            me.dirty = me.dirtySave;
            delete me.modifiedSave;
            delete me.dataSave;
            delete me.dirtySave;
        }
    },

    
    endEdit : function(silent, modifiedFieldNames){
        var me = this,
            changed;
        if (me.editing) {
            me.editing = false;
            if(!modifiedFieldNames) {
                modifiedFieldNames = me.getModifiedFieldNames();
            }
            changed = me.dirty || modifiedFieldNames.length > 0;
            delete me.modifiedSave;
            delete me.dataSave;
            delete me.dirtySave;
            if (changed && silent !== true) {
                me.afterEdit(modifiedFieldNames);
            }
        }
    },

    
    getModifiedFieldNames: function(){
        var me = this,
            saved = me.dataSave,
            data = me[me.persistenceProperty],
            modified = [],
            key;

        for (key in data) {
            if (data.hasOwnProperty(key)) {
                if (!me.isEqual(data[key], saved[key])) {
                    modified.push(key);
                }
            }
        }
        return modified; 
    },

    
    getChanges : function(){
        var modified = this.modified,
            changes  = {},
            field;

        for (field in modified) {
            if (modified.hasOwnProperty(field)){
                changes[field] = this.get(field);
            }
        }

        return changes;
    },

    
    isModified : function(fieldName) {
        return this.modified.hasOwnProperty(fieldName);
    },

    
    setDirty : function() {
        var me     = this,
            fields = me.fields.items,
            fLen   = fields.length,
            field, name, f;

        me.dirty = true;

        for (f = 0; f < fLen; f++) {
            field = fields[f];

            if (field.persist) {
                name  = field.name;
                me.modified[name] = me.get(name);
            }
        }
    },


    
    reject : function(silent) {
        var me = this,
            modified = me.modified,
            field;

        for (field in modified) {
            if (modified.hasOwnProperty(field)) {
                if (typeof modified[field] != "function") {
                    me[me.persistenceProperty][field] = modified[field];
                }
            }
        }

        me.dirty = false;
        me.editing = false;
        me.modified = {};

        if (silent !== true) {
            me.afterReject();
        }
    },

    
    commit : function(silent) {
        var me = this;

        me.phantom = me.dirty = me.editing = false;
        me.modified = {};

        if (silent !== true) {
            me.afterCommit();
        }
    },

    
    copy : function(newId) {
        var me = this;

        
        
        return new me.self(me.raw, newId, null, Ext.apply({}, me[me.persistenceProperty]));
    },

    
    setProxy: function(proxy) {
        
        if (!proxy.isProxy) {
            if (typeof proxy === "string") {
                proxy = {
                    type: proxy
                };
            }
            proxy = Ext.createByAlias("proxy." + proxy.type, proxy);
        }
        proxy.setModel(this.self);
        this.proxy = proxy;

        return proxy;
    },

    
    getProxy: function() {
        return this.proxy;
    },

    
    validate: function() {
        var errors      = new Ext.data.Errors(),
            validations = this.validations,
            validators  = Ext.data.validations,
            length, validation, field, valid, type, i;

        if (validations) {
            length = validations.length;

            for (i = 0; i < length; i++) {
                validation = validations[i];
                field = validation.field || validation.name;
                type  = validation.type;
                valid = validators[type](validation, this.get(field));

                if (!valid) {
                    errors.add({
                        field  : field,
                        message: validation.message || validators[type + 'Message']
                    });
                }
            }
        }

        return errors;
    },

    
    isValid: function(){
        return this.validate().isValid();
    },

    
    save: function(options) {
        options = Ext.apply({}, options);

        var me     = this,
            action = me.phantom ? 'create' : 'update',
            scope  = options.scope || me,
            stores = me.stores,
            i = 0,
            storeCount,
            store,
            args,
            operation,
            callback;

        Ext.apply(options, {
            records: [me],
            action : action
        });

        operation = new Ext.data.Operation(options);

        callback = function(operation) {
            args = [me, operation];
            if (operation.wasSuccessful()) {
                for(storeCount = stores.length; i < storeCount; i++) {
                    store = stores[i];
                    store.fireEvent('write', store, operation);
                    store.fireEvent('datachanged', store);
                    
                }
                Ext.callback(options.success, scope, args);
            } else {
                Ext.callback(options.failure, scope, args);
            }

            Ext.callback(options.callback, scope, args);
        };

        me.getProxy()[action](operation, callback, me);

        return me;
    },

    
    destroy: function(options){
        options = Ext.apply({}, options);

        var me     = this,
            scope  = options.scope || me,
            stores = me.stores,
            i = 0,
            storeCount,
            store,
            args,
            operation,
            callback;

        Ext.apply(options, {
            records: [me],
            action : 'destroy'
        });

        operation = new Ext.data.Operation(options);
        callback = function(operation) {
            args = [me, operation];
            if (operation.wasSuccessful()) {
                for(storeCount = stores.length; i < storeCount; i++) {
                    store = stores[i];
                    store.fireEvent('write', store, operation);
                    store.fireEvent('datachanged', store);
                    
                }
                me.clearListeners();
                Ext.callback(options.success, scope, args);
            } else {
                Ext.callback(options.failure, scope, args);
            }
            Ext.callback(options.callback, scope, args);
        };

        me.getProxy().destroy(operation, callback, me);
        return me;
    },

    
    getId: function() {
        return this.get(this.idProperty);
    },

    
    getObservableId: function() {
        return this.id;
    },

    
    setId: function(id) {
        this.set(this.idProperty, id);
        this.phantom  = !(id || id === 0);
    },

    
    join : function(store) {
        Ext.Array.include(this.stores, store);

        
        this.store = this.stores[0]; 
    },

    
    unjoin: function(store) {
        Ext.Array.remove(this.stores, store);
        this.store = this.stores[0] || null; 
    },

    
    afterEdit : function(modifiedFieldNames) {
        this.callStore('afterEdit', modifiedFieldNames);
    },

    
    afterReject : function() {
        this.callStore("afterReject");
    },

    
    afterCommit: function() {
        this.callStore('afterCommit');
    },

    
    callStore: function(fn) {
        var args = Ext.Array.clone(arguments),
            stores = this.stores,
            i = 0,
            len = stores.length,
            store, treeStore;

        args[0] = this;
        for (; i < len; ++i) {
            store = stores[i];
            if (store && typeof store[fn] == "function") {
                store[fn].apply(store, args);
            }
            
            treeStore = store.treeStore;
            if (treeStore && typeof treeStore[fn] == "function") {
                treeStore[fn].apply(treeStore, args);
            }
        }
    },

    
    getData: function(includeAssociated){
        var me     = this,
            fields = me.fields.items,
            fLen   = fields.length,
            data   = {},
            name, f;

        for (f = 0; f < fLen; f++) {
            name = fields[f].name;
            data[name] = me.get(name);
        }

        if (includeAssociated === true) {
            Ext.apply(data, me.getAssociatedData());
        }
        return data;
    },

    
    getAssociatedData: function(){
        return this.prepareAssociatedData({}, 1);
    },

    
    prepareAssociatedData: function(seenKeys, depth) {
        
        var me               = this,
            associations     = me.associations.items,
            associationCount = associations.length,
            associationData  = {},
            
            
            
            toRead           = [],
            toReadKey        = [],
            toReadIndex      = [],
            associatedStore, associatedRecords, associatedRecord, o, index, result, seenDepth,
            associationId, associatedRecordCount, association, i, j, type, name;

        for (i = 0; i < associationCount; i++) {
            association = associations[i];
            associationId = association.associationId;
            
            seenDepth = seenKeys[associationId];
            if (seenDepth && seenDepth !== depth) {
                continue;
            }
            seenKeys[associationId] = depth;

            type = association.type;
            name = association.name;
            if (type == 'hasMany') {
                
                associatedStore = me[association.storeName];

                
                associationData[name] = [];

                
                if (associatedStore && associatedStore.getCount() > 0) {
                    associatedRecords = associatedStore.data.items;
                    associatedRecordCount = associatedRecords.length;

                    
                    
                    for (j = 0; j < associatedRecordCount; j++) {
                        associatedRecord = associatedRecords[j];
                        associationData[name][j] = associatedRecord.getData();
                        toRead.push(associatedRecord);
                        toReadKey.push(name);
                        toReadIndex.push(j);
                    }
                }
            } else if (type == 'belongsTo' || type == 'hasOne') {
                associatedRecord = me[association.instanceName];
                
                if (associatedRecord !== undefined) {
                    associationData[name] = associatedRecord.getData();
                    toRead.push(associatedRecord);
                    toReadKey.push(name);
                    toReadIndex.push(-1);
                }
            }
        }
        
        for (i = 0, associatedRecordCount = toRead.length; i < associatedRecordCount; ++i) {
            associatedRecord = toRead[i];
            o = associationData[toReadKey[i]];
            index = toReadIndex[i];
            result = associatedRecord.prepareAssociatedData(seenKeys, depth + 1);
            if (index === -1) {
                Ext.apply(o, result);
            } else {
                Ext.apply(o[index], result);
            }
        }

        return associationData;
    }
});

Ext.define('Ext.data.StoreManager', {
    extend: 'Ext.util.MixedCollection',
    alternateClassName: ['Ext.StoreMgr', 'Ext.data.StoreMgr', 'Ext.StoreManager'],
    singleton: true,
    uses: ['Ext.data.ArrayStore'],
    
    

    
    register : function() {
        for (var i = 0, s; (s = arguments[i]); i++) {
            this.add(s);
        }
    },

    
    unregister : function() {
        for (var i = 0, s; (s = arguments[i]); i++) {
            this.remove(this.lookup(s));
        }
    },

    
    lookup : function(store) {
        
        if (Ext.isArray(store)) {
            var fields = ['field1'], 
                expand = !Ext.isArray(store[0]),
                data = store,
                i,
                len;
                
            if(expand){
                data = [];
                for (i = 0, len = store.length; i < len; ++i) {
                    data.push([store[i]]);
                }
            } else {
                for(i = 2, len = store[0].length; i <= len; ++i){
                    fields.push('field' + i);
                }
            }
            return new Ext.data.ArrayStore({
                data  : data,
                fields: fields,
                autoDestroy: true,
                autoCreated: true,
                expanded: expand
            });
        }
        
        if (Ext.isString(store)) {
            
            return this.get(store);
        } else {
            
            return Ext.data.AbstractStore.create(store);
        }
    },

    
    getKey : function(o) {
         return o.storeId;
    }
}, function() {    
    
    Ext.regStore = function(name, config) {
        var store;

        if (Ext.isObject(name)) {
            config = name;
        } else {
            config.storeId = name;
        }

        if (config instanceof Ext.data.Store) {
            store = config;
        } else {
            store = new Ext.data.Store(config);
        }

        return Ext.data.StoreManager.register(store);
    };

    
    Ext.getStore = function(name) {
        return Ext.data.StoreManager.lookup(name);
    };
});


Ext.define('Ext.data.TreeStore', {
    extend: 'Ext.data.AbstractStore',
    alias: 'store.tree',
    requires: [
        'Ext.util.Sorter',
        'Ext.data.Tree',
        'Ext.data.NodeInterface'
    ],

    

    
    clearOnLoad : true,

    
    clearRemovedOnLoad: true,

    
    nodeParam: 'node',

    
    defaultRootId: 'root',

    
    defaultRootProperty: 'children',
    
    
    rootProperty: 'children',

    
    folderSort: false,

    constructor: function(config) {
        var me = this,
            root,
            fields,
            defaultRoot;

        config = Ext.apply({}, config);

        
        fields = config.fields || me.fields;
        if (!fields) {
            config.fields = [
                {name: 'text', type: 'string'}
            ];
            defaultRoot = config.defaultRootProperty || me.defaultRootProperty;
            if (defaultRoot !== me.defaultRootProperty) {
                config.fields.push({
                    name: defaultRoot,   
                    type: 'auto',   
                    defaultValue: null, 
                    persist: false
                });
            }
        }

        me.callParent([config]);

        
        me.tree = new Ext.data.Tree();

        me.relayEvents(me.tree, [
            
            "append",

            
            "remove",

            
            "move",

            
            "insert",

            
            "beforeappend",

            
            "beforeremove",

            
            "beforemove",

            
            "beforeinsert",

            
            "expand",

            
            "collapse",

            
            "beforeexpand",

            
            "beforecollapse",

            
            "sort",

            
            "rootchange"
        ]);

        me.tree.on({
            scope: me,
            remove: me.onNodeRemove,
            
            
            beforeexpand: me.onBeforeNodeExpand,
            beforecollapse: me.onBeforeNodeCollapse,
            append: me.onNodeAdded,
            insert: me.onNodeAdded,
            sort: me.onNodeSort
        });

        me.onBeforeSort();

        root = me.root;
        if (root) {
            delete me.root;
            me.setRootNode(root);
        }

        if (Ext.isDefined(me.nodeParameter)) {
            if (Ext.isDefined(Ext.global.console)) {
                Ext.global.console.warn('Ext.data.TreeStore: nodeParameter has been deprecated. Please use nodeParam instead.');
            }
            me.nodeParam = me.nodeParameter;
            delete me.nodeParameter;
        }
    },

    
    setProxy: function(proxy) {
        var reader,
            needsRoot;

        if (proxy instanceof Ext.data.proxy.Proxy) {
            
            needsRoot = Ext.isEmpty(proxy.getReader().root);
        } else if (Ext.isString(proxy)) {
            
            needsRoot = true;
        } else {
            
            reader = proxy.reader;
            needsRoot = !(reader && !Ext.isEmpty(reader.root));
        }
        proxy = this.callParent(arguments);
        if (needsRoot) {
            reader = proxy.getReader();
            reader.root = this.defaultRootProperty;
            
            reader.buildExtractors(true);
        }
    },

    
    onBeforeSort: function() {
        if (this.folderSort) {
            this.sort({
                property: 'leaf',
                direction: 'ASC'
            }, 'prepend', false);
        }
    },

    
    onBeforeNodeExpand: function(node, callback, scope) {
        if (node.isLoaded()) {
            Ext.callback(callback, scope || node, [node.childNodes]);
        }
        else if (node.isLoading()) {
            this.on('load', function() {
                Ext.callback(callback, scope || node, [node.childNodes]);
            }, this, {single: true});
        }
        else {
            this.read({
                node: node,
                callback: function() {
                    Ext.callback(callback, scope || node, [node.childNodes]);
                }
            });
        }
    },

    
    getNewRecords: function() {
        return Ext.Array.filter(this.tree.flatten(), this.filterNew);
    },

    
    getUpdatedRecords: function() {
        return Ext.Array.filter(this.tree.flatten(), this.filterUpdated);
    },

    
    onBeforeNodeCollapse: function(node, callback, scope) {
        callback.call(scope || node, node.childNodes);
    },

    onNodeRemove: function(parent, node, isMove) {
        var me = this,
            removed = me.removed;

        if (!node.isReplace && Ext.Array.indexOf(removed, node) == -1) {
            removed.push(node);
        }

        if (me.autoSync && !me.autoSyncSuspended && !isMove) {
            me.sync();
        }
    },

    onNodeAdded: function(parent, node) {
        var me = this,
            proxy = me.getProxy(),
            reader = proxy.getReader(),
            data = node.raw || node[node.persistenceProperty],
            dataRoot;

        Ext.Array.remove(me.removed, node);

        if (!node.isLeaf()) {
            dataRoot = reader.getRoot(data);
            if (dataRoot) {
                me.fillNode(node, reader.extractData(dataRoot));
                delete data[reader.root];
            }
        }

        if (me.autoSync && !me.autoSyncSuspended && (node.phantom || node.dirty)) {
            me.sync();
        }
    },

    onNodeSort: function() {
        if(this.autoSync && !this.autoSyncSuspended) {
            this.sync();
        }
    },

    
    setRootNode: function(root,  preventLoad) {
        var me = this,
            model = me.model,
            idProperty = model.prototype.idProperty

        root = root || {};
        if (!root.isModel) {
            
            Ext.applyIf(root, {
                id: me.defaultRootId,
                text: 'Root',
                allowDrag: false
            });
            if (root[idProperty] === undefined) {
                root[idProperty] = me.defaultRootId;
            }
            Ext.data.NodeInterface.decorate(model);
            root = Ext.ModelManager.create(root, model);
        } else if (root.isModel && !root.isNode) {
            Ext.data.NodeInterface.decorate(model);
        }


        
        
        me.getProxy().getReader().buildExtractors(true);

        
        me.tree.setRootNode(root);

        
        if (preventLoad !== true && !root.isLoaded() && (me.autoLoad === true || root.isExpanded())) {
            me.load({
                node: root
            });
        }

        return root;
    },

    
    getRootNode: function() {
        return this.tree.getRootNode();
    },

    
    getNodeById: function(id) {
        return this.tree.getNodeById(id);
    },
    
    
    getById: function(id) {
        return this.getNodeById(id);    
    },

    
    load: function(options) {
        options = options || {};
        options.params = options.params || {};

        var me = this,
            node = options.node || me.tree.getRootNode();

        
        
        if (!node) {
            node = me.setRootNode({
                expanded: true
            }, true);
        }

        
        options.id = node.getId();

        if (me.clearOnLoad) {
            if(me.clearRemovedOnLoad) {
                
                me.clearRemoved(node);
            }
            
            me.tree.un('remove', me.onNodeRemove, me);
            
            node.removeAll(false);
            
            me.tree.on('remove', me.onNodeRemove, me);
        }

        Ext.applyIf(options, {
            node: node
        });
        options.params[me.nodeParam] = node ? node.getId() : 'root';

        if (node) {
            node.set('loading', true);
        }

        return me.callParent([options]);
    },

    
    clearRemoved: function(node) {
        var me = this,
            removed = me.removed,
            id = node.getId(),
            removedLength = removed.length,
            i = removedLength,
            recordsToClear = {},
            newRemoved = [],
            removedHash = {},
            removedNode,
            targetNode,
            targetId;

        if(node === me.getRootNode()) {
            
            me.removed = [];
            return;
        }

        
        for(; i--;) {
            removedNode = removed[i];
            removedHash[removedNode.getId()] = removedNode;
        }

        for(i = removedLength; i--;) {
            removedNode = removed[i];
            targetNode = removedNode;
            while(targetNode && targetNode.getId() !== id) {
                
                targetId = targetNode.get('parentId');
                targetNode = targetNode.parentNode || me.getNodeById(targetId) || removedHash[targetId];
            }
            if(targetNode) {
                
                recordsToClear[removedNode.getId()] = removedNode;
            }
        }

        
        for(i = 0; i < removedLength; i++) {
            removedNode = removed[i];
            if(!recordsToClear[removedNode.getId()]) {
                newRemoved.push(removedNode);
            }
        }

        me.removed = newRemoved;
    },

    
    fillNode: function(node, newNodes) {
        var me = this,
            ln = newNodes ? newNodes.length : 0,
            sorters = me.sorters,
            i, sortCollection,
            needsIndexSort = false,
            performLocalSort = ln && me.sortOnLoad && !me.remoteSort && sorters && sorters.items && sorters.items.length,
            node1, node2;

        
        for (i = 1; i < ln; i++) {
            node1 = newNodes[i];
            node2 = newNodes[i - 1];
            needsIndexSort = node1[node1.persistenceProperty].index != node2[node2.persistenceProperty].index;
            if (needsIndexSort) {
                break;
            }
        }

        
        if (performLocalSort) {
            
            if (needsIndexSort) {
                me.sorters.insert(0, me.indexSorter);
            }
            sortCollection = new Ext.util.MixedCollection();
            sortCollection.addAll(newNodes);
            sortCollection.sort(me.sorters.items);
            newNodes = sortCollection.items;

            
            me.sorters.remove(me.indexSorter);
        } else if (needsIndexSort) {
            Ext.Array.sort(newNodes, me.sortByIndex);
        }

        node.set('loaded', true);
        for (i = 0; i < ln; i++) {
            node.appendChild(newNodes[i], undefined, true);
        }

        return newNodes;
    },

    
    sortByIndex: function(node1, node2) {
        return node1[node1.persistenceProperty].index - node2[node2.persistenceProperty].index;
    },

    
    onProxyLoad: function(operation) {
        var me = this,
            successful = operation.wasSuccessful(),
            records = operation.getRecords(),
            node = operation.node;

        me.loading = false;
        node.set('loading', false);
        if (successful) {
            if (!me.clearOnLoad) {
                records = me.cleanRecords(node, records);
            }
            records = me.fillNode(node, records);
        }
        
        
        
        
        me.fireEvent('read', me, operation.node, records, successful);
        me.fireEvent('load', me, operation.node, records, successful);
        
        Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
    },
    
    onCreateRecords: function(records) {
        this.callParent(arguments);
        
        var i = 0,
            len = records.length,
            tree = this.tree,
            node;

        for (; i < len; ++i) {
            node = records[i];
            tree.onNodeIdChanged(node, null, node.getId());
        }
        
    },
    
    cleanRecords: function(node, records){
        var nodeHash = {},
            childNodes = node.childNodes,
            i = 0,
            len  = childNodes.length,
            out = [],
            rec;
            
        
        for (; i < len; ++i) {
            nodeHash[childNodes[i].getId()] = true;
        }
        
        for (i = 0, len = records.length; i < len; ++i) {
            rec = records[i];
            if (!nodeHash[rec.getId()]) {
                out.push(rec);    
            }
        }
        
        return out;
    },

    
    removeAll: function() {
        var root = this.getRootNode();
        if (root) {
            root.destroy(true);
        }
        this.fireEvent('clear', this);
    },

    
    doSort: function(sorterFn) {
        var me = this;
        if (me.remoteSort) {
            
            me.load();
        } else {
            me.tree.sort(sorterFn, true);
            me.fireEvent('datachanged', me);
            me.fireEvent('refresh', me);
        }
        me.fireEvent('sort', me);
    }
}, function() {
    var proto = this.prototype;
    proto.indexSorter = new Ext.util.Sorter({
        sorterFn: proto.sortByIndex
    });
});


Ext.define('Ext.data.proxy.Ajax', {
    requires: ['Ext.util.MixedCollection', 'Ext.Ajax'],
    extend: 'Ext.data.proxy.Server',
    alias: 'proxy.ajax',
    alternateClassName: ['Ext.data.HttpProxy', 'Ext.data.AjaxProxy'],
    
    
    actionMethods: {
        create : 'POST',
        read   : 'GET',
        update : 'POST',
        destroy: 'POST'
    },
    
    
    
    doRequest: function(operation, callback, scope) {
        var writer  = this.getWriter(),
            request = this.buildRequest(operation, callback, scope);
            
        if (operation.allowWrite()) {
            request = writer.write(request);
        }
        
        Ext.apply(request, {
            headers       : this.headers,
            timeout       : this.timeout,
            scope         : this,
            callback      : this.createRequestCallback(request, operation, callback, scope),
            method        : this.getMethod(request),
            disableCaching: false 
        });
        
        Ext.Ajax.request(request);
        
        return request;
    },
    
    
    getMethod: function(request) {
        return this.actionMethods[request.action];
    },
    
    
    createRequestCallback: function(request, operation, callback, scope) {
        var me = this;
        
        return function(options, success, response) {
            me.processResponse(success, operation, request, response, callback, scope);
        };
    }
}, function() {
    
    Ext.data.HttpProxy = this;
});


Ext.define('Ext.data.Store', {
    extend: 'Ext.data.AbstractStore',

    alias: 'store.store',

    
    
    
    requires: [
        'Ext.data.StoreManager',
        'Ext.data.Model',
        'Ext.data.proxy.Ajax',
        'Ext.data.proxy.Memory',
        'Ext.data.reader.Json',
        'Ext.data.writer.Json',
        'Ext.util.LruCache'
    ],

    uses: [
        'Ext.ModelManager',
        'Ext.util.Grouper'
    ],

    remoteSort: false,
    remoteFilter: false,

    
    remoteGroup : false,

    

    

    
    groupField: undefined,

    
    groupDir: "ASC",

    
    trailingBufferZone: 25,

    
    leadingBufferZone: 200,

    
    pageSize: undefined,

    
    currentPage: 1,

    
    clearOnPageLoad: true,

    
    loading: false,

    
    sortOnFilter: true,

    
    buffered: false,

    
    purgePageCount: 5,

    
    clearRemovedOnLoad: true,

    defaultPageSize: 25,

    
    addRecordsOptions: {
        addRecords: true
    },

    statics: {
        recordIdFn: function(record) {
            return record.internalId;
        },
        recordIndexFn: function(record) {
            return record.index;
        }
    },

    onClassExtended: function(cls, data, hooks) {
        var model = data.model,
            onBeforeClassCreated;

        if (typeof model == 'string') {
            onBeforeClassCreated = hooks.onBeforeCreated;

            hooks.onBeforeCreated = function() {
                var me = this,
                    args = arguments;

                Ext.require(model, function() {
                    onBeforeClassCreated.apply(me, args);
                });
            };
        }
    },

    
    constructor: function(config) {
        
        config = Ext.Object.merge({}, config);

        var me = this,
            groupers = config.groupers || me.groupers,
            groupField = config.groupField || me.groupField,
            proxy,
            data;

        
        
        
        data = config.data || me.data;

        
        me.data = new Ext.util.MixedCollection(false, Ext.data.Store.recordIdFn);

        if (data) {
            me.inlineData = data;
            delete config.data;
        }

        if (!groupers && groupField) {
            groupers = [{
                property : groupField,
                direction: config.groupDir || me.groupDir
            }];
        }
        delete config.groupers;

        
        me.groupers = new Ext.util.MixedCollection();
        me.groupers.addAll(me.decodeGroupers(groupers));

        this.callParent([config]);
        

        if (me.buffered) {

            
            me.pageMap = new me.PageMap({
                pageSize: me.pageSize,
                maxSize: me.purgePageCount,
                listeners: {
                    
                    
                    clear: me.cancelAllPrefetches,
                    scope: me
                }
            });
            me.pageRequests = {};

            me.sortOnLoad = false;
            me.filterOnLoad = false;
        }

        
        if (me.remoteGroup) {
            me.remoteSort = true;
        }
        if (me.groupers.items.length && !me.remoteGroup) {
            me.sort(me.groupers.items, 'prepend', false);
        }

        proxy = me.proxy;
        data = me.inlineData;

        
        
        if (!me.buffered && !me.pageSize) {
            me.pageSize = me.defaultPageSize;
        }

        if (data) {
            if (proxy instanceof Ext.data.proxy.Memory) {
                proxy.data = data;
                me.read();
            } else {
                me.add.apply(me, [data]);
            }

            me.sort();
            delete me.inlineData;
        } else if (me.autoLoad) {
            Ext.defer(me.load, 10, me, [ typeof me.autoLoad === 'object' ? me.autoLoad : undefined ]);
            
            
        }
    },

     
     
    destroyStore: function() {
        this.callParent(arguments);

        
        
        
        if (this.pageMap) {
            this.pageMap.clear();
        }
    },

    onBeforeSort: function() {
        var groupers = this.groupers;
        if (groupers.getCount() > 0) {
            this.sort(groupers.items, 'prepend', false);
        }
    },

    
    decodeGroupers: function(groupers) {
        if (!Ext.isArray(groupers)) {
            if (groupers === undefined) {
                groupers = [];
            } else {
                groupers = [groupers];
            }
        }

        var length = groupers.length,
            Grouper = Ext.util.Grouper,
            config, i, result = [];

        for (i = 0; i < length; i++) {
            config = groupers[i];

            if (!(config instanceof Grouper)) {
                if (Ext.isString(config)) {
                    config = {
                        property: config
                    };
                }

                config = Ext.apply({
                    root     : 'data',
                    direction: "ASC"
                }, config);

                
                if (config.fn) {
                    config.sorterFn = config.fn;
                }

                
                if (typeof config == 'function') {
                    config = {
                        sorterFn: config
                    };
                }

                
                result.push(new Grouper(config));
            } else {
                result.push(config);
            }
        }
        return result;
    },

    
    group: function(groupers, direction) {
        var me = this,
            hasNew = false,
            grouper,
            newGroupers;

        if (Ext.isArray(groupers)) {
            newGroupers = groupers;
        } else if (Ext.isObject(groupers)) {
            newGroupers = [groupers];
        } else if (Ext.isString(groupers)) {
            grouper = me.groupers.get(groupers);

            if (!grouper) {
                grouper = {
                    property : groupers,
                    direction: direction
                };
                newGroupers = [grouper];
            } else if (direction === undefined) {
                grouper.toggle();
            } else {
                grouper.setDirection(direction);
            }
        }

        if (newGroupers && newGroupers.length) {
            hasNew = true;
            newGroupers = me.decodeGroupers(newGroupers);
            me.groupers.clear();
            me.groupers.addAll(newGroupers);
        }

        if (me.remoteGroup) {
            if (me.buffered) {
                me.pageMap.clear();
                me.loadPage(1, { groupChange: true });
            } else {
                me.load({
                    scope: me,
                    callback: me.fireGroupChange
                });
            }
        } else {
            
            me.sort(null, null, null, hasNew);
            me.fireGroupChange();
        }
    },

    
    clearGrouping: function() {
        var me       = this,
            groupers = me.groupers.items,
            gLen     = groupers.length,
            grouper, g;

        for (g = 0; g < gLen; g++) {
            grouper = groupers[g];

            me.sorters.remove(grouper);
        }
        me.groupers.clear();
        if (me.remoteGroup) {
            if (me.buffered) {
                me.pageMap.clear();
                me.loadPage(1, { groupChange: true });
            } else {
                me.load({
                    scope: me,
                    callback: me.fireGroupChange
                });
            }
        } else {
            me.sort();
            me.fireGroupChange();
        }
    },

    
    isGrouped: function() {
        return this.groupers.getCount() > 0;
    },

    
    fireGroupChange: function() {
        this.fireEvent('groupchange', this, this.groupers);
    },

    
    getGroups: function(requestGroupString) {
        var records = this.data.items,
            length = records.length,
            groups = [],
            pointers = {},
            record,
            groupStr,
            group,
            i;

        for (i = 0; i < length; i++) {
            record = records[i];
            groupStr = this.getGroupString(record);
            group = pointers[groupStr];

            if (group === undefined) {
                group = {
                    name: groupStr,
                    children: []
                };

                groups.push(group);
                pointers[groupStr] = group;
            }

            group.children.push(record);
        }

        return requestGroupString ? pointers[requestGroupString] : groups;
    },

    
    getGroupsForGrouper: function(records, grouper) {
        var length = records.length,
            groups = [],
            oldValue,
            newValue,
            record,
            group,
            i;

        for (i = 0; i < length; i++) {
            record = records[i];
            newValue = grouper.getGroupString(record);

            if (newValue !== oldValue) {
                group = {
                    name: newValue,
                    grouper: grouper,
                    records: []
                };
                groups.push(group);
            }

            group.records.push(record);

            oldValue = newValue;
        }

        return groups;
    },

    
    getGroupsForGrouperIndex: function(records, grouperIndex) {
        var me = this,
            groupers = me.groupers,
            grouper = groupers.getAt(grouperIndex),
            groups = me.getGroupsForGrouper(records, grouper),
            length = groups.length,
            i;

        if (grouperIndex + 1 < groupers.length) {
            for (i = 0; i < length; i++) {
                groups[i].children = me.getGroupsForGrouperIndex(groups[i].records, grouperIndex + 1);
            }
        }

        for (i = 0; i < length; i++) {
            groups[i].depth = grouperIndex;
        }

        return groups;
    },

    
    getGroupData: function(sort) {
        var me = this;
        if (sort !== false) {
            me.sort();
        }

        return me.getGroupsForGrouperIndex(me.data.items, 0);
    },

    
    getGroupString: function(instance) {
        var group = this.groupers.first();
        if (group) {
            return instance.get(group.property);
        }
        return '';
    },

    
    insert: function(index, records) {
        var me = this,
            sync = false,
            i,
            record,
            len;

        records = [].concat(records);
        for (i = 0,len = records.length; i < len; i++) {
            record = me.createModel(records[i]);
            record.set(me.modelDefaults);
            
            records[i] = record;

            me.data.insert(index + i, record);
            record.join(me);

            sync = sync || record.phantom === true;
        }

        if (me.snapshot) {
            me.snapshot.addAll(records);
        }

        if (me.requireSort) {
            
            me.suspendEvents();
            me.sort();
            me.resumeEvents();
        }

        me.fireEvent('add', me, records, index);
        me.fireEvent('datachanged', me);
        if (me.autoSync && sync && !me.autoSyncSuspended) {
            me.sync();
        }
    },

    
    add: function(records) {
        
        if (!Ext.isArray(records)) {
            records = Array.prototype.slice.apply(arguments);
        } else {
            
            records = records.slice(0);
        }

        var me = this,
            i = 0,
            length = records.length,
            record,
            isSorted = !me.remoteSort && me.sorters && me.sorters.items.length;

        
        
        if (isSorted && length === 1) {
            return [ me.addSorted(me.createModel(records[0])) ];
        }

        for (; i < length; i++) {
            record = me.createModel(records[i]);
            
            records[i] = record;
        }

        
        
        if (isSorted) {
            me.requireSort = true;
        }

        me.insert(me.data.length, records);
        delete me.requireSort;

        return records;
    },

    
    addSorted: function(record) {
        var me = this,
            index = me.data.findInsertionIndex(record, me.generateComparator());

        me.insert(index, record);
        return record;
    },

    
    createModel: function(record) {
        if (!record.isModel) {
            record = Ext.ModelManager.create(record, this.model);
        }

        return record;
    },

    
    each: function(fn, scope) {
        var data = this.data.items,
            dLen = data.length,
            record, d;

        for (d = 0; d < dLen; d++) {
            record = data[d];
            if (fn.call(scope || record, record, d, dLen) === false) {
                break;
            }
        }
    },

    
    remove: function(records,  isMove) {
        if (!Ext.isArray(records)) {
            records = [records];
        }

        
        isMove = isMove === true;
        var me = this,
            sync = false,
            i = 0,
            length = records.length,
            isNotPhantom,
            index,
            record;

        for (; i < length; i++) {
            record = records[i];
            index = me.data.indexOf(record);

            if (me.snapshot) {
                me.snapshot.remove(record);
            }

            if (index > -1) {
                isNotPhantom = record.phantom !== true;

                
                if (!isMove && isNotPhantom) {

                    
                    
                    record.removedFrom = index;
                    me.removed.push(record);
                }

                record.unjoin(me);
                me.data.remove(record);
                sync = sync || isNotPhantom;

                me.fireEvent('remove', me, record, index);
            }
        }

        me.fireEvent('datachanged', me);
        if (!isMove && me.autoSync && sync && !me.autoSyncSuspended) {
            me.sync();
        }
    },

    
    removeAt: function(index) {
        var record = this.getAt(index);

        if (record) {
            this.remove(record);
        }
    },

    
    load: function(options) {
        var me = this;

        options = options || {};

        if (typeof options == 'function') {
            options = {
                callback: options
            };
        }

        options.groupers = options.groupers ||  me.groupers.items;
        options.page = options.page || me.currentPage;
        options.start = (options.start !== undefined) ? options.start : (options.page - 1) * me.pageSize;
        options.limit = options.limit || me.pageSize;
        options.addRecords = options.addRecords || false;

        if (me.buffered) {
            return me.loadToPrefetch(options);
        }
        return me.callParent([options]);
    },

    reload: function(options) {
        var me = this,
            startIdx,
            endIdx,
            startPage,
            endPage,
            i,
            waitForReload,
            bufferZone,
            records;

        if (!options) {
            options = {};
        }

        
        
        if (me.buffered) {

            
            delete me.totalCount;

            waitForReload = function() {
                if (me.rangeCached(startIdx, endIdx)) {
                    me.loading = false;
                    me.pageMap.un('pageAdded', waitForReload);
                    records = me.pageMap.getRange(startIdx, endIdx);
                    me.loadRecords(records, {
                        start: startIdx
                    });
                    me.fireEvent('load', me, records, true);
                }
            };
            bufferZone = Math.ceil((me.leadingBufferZone + me.trailingBufferZone) / 2);

            
            startIdx = options.start || me.getAt(0).index;
            endIdx = startIdx + (options.count || me.getCount()) - 1;

            
            startPage = me.getPageFromRecordIndex(Math.max(startIdx - bufferZone, 0));
            endPage = me.getPageFromRecordIndex(endIdx + bufferZone);

            
            me.pageMap.clear(true);

            if (me.fireEvent('beforeload', me, options) !== false) {
                me.loading = true;

                
                for (i = startPage; i <= endPage; i++) {
                    me.prefetchPage(i, options);
                }

                
                
                me.pageMap.on('pageAdded', waitForReload);
            }
        } else {
            return me.callParent(arguments);
        }
    },

    
    onProxyLoad: function(operation) {
        var me = this,
            resultSet = operation.getResultSet(),
            records = operation.getRecords(),
            successful = operation.wasSuccessful();

        if (resultSet) {
            me.totalCount = resultSet.total;
        }

        if (successful) {
            me.loadRecords(records, operation);
        }

        me.loading = false;
        if (me.hasListeners.load) {
            me.fireEvent('load', me, records, successful);
        }

        
        
        if (me.hasListeners.read) {
            me.fireEvent('read', me, records, successful);
        }

        
        Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
    },

    
    getNewRecords: function() {
        return this.data.filterBy(this.filterNew).items;
    },

    
    getUpdatedRecords: function() {
        return this.data.filterBy(this.filterUpdated).items;
    },

    
    filter: function(filters, value) {
        if (Ext.isString(filters)) {
            filters = {
                property: filters,
                value: value
            };
        }

        var me = this,
            decoded = me.decodeFilters(filters),
            i = 0,
            doLocalSort = me.sorters.length && me.sortOnFilter && !me.remoteSort,
            length = decoded.length;

        for (; i < length; i++) {
            me.filters.replace(decoded[i]);
        }

        if (me.remoteFilter) {
            
            delete me.totalCount;
            
            
            
            
            if (me.buffered) {
                me.pageMap.clear();
                me.loadPage(1);
            } else {
                
                me.currentPage = 1;
                
                me.load();
            }
        } else {
            
            if (me.filters.getCount()) {
                me.snapshot = me.snapshot || me.data.clone();
                me.data = me.data.filter(me.filters.items);

                if (doLocalSort) {
                    me.sort();
                } else {
                    
                    me.fireEvent('datachanged', me);
                    me.fireEvent('refresh', me);
                }
            }
        }
    },

    
    clearFilter: function(suppressEvent) {
        var me = this;

        me.filters.clear();

        if (me.remoteFilter) {

            
            if (suppressEvent) {
                return;
            }

            
            delete me.totalCount;

            
            
            
            if (me.buffered) {
                me.pageMap.clear();
                me.loadPage(1);
            } else {
                
                me.currentPage = 1;
                me.load();
            }
        } else if (me.isFiltered()) {
            me.data = me.snapshot.clone();
            delete me.snapshot;

            if (suppressEvent !== true) {
                me.fireEvent('datachanged', me);
                me.fireEvent('refresh', me);
            }
        }
    },

    
    isFiltered: function() {
        var snapshot = this.snapshot;
        return !! snapshot && snapshot !== this.data;
    },

    
    filterBy: function(fn, scope) {
        var me = this;

        me.snapshot = me.snapshot || me.data.clone();
        me.data = me.queryBy(fn, scope || me);
        me.fireEvent('datachanged', me);
        me.fireEvent('refresh', me);
    },

    
    queryBy: function(fn, scope) {
        var me = this,
            data = me.snapshot || me.data;
        return data.filterBy(fn, scope || me);
    },

    
    query: function(property, value, anyMatch, caseSensitive, exactMatch) {
        var me = this,
            queryFn = me.createFilterFn(property, value, anyMatch, caseSensitive, exactMatch),
            results = me.queryBy(queryFn);

        
        if(!results) {
            results = new Ext.util.MixedCollection();
        }

        return results;
    },

    
    loadData: function(data, append) {
        var me = this,
            model = me.model,
            length = data.length,
            newData = [],
            i,
            record;

        
        for (i = 0; i < length; i++) {
            record = data[i];

            if (!(record.isModel)) {
                record = Ext.ModelManager.create(record, model);
            }
            newData.push(record);
        }

        me.loadRecords(newData, append ? me.addRecordsOptions : undefined);
    },

    
    loadRawData : function(data, append) {
         var me      = this,
             result  = me.proxy.reader.read(data),
             records = result.records;

         if (result.success) {
             me.totalCount = result.total;
             me.loadRecords(records, append ? me.addRecordsOptions : undefined);
             me.fireEvent('load', me, records, true);
         }
     },

    
    loadRecords: function(records, options) {
        var me     = this,
            i      = 0,
            length = records.length,
            start,
            addRecords,
            snapshot = me.snapshot;

        if (options) {
            start = options.start;
            addRecords = options.addRecords;
        }

        if (!addRecords) {
            delete me.snapshot;
            me.clearData(true);
        } else if (snapshot) {
            snapshot.addAll(records);
        }

        me.data.addAll(records);

        if (start !== undefined) {
            for (; i < length; i++) {
                records[i].index = start + i;
                records[i].join(me);
            }
        } else {
            for (; i < length; i++) {
                records[i].join(me);
            }
        }

        
        me.suspendEvents();

        if (me.filterOnLoad && !me.remoteFilter) {
            me.filter();
        }

        if (me.sortOnLoad && !me.remoteSort) {
            me.sort(undefined, undefined, undefined, true);
        }

        me.resumeEvents();
        me.fireEvent('datachanged', me);
        me.fireEvent('refresh', me);
    },

    
    
    loadPage: function(page, options) {
        var me = this;

        me.currentPage = page;

        
        options = Ext.apply({
            page: page,
            start: (page - 1) * me.pageSize,
            limit: me.pageSize,
            addRecords: !me.clearOnPageLoad
        }, options);

        if (me.buffered) {
            return me.loadToPrefetch(options);
        }
        me.read(options);
    },

    
    nextPage: function(options) {
        this.loadPage(this.currentPage + 1, options);
    },

    
    previousPage: function(options) {
        this.loadPage(this.currentPage - 1, options);
    },

    
    clearData: function(isLoad) {
        var me = this,
            records = me.data.items,
            i = records.length;

        while (i--) {
            records[i].unjoin(me);
        }
        me.data.clear();
        if (isLoad !== true || me.clearRemovedOnLoad) {
            me.removed.length = 0;
        }
    },

    loadToPrefetch: function(options) {
        var me = this,
            i,
            records,

            
            startIdx = options.start,
            endIdx = options.start + options.limit - 1,

            
            loadEndIdx = options.start + (me.viewSize || options.limit) - 1,

            
            startPage = me.getPageFromRecordIndex(Math.max(startIdx - me.trailingBufferZone, 0)),
            endPage = me.getPageFromRecordIndex(endIdx + me.leadingBufferZone),

            
            waitForRequestedRange = function() {
                if (me.rangeCached(startIdx, loadEndIdx)) {
                    me.loading = false;
                    records = me.pageMap.getRange(startIdx, loadEndIdx);
                    me.pageMap.un('pageAdded', waitForRequestedRange);

                    
                    if (me.hasListeners.guaranteedrange) {
                        me.guaranteeRange(startIdx, loadEndIdx, options.callback, options.scope);
                    }
                    
                    else {
                        me.loadRecords(records, {
                            start: startIdx
                        });
                    }
                    me.fireEvent('load', me, records, true);
                    if (options.groupChange) {
                        me.fireGroupChange();
                    }
                }
            };

        if (me.fireEvent('beforeload', me, options) !== false) {

            
            delete me.totalCount;

            me.loading = true;

            
            me.pageMap.on('pageAdded', waitForRequestedRange);
            
            
            
            
            
            me.on('prefetch', function(){
                for (i = startPage + 1; i <= endPage; ++i) {
                    me.prefetchPage(i, options);
                }
            }, null, {single: true});
            
            me.prefetchPage(startPage, options);
        }
    },

    
    
    prefetch: function(options) {
        var me = this,
            pageSize = me.pageSize,
            proxy,
            operation;

        
        if (pageSize) {
            if (me.lastPageSize && pageSize != me.lastPageSize) {
                Ext.error.raise("pageSize cannot be dynamically altered");
            }
            if (!me.pageMap.pageSize) {
                me.pageMap.pageSize = pageSize;
            }
        }

        
        else {
            me.pageSize = me.pageMap.pageSize = pageSize = options.limit;
        }

        
        me.lastPageSize = pageSize;

        
        if (!options.page) {
            options.page = me.getPageFromRecordIndex(options.start);
            options.start = (options.page - 1) * pageSize;
            options.limit = Math.ceil(options.limit / pageSize) * pageSize;
        }

        
        if (!me.pageRequests[options.page]) {

            
            options = Ext.apply({
                action : 'read',
                filters: me.filters.items,
                sorters: me.sorters.items,
                groupers: me.groupers.items,

                
                
                generation: me.pageMap.generation
            }, options);

            operation = new Ext.data.Operation(options);

            if (me.fireEvent('beforeprefetch', me, operation) !== false) {
                me.loading = true;
                proxy = me.proxy;
                me.pageRequests[options.page] = proxy.read(operation, me.onProxyPrefetch, me);
                if (proxy.isSynchronous) {
                    delete me.pageRequests[options.page];
                }
            }
        }

        return me;
    },

    
    cancelAllPrefetches: function() {
        var me = this,
            reqs = me.pageRequests,
            req,
            page;

        
        if (me.pageMap.events.pageadded) {
            me.pageMap.events.pageadded.clearListeners();
        }

        
        for (page in reqs) {
            if (reqs.hasOwnProperty(page)) {
                req = reqs[page];
                delete reqs[page];
                delete req.callback;
            }
        }
    },

    
    prefetchPage: function(page, options) {
        var me = this,
            pageSize = me.pageSize || me.defaultPageSize,
            start = (page - 1) * me.pageSize,
            total = me.totalCount;

        
        if (total !== undefined && me.getCount() === total) {
            return;
        }

        
        me.prefetch(Ext.applyIf({
            page     : page,
            start    : start,
            limit    : pageSize
        }, options));
    },

    
    onProxyPrefetch: function(operation) {
        var me = this,
            resultSet = operation.getResultSet(),
            records = operation.getRecords(),
            successful = operation.wasSuccessful(),
            page = operation.page;

        
        
        if (operation.generation === me.pageMap.generation) {

            if (resultSet) {
                me.totalCount = resultSet.total;
                me.fireEvent('totalcountchange', me.totalCount);
            }

            
            if (page !== undefined) {
                delete me.pageRequests[page];
            }

            
            
            if (successful) {
                me.cachePage(records, operation.page);
            }

            me.loading = false;
            me.fireEvent('prefetch', me, records, successful, operation);

            
            Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
        }
    },

    
    cachePage: function(records, page) {
        var me = this;

        if (!Ext.isDefined(me.totalCount)) {
            me.totalCount = records.length;
            me.fireEvent('totalcountchange', me.totalCount);
        }

        
        me.pageMap.addPage(page, records);
    },

    
    rangeCached: function(start, end) {
        return this.pageMap && this.pageMap.hasRange(start, end);
    },

    
    pageCached: function(page) {
        return this.pageMap && this.pageMap.hasPage(page);
    },

    
    rangeSatisfied: function(start, end) {
        return this.rangeCached(start, end);
    },

    
    getPageFromRecordIndex: function(index) {
        return Math.floor(index / this.pageSize) + 1;
    },

    
    onGuaranteedRange: function(options) {
        var me = this,
            totalCount = me.getTotalCount(),
            start = options.prefetchStart,
            end = ((totalCount - 1) < options.prefetchEnd) ? totalCount - 1 : options.prefetchEnd,
            range;

        end = Math.max(0, end);


        range = me.pageMap.getRange(start, end);
        me.fireEvent('guaranteedrange', range, start, end);
        if (options.cb) {
            options.cb.call(options.scope || me, range, start, end);
        }
    },

    
    prefetchRange: function(start, end) {
        var me = this,
            startPage, endPage, page;
        if (!me.rangeCached(start, end)) {
            startPage = me.getPageFromRecordIndex(start);
            endPage = me.getPageFromRecordIndex(end);

            
            
            
            me.pageMap.maxSize = me.purgePageCount ? (endPage - startPage + 1) + me.purgePageCount : 0;

            
            for (page = startPage; page <= endPage; page++) {
                if (!me.pageCached(page)) {
                    me.prefetchPage(page);
                }
            }
        }
    },

    
    guaranteeRange: function(start, end, cb, scope) {
        
        end = (end > this.totalCount) ? this.totalCount - 1 : end;

        var me = this,
            lastRequestStart = me.lastRequestStart,
            options = {
                prefetchStart: start,
                prefetchEnd: end,
                cb: cb,
                scope: scope
            },
            pageAddHandler;

        me.lastRequestStart = start;

        
        if (me.rangeCached(start, end)) {

            
            if (start < lastRequestStart) {
                start = Math.max(start - me.leadingBufferZone, 0);
                end   = Math.min(end   + me.trailingBufferZone, me.totalCount - 1);
            } else {
                start = Math.max(Math.min(start - me.trailingBufferZone, me.totalCount - me.pageSize), 0);
                end   = Math.min(end + me.leadingBufferZone, me.totalCount - 1);
            }

            
            
            if (!me.rangeCached(start, end)) {
                
                me.prefetchRange(start, end);
            }
            me.onGuaranteedRange(options);
        }
        
        else {
            
            me.fireEvent('cachemiss', me, start, end);

            
            start = Math.min(Math.max(Math.floor(start - ((me.leadingBufferZone + me.trailingBufferZone) / 2)), 0), me.totalCount - me.pageSize);
            end =   Math.min(Math.max(Math.ceil (end   + ((me.leadingBufferZone + me.trailingBufferZone) / 2)), 0), me.totalCount - 1);

            
            pageAddHandler = function(page, records) {
                if (me.rangeCached(options.prefetchStart, options.prefetchEnd)) {
                    
                    me.fireEvent('cachefilled', me, start, end);
                    me.pageMap.un('pageAdded', pageAddHandler);
                    me.onGuaranteedRange(options);
                }
            };
            me.pageMap.on('pageAdded', pageAddHandler);

            
            
            
            me.prefetchRange(options.prefetchStart, options.prefetchEnd);

            
            me.prefetchRange(start, end);
        }
    },

    
    
    sort: function() {
        var me = this,
            prefetchData = me.pageMap;

        if (me.buffered) {
            if (me.remoteSort) {
                prefetchData.clear();
                me.callParent(arguments);
            } else {
                me.callParent(arguments);
            }
        } else {
            me.callParent(arguments);
        }
    },

    
    
    
    doSort: function(sorterFn) {
        var me = this,
            range,
            ln,
            i;
        if (me.remoteSort) {

            
            
            
            if (me.buffered) {
                me.pageMap.clear();
                me.loadPage(1);
            } else {
                
                me.load();
            }
        } else {
            me.data.sortBy(sorterFn);
            if (!me.buffered) {
                range = me.getRange();
                ln = range.length;
                for (i = 0; i < ln; i++) {
                    range[i].index = i;
                }
            }
            me.fireEvent('datachanged', me);
            me.fireEvent('refresh', me);
        }
    },

    
    find: function(property, value, start, anyMatch, caseSensitive, exactMatch) {
        var fn = this.createFilterFn(property, value, anyMatch, caseSensitive, exactMatch);
        return fn ? this.data.findIndexBy(fn, null, start) : -1;
    },

    
    findRecord: function() {
        var me = this,
            index = me.find.apply(me, arguments);
        return index !== -1 ? me.getAt(index) : null;
    },

    
    createFilterFn: function(property, value, anyMatch, caseSensitive, exactMatch) {
        if (Ext.isEmpty(value)) {
            return false;
        }
        value = this.data.createValueMatcher(value, anyMatch, caseSensitive, exactMatch);
        return function(r) {
            return value.test(r.data[property]);
        };
    },

    
    findExact: function(property, value, start) {
        return this.data.findIndexBy(function(rec) {
            return rec.isEqual(rec.get(property), value);
        },
        this, start);
    },

    
    findBy: function(fn, scope, start) {
        return this.data.findIndexBy(fn, scope, start);
    },

    
    collect: function(dataIndex, allowNull, bypassFilter) {
        var me = this,
            data = (bypassFilter === true && me.snapshot) ? me.snapshot : me.data;

        return data.collect(dataIndex, 'data', allowNull);
    },

    
    getCount: function() {
        return this.data.length || 0;
    },

    
    getTotalCount: function() {
        return this.totalCount || 0;
    },

    
    getAt: function(index) {
        return this.data.getAt(index);
    },

    
    getRange: function(start, end) {
        return this.data.getRange(start, end);
    },

    
    getById: function(id) {
        return (this.snapshot || this.data).findBy(function(record) {
            return record.getId() === id;
        });
    },

    
    indexOf: function(record) {
        return this.data.indexOf(record);
    },


    
    indexOfTotal: function(record) {
        var index = record.index;
        if (index || index === 0) {
            return index;
        }
        return this.indexOf(record);
    },

    
    indexOfId: function(id) {
        return this.indexOf(this.getById(id));
    },

    
    removeAll: function(silent) {
        var me = this;

        me.clearData();
        if (me.snapshot) {
            me.snapshot.clear();
        }

        
        
        if (me.pageMap) {
            me.pageMap.clear();
        }
        if (silent !== true) {
            me.fireEvent('clear', me);
        }
    },

    

    
    first: function(grouped) {
        var me = this;

        if (grouped && me.isGrouped()) {
            return me.aggregate(function(records) {
                return records.length ? records[0] : undefined;
            }, me, true);
        } else {
            return me.data.first();
        }
    },

    
    last: function(grouped) {
        var me = this;

        if (grouped && me.isGrouped()) {
            return me.aggregate(function(records) {
                var len = records.length;
                return len ? records[len - 1] : undefined;
            }, me, true);
        } else {
            return me.data.last();
        }
    },

    
    sum: function(field, grouped) {
        var me = this;

        if (grouped && me.isGrouped()) {
            return me.aggregate(me.getSum, me, true, [field]);
        } else {
            return me.getSum(me.data.items, field);
        }
    },

    
    getSum: function(records, field) {
        var total = 0,
            i = 0,
            len = records.length;

        for (; i < len; ++i) {
            total += records[i].get(field);
        }

        return total;
    },

    
    count: function(grouped) {
        var me = this;

        if (grouped && me.isGrouped()) {
            return me.aggregate(function(records) {
                return records.length;
            }, me, true);
        } else {
            return me.getCount();
        }
    },

    
    min: function(field, grouped) {
        var me = this;

        if (grouped && me.isGrouped()) {
            return me.aggregate(me.getMin, me, true, [field]);
        } else {
            return me.getMin(me.data.items, field);
        }
    },

    
    getMin: function(records, field) {
        var i = 1,
            len = records.length,
            value, min;

        if (len > 0) {
            min = records[0].get(field);
        }

        for (; i < len; ++i) {
            value = records[i].get(field);
            if (value < min) {
                min = value;
            }
        }
        return min;
    },

    
    max: function(field, grouped) {
        var me = this;

        if (grouped && me.isGrouped()) {
            return me.aggregate(me.getMax, me, true, [field]);
        } else {
            return me.getMax(me.data.items, field);
        }
    },

    
    getMax: function(records, field) {
        var i = 1,
            len = records.length,
            value,
            max;

        if (len > 0) {
            max = records[0].get(field);
        }

        for (; i < len; ++i) {
            value = records[i].get(field);
            if (value > max) {
                max = value;
            }
        }
        return max;
    },

    
    average: function(field, grouped) {
        var me = this;
        if (grouped && me.isGrouped()) {
            return me.aggregate(me.getAverage, me, true, [field]);
        } else {
            return me.getAverage(me.data.items, field);
        }
    },

    
    getAverage: function(records, field) {
        var i = 0,
            len = records.length,
            sum = 0;

        if (records.length > 0) {
            for (; i < len; ++i) {
                sum += records[i].get(field);
            }
            return sum / len;
        }
        return 0;
    },

    
    aggregate: function(fn, scope, grouped, args) {
        args = args || [];
        if (grouped && this.isGrouped()) {
            var groups = this.getGroups(),
                i = 0,
                len = groups.length,
                out = {},
                group;

            for (; i < len; ++i) {
                group = groups[i];
                out[group.name] = fn.apply(scope || this, [group.children].concat(args));
            }
            return out;
        } else {
            return fn.apply(scope || this, [this.data.items].concat(args));
        }
    },

    
    commitChanges : function(){
        var me = this,
            recs = me.getModifiedRecords(),
            len = recs.length,
            i = 0;

        for (; i < len; i++){
            recs[i].commit();
        }

        
        
        me.removed.length = 0;
    },

    filterNewOnly: function(item){
        return item.phantom === true;
    },

    
    
    
    getRejectRecords: function() {
        
        return Ext.Array.push(this.data.filterBy(this.filterNewOnly).items, this.getUpdatedRecords());
    },

    
    rejectChanges : function() {
        var me = this,
            recs = me.getRejectRecords(),
            len = recs.length,
            i = 0,
            rec;

        for (; i < len; i++) {
            rec = recs[i];
            rec.reject();
            if (rec.phantom) {
                me.remove(rec);
            }
        }

        
        recs = me.removed;
        len = recs.length;
        for (i = 0; i < len; i++) {
            rec = recs[i];
            me.insert(rec.removedFrom || 0, rec);
            rec.reject();
        }

        
        
        me.removed.length = 0;
    }
}, function() {
    
    
    
    Ext.regStore('ext-empty-store', {fields: [], proxy: 'memory'});

    
    this.prototype.PageMap = new Ext.Class({
        extend: 'Ext.util.LruCache',

        
        clear: function(initial) {
            this.generation = (this.generation ||0) + 1;
            this.callParent(arguments);
        },

        getPageFromRecordIndex: this.prototype.getPageFromRecordIndex,

        addPage: function(page, records) {
            this.add(page, records);
            this.fireEvent('pageAdded', page, records);
        },

        getPage: function(page) {
            return this.get(page);
        },

        hasRange: function(start, end) {
            var page = this.getPageFromRecordIndex(start),
                endPage = this.getPageFromRecordIndex(end);

            for (; page <= endPage; page++) {
                if (!this.hasPage(page)) {
                    return false;
                }
            }
            return true;
        },

        hasPage: function(page) {
            
            return !!this.get(page);
        },

        getRange: function(start, end) {
            if (!this.hasRange(start, end)) {
                Ext.Error.raise('PageMap asked for range which it does not have');
            }
            var me = this,
                startPage = me.getPageFromRecordIndex(start),
                endPage = me.getPageFromRecordIndex(end),
                dataStart = (startPage - 1) * me.pageSize,
                dataEnd = (endPage * me.pageSize) - 1,
                page = startPage,
                result = [],
                sliceBegin, sliceEnd, doSlice,
                i = 0, len;

            for (; page <= endPage; page++) {

                
                if (page == startPage) {
                    sliceBegin = start - dataStart;
                    doSlice = true;
                } else {
                    sliceBegin = 0;
                    doSlice = false;
                }
                if (page == endPage) {
                    sliceEnd = me.pageSize - (dataEnd - end);
                    doSlice = true;
                }

                
                if (doSlice) {
                    Ext.Array.push(result, Ext.Array.slice(me.getPage(page), sliceBegin, sliceEnd));
                } else {
                    Ext.Array.push(result, me.getPage(page));
                }
            }

            
            for (len = result.length; i < len; i++) {
                result[i].index = start++;
            }
            return result;
        }
    });
});


Ext.define('Ext.data.ArrayStore', {
    extend: 'Ext.data.Store',
    alias: 'store.array',
    requires: [
        'Ext.data.proxy.Memory',
        'Ext.data.reader.Array'
    ],

    constructor: function(config) {
        config = Ext.apply({
            proxy: {
                type: 'memory',
                reader: 'array'
            }
        }, config);
        this.callParent([config]);
    },

    loadData: function(data, append) {
        if (this.expandData === true) {
            var r = [],
                i = 0,
                ln = data.length;

            for (; i < ln; i++) {
                r[r.length] = [data[i]];
            }

            data = r;
        }

        this.callParent([data, append]);
    }
}, function() {
    
    Ext.data.SimpleStore = Ext.data.ArrayStore;
    
});

Ext.define('Ext.data.BufferStore', {
    extend: 'Ext.data.Store',
    alias: 'store.buffer',
    sortOnLoad: false,
    filterOnLoad: false,
    
    constructor: function() {
        Ext.Error.raise('The BufferStore class has been deprecated. Instead, specify the buffered config option on Ext.data.Store');
    }
});

Ext.define('Ext.data.JsonPStore', {
    extend: 'Ext.data.Store',
    alias : 'store.jsonp',
    requires: [
        'Ext.data.proxy.JsonP',
        'Ext.data.reader.Json'
    ],

    constructor: function(config) {
        config = Ext.apply({
            proxy: {
                type: 'jsonp',
                reader: 'json'
            }
        }, config);
        this.callParent([config]);
    }
});

Ext.define('Ext.data.JsonStore',  {
    extend: 'Ext.data.Store',
    alias: 'store.json',
    requires: [
        'Ext.data.proxy.Ajax',
        'Ext.data.reader.Json',
        'Ext.data.writer.Json'
    ],

    constructor: function(config) {
        config = Ext.apply({
            proxy: {
                type  : 'ajax',
                reader: 'json',
                writer: 'json'
            }
        }, config);
        this.callParent([config]);
    }
});

Ext.define('Ext.data.NodeStore', {
    extend: 'Ext.data.Store',
    alias: 'store.node',
    requires: ['Ext.data.NodeInterface'],

    
    node: null,

    
    recursive: false,
    
        
    rootVisible: false,

    

    constructor: function(config) {
        var me = this,
            node;

        config = config || {};
        Ext.apply(me, config);


        config.proxy = {type: 'proxy'};
        me.callParent([config]);

        node = me.node;
        if (node) {
            me.node = null;
            me.setNode(node);
        }
    },

    setNode: function(node) {
        var me = this;
        if (me.node && me.node != node) {
            
            me.mun(me.node, {
                expand: me.onNodeExpand,
                collapse: me.onNodeCollapse,
                append: me.onNodeAppend,
                insert: me.onNodeInsert,
                remove: me.onNodeRemove,
                sort: me.onNodeSort,
                scope: me
            });
            me.node = null;
        }

        if (node) {
            Ext.data.NodeInterface.decorate(node.self);
            me.removeAll();
            if (me.rootVisible) {
                me.add(node);
            } else if (!node.isExpanded() && me.treeStore.autoLoad !== false) {
                node.expand();
            }

            me.mon(node, {
                expand: me.onNodeExpand,
                collapse: me.onNodeCollapse,
                append: me.onNodeAppend,
                insert: me.onNodeInsert,
                remove: me.onNodeRemove,
                sort: me.onNodeSort,
                scope: me
            });
            me.node = node;
            if (node.isExpanded() && node.isLoaded()) {
                me.onNodeExpand(node, node.childNodes, true);
            }
        }
    },

    onNodeSort: function(node, childNodes) {
        var me = this;

        if ((me.indexOf(node) !== -1 || (node === me.node && !me.rootVisible) && node.isExpanded())) {
            me.onNodeCollapse(node, childNodes, true);
            me.onNodeExpand(node, childNodes, true);
        }
    },

    onNodeExpand: function(parent, records, suppressEvent) {
        var me = this,
            insertIndex = me.indexOf(parent) + 1,
            ln = records ? records.length : 0,
            i, record;

        if (!me.recursive && parent !== me.node) {
            return;
        }

        if (parent !== this.node && !me.isVisible(parent)) {
            return;
        }

        if (!suppressEvent && me.fireEvent('beforeexpand', parent, records, insertIndex) === false) {
            return;
        }

        if (ln) {
            me.insert(insertIndex, records);
            for (i = 0; i < ln; i++) {
                record = records[i];
                if (record.isExpanded()) {
                    if (record.isLoaded()) {
                        
                        me.onNodeExpand(record, record.childNodes, true);
                    }
                    else {
                        record.set('expanded', false);
                        record.expand();
                    }
                }
            }
        }

        if (!suppressEvent) {
            me.fireEvent('expand', parent, records);
        }
    },

    onNodeCollapse: function(parent, records, suppressEvent) {
        var me = this,
            ln = records.length,
            collapseIndex = me.indexOf(parent) + 1,
            i, record;

        if (!me.recursive && parent !== me.node) {
            return;
        }

        if (!suppressEvent && me.fireEvent('beforecollapse', parent, records, collapseIndex) === false) {
            return;
        }

        for (i = 0; i < ln; i++) {
            record = records[i];
            me.remove(record);
            if (record.isExpanded()) {
                me.onNodeCollapse(record, record.childNodes, true);
            }
        }

        if (!suppressEvent) {
            me.fireEvent('collapse', parent, records, collapseIndex);
        }
    },

    onNodeAppend: function(parent, node, index) {
        var me = this,
            refNode, sibling;

        if (me.isVisible(node)) {
            if (index === 0) {
                refNode = parent;
            } else {
                sibling = node.previousSibling;
                while (sibling.isExpanded() && sibling.lastChild) {
                    sibling = sibling.lastChild;
                }
                refNode = sibling;
            }
            me.insert(me.indexOf(refNode) + 1, node);
            if (!node.isLeaf() && node.isExpanded()) {
                if (node.isLoaded()) {
                    
                    me.onNodeExpand(node, node.childNodes, true);
                }
                else {
                    node.set('expanded', false);
                    node.expand();
                }
            }
        }
    },

    onNodeInsert: function(parent, node, refNode) {
        var me = this,
            index = this.indexOf(refNode);

        if (index != -1 && me.isVisible(node)) {
            me.insert(index, node);
            if (!node.isLeaf() && node.isExpanded()) {
                if (node.isLoaded()) {
                    
                    me.onNodeExpand(node, node.childNodes, true);
                }
                else {
                    node.set('expanded', false);
                    node.expand();
                }
            }
        }
    },

    onNodeRemove: function(parent, node, index) {
        var me = this;
        if (me.indexOf(node) != -1) {
            if (!node.isLeaf() && node.isExpanded()) {
                me.onNodeCollapse(node, node.childNodes, true);
            }
            me.remove(node);
        }
    },

    isVisible: function(node) {
        var parent = node.parentNode;
        while (parent) {
            if (parent === this.node && !this.rootVisible && parent.isExpanded()) {
                return true;
            }

            if (this.indexOf(parent) === -1 || !parent.isExpanded()) {
                return false;
            }

            parent = parent.parentNode;
        }
        return true;
    }
});

Ext.define('Ext.data.XmlStore', {
    extend: 'Ext.data.Store',
    alias: 'store.xml',

    requires: [
        'Ext.data.proxy.Ajax',
        'Ext.data.reader.Xml',
        'Ext.data.writer.Xml'
    ],
    
    constructor: function(config){
        config = Ext.apply({
            proxy: {
                type: 'ajax',
                reader: 'xml',
                writer: 'xml'
            }
        }, config);

        this.callParent([config]);
    }
});

Ext.define('Ext.data.proxy.Rest', {
    extend: 'Ext.data.proxy.Ajax',
    alternateClassName: 'Ext.data.RestProxy',
    alias : 'proxy.rest',
    
    
    appendId: true,
    
    
    
    
    batchActions: false,
    
    
    buildUrl: function(request) {
        var me        = this,
            operation = request.operation,
            records   = operation.records || [],
            record    = records[0],
            format    = me.format,
            url       = me.getUrl(request),
            id        = record ? record.getId() : operation.id;
        
        if (me.appendId && id) {
            if (!url.match(/\/$/)) {
                url += '/';
            }
            
            url += id;
        }
        
        if (format) {
            if (!url.match(/\.$/)) {
                url += '.';
            }
            
            url += format;
        }
        
        request.url = url;
        
        return me.callParent(arguments);
    }
}, function() {
    Ext.apply(this.prototype, {
        
        actionMethods: {
            create : 'POST',
            read   : 'GET',
            update : 'PUT',
            destroy: 'DELETE'
        }
    });
});


Ext.define('Ext.direct.Manager', {

    
    singleton: true,

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: ['Ext.util.MixedCollection'],

    
    exceptions: {
        TRANSPORT: 'xhr',
        PARSE: 'parse',
        LOGIN: 'login',
        SERVER: 'exception'
    },

    

    constructor: function(){
        var me = this;

        me.addEvents(
            
            'event',
            
            'exception'
        );
        me.transactions = new Ext.util.MixedCollection();
        me.providers = new Ext.util.MixedCollection();

        me.mixins.observable.constructor.call(me);
    },

    
    addProvider : function(provider){
        var me = this,
            args = arguments,
            i = 0,
            len;

        if (args.length > 1) {
            for (len = args.length; i < len; ++i) {
                me.addProvider(args[i]);
            }
            return;
        }

        
        if (!provider.isProvider) {
            provider = Ext.create('direct.' + provider.type + 'provider', provider);
        }
        me.providers.add(provider);
        provider.on('data', me.onProviderData, me);


        if (!provider.isConnected()) {
            provider.connect();
        }

        return provider;
    },

    
    getProvider : function(id){
        return id.isProvider ? id : this.providers.get(id);
    },

    
    removeProvider : function(provider){
        var me = this,
            providers = me.providers;

        provider = provider.isProvider ? provider : providers.get(provider);

        if (provider) {
            provider.un('data', me.onProviderData, me);
            providers.remove(provider);
            return provider;
        }
        return null;
    },

    
    addTransaction: function(transaction){
        this.transactions.add(transaction);
        return transaction;
    },

    
    removeTransaction: function(transaction){
        transaction = this.getTransaction(transaction);
        this.transactions.remove(transaction);
        return transaction;
    },

    
    getTransaction: function(transaction){
        return Ext.isObject(transaction) ? transaction : this.transactions.get(transaction);
    },

    onProviderData : function(provider, event){
        var me = this,
            i = 0,
            len;

        if (Ext.isArray(event)) {
            for (len = event.length; i < len; ++i) {
                me.onProviderData(provider, event[i]);
            }
            return;
        }
        if (event.name && event.name != 'event' && event.name != 'exception') {
            me.fireEvent(event.name, event);
        } else if (event.status === false) {
            me.fireEvent('exception', event);
        }
        me.fireEvent('event', event, provider);
    },
    
    
    parseMethod: function(fn){
        if (Ext.isString(fn)) {
            var parts = fn.split('.'),
                i = 0,
                len = parts.length,
                current = window;
                
            while (current && i < len) {
                current = current[parts[i]];
                ++i;
            }
            fn = Ext.isFunction(current) ? current : null;
        }
        return fn || null;
    }
    
}, function(){
    
    Ext.Direct = Ext.direct.Manager;
});


Ext.define('Ext.data.proxy.Direct', {
    

    extend: 'Ext.data.proxy.Server',
    alternateClassName: 'Ext.data.DirectProxy',

    alias: 'proxy.direct',

    requires: ['Ext.direct.Manager'],

    

    
    paramOrder: undefined,

    
    paramsAsHash: true,

    
    directFn : undefined,

    

    

    
    paramOrderRe: /[\s,|]/,

    constructor: function(config){
        var me = this,
            paramOrder,
            fn,
            api;
            
        me.callParent(arguments);
        
        paramOrder = me.paramOrder;
        if (Ext.isString(paramOrder)) {
            me.paramOrder = paramOrder.split(me.paramOrderRe);
        }
        
        fn = me.directFn;
        if (fn) {
            me.directFn = Ext.direct.Manager.parseMethod(fn);
        }
        
        api = me.api;
        for (fn in api) {
            if (api.hasOwnProperty(fn)) {
                api[fn] = Ext.direct.Manager.parseMethod(api[fn]);
            }
        }
    },

    doRequest: function(operation, callback, scope) {
        var me = this,
            writer = me.getWriter(),
            request = me.buildRequest(operation, callback, scope),
            fn = me.api[request.action]  || me.directFn,
            params = request.params,
            args = [],
            method;


        if (operation.allowWrite()) {
            request = writer.write(request);
        }

        if (operation.action == 'read') {
            
            method = fn.directCfg.method;
            args = method.getArgs(params, me.paramOrder, me.paramsAsHash);
        } else {
            args.push(request.jsonData);
        }

        Ext.apply(request, {
            args: args,
            directFn: fn
        });
        args.push(me.createRequestCallback(request, operation, callback, scope), me);
        fn.apply(window, args);
    },

    
    applyEncoding: function(value){
        return value;
    },

    createRequestCallback: function(request, operation, callback, scope){
        var me = this;

        return function(data, event){
            me.processResponse(event.status, operation, request, event, callback, scope);
        };
    },

    
    extractResponseData: function(response){
        return Ext.isDefined(response.result) ? response.result : response.data;
    },

    
    setException: function(operation, response) {
        operation.setException(response.message);
    },

    
    buildUrl: function(){
        return '';
    }
});


Ext.define('Ext.data.DirectStore', {
    
    
    extend: 'Ext.data.Store',
    
    alias: 'store.direct',
    
    requires: ['Ext.data.proxy.Direct'],
   
    

    constructor : function(config){
        config = Ext.apply({}, config);
        if (!config.proxy) {
            var proxy = {
                type: 'direct',
                reader: {
                    type: 'json'
                }
            };
            Ext.copyTo(proxy, config, 'paramOrder,paramsAsHash,directFn,api,simpleSortMode');
            Ext.copyTo(proxy.reader, config, 'totalProperty,root,idProperty');
            config.proxy = proxy;
        }
        this.callParent([config]);
    }    
});


Ext.define('Ext.direct.Event', {

    

    alias: 'direct.event',

    requires: ['Ext.direct.Manager'],

    

    status: true,

    
    constructor: function(config) {
        Ext.apply(this, config);
    },

    
    getData: function(){
        return this.data;
    }
});


Ext.define('Ext.direct.RemotingEvent', {
    
    
   
    extend: 'Ext.direct.Event',
    
    alias: 'direct.rpc',
    
    
    
    
    getTransaction: function(){
        return this.transaction || Ext.direct.Manager.getTransaction(this.tid);
    }
});


Ext.define('Ext.direct.ExceptionEvent', {
    
    
   
    extend: 'Ext.direct.RemotingEvent',
    
    alias: 'direct.exception',
    
    
   
   status: false
});


Ext.define('Ext.direct.RemotingProvider', {
    
    
   
    alias: 'direct.remotingprovider',
    
    extend: 'Ext.direct.JsonProvider', 
    
    requires: [
        'Ext.util.MixedCollection', 
        'Ext.util.DelayedTask', 
        'Ext.direct.Transaction',
        'Ext.direct.RemotingMethod'
    ],
   
    
   
   
    
    
    
    
    
    
    
    
    enableBuffer: 10,
    
    
    maxRetries: 1,
    
    
    timeout: undefined,
    
    constructor : function(config){
        var me = this;
        me.callParent(arguments);
        me.addEvents(
                        
            'beforecall',            
                        
            'call'
        );
        me.namespace = (Ext.isString(me.namespace)) ? Ext.ns(me.namespace) : me.namespace || window;
        me.transactions = new Ext.util.MixedCollection();
        me.callBuffer = [];
    },
    
    
    initAPI : function(){
        var actions = this.actions,
            namespace = this.namespace,
            action,
            cls,
            methods,
            i,
            len,
            method;
            
        for (action in actions) {
            if (actions.hasOwnProperty(action)) {
                cls = namespace[action];
                if (!cls) {
                    cls = namespace[action] = {};
                }
                methods = actions[action];
                
                for (i = 0, len = methods.length; i < len; ++i) {
                    method = new Ext.direct.RemotingMethod(methods[i]);
                    cls[method.name] = this.createHandler(action, method);
                }
            }
        }
    },
    
    
    createHandler : function(action, method){
        var me = this,
            handler;
        
        if (!method.formHandler) {
            handler = function(){
                me.configureRequest(action, method, Array.prototype.slice.call(arguments, 0));
            };
        } else {
            handler = function(form, callback, scope){
                me.configureFormRequest(action, method, form, callback, scope);
            };
        }
        handler.directCfg = {
            action: action,
            method: method
        };
        return handler;
    },
    
    
    isConnected: function(){
        return !!this.connected;
    },

    
    connect: function(){
        var me = this;
        
        if (me.url) {
            me.initAPI();
            me.connected = true;
            me.fireEvent('connect', me);
        } else if(!me.url) {
        }
    },

    
    disconnect: function(){
        var me = this;
        
        if (me.connected) {
            me.connected = false;
            me.fireEvent('disconnect', me);
        }
    },
    
    
    runCallback: function(transaction, event){
        var success = !!event.status,
            funcName = success ? 'success' : 'failure',
            callback,
            result;
        
        if (transaction && transaction.callback) {
            callback = transaction.callback;
            result = Ext.isDefined(event.result) ? event.result : event.data;
        
            if (Ext.isFunction(callback)) {
                callback(result, event, success);
            } else {
                Ext.callback(callback[funcName], callback.scope, [result, event, success]);
                Ext.callback(callback.callback, callback.scope, [result, event, success]);
            }
        }
    },
    
    
    onData: function(options, success, response){
        var me = this,
            i = 0,
            len,
            events,
            event,
            transaction,
            transactions;
            
        if (success) {
            events = me.createEvents(response);
            for (len = events.length; i < len; ++i) {
                event = events[i];
                transaction = me.getTransaction(event);
                me.fireEvent('data', me, event);
                if (transaction) {
                    me.runCallback(transaction, event, true);
                    Ext.direct.Manager.removeTransaction(transaction);
                }
            }
        } else {
            transactions = [].concat(options.transaction);
            for (len = transactions.length; i < len; ++i) {
                transaction = me.getTransaction(transactions[i]);
                if (transaction && transaction.retryCount < me.maxRetries) {
                    transaction.retry();
                } else {
                    event = new Ext.direct.ExceptionEvent({
                        data: null,
                        transaction: transaction,
                        code: Ext.direct.Manager.exceptions.TRANSPORT,
                        message: 'Unable to connect to the server.',
                        xhr: response
                    });
                    me.fireEvent('data', me, event);
                    if (transaction) {
                        me.runCallback(transaction, event, false);
                        Ext.direct.Manager.removeTransaction(transaction);
                    }
                }
            }
        }
    },
    
    
    getTransaction: function(options){
        return options && options.tid ? Ext.direct.Manager.getTransaction(options.tid) : null;
    },
    
    
    configureRequest: function(action, method, args){
        var me = this,
            callData = method.getCallData(args),
            data = callData.data, 
            callback = callData.callback, 
            scope = callData.scope,
            transaction;

        transaction = new Ext.direct.Transaction({
            provider: me,
            args: args,
            action: action,
            method: method.name,
            data: data,
            callback: scope && Ext.isFunction(callback) ? Ext.Function.bind(callback, scope) : callback
        });

        if (me.fireEvent('beforecall', me, transaction, method) !== false) {
            Ext.direct.Manager.addTransaction(transaction);
            me.queueTransaction(transaction);
            me.fireEvent('call', me, transaction, method);
        }
    },
    
    
    getCallData: function(transaction){
        return {
            action: transaction.action,
            method: transaction.method,
            data: transaction.data,
            type: 'rpc',
            tid: transaction.id
        };
    },
    
    
    sendRequest : function(data){
        var me = this,
            request = {
                url: me.url,
                callback: me.onData,
                scope: me,
                transaction: data,
                timeout: me.timeout
            }, callData,
            enableUrlEncode = me.enableUrlEncode,
            i = 0,
            len,
            params;
            

        if (Ext.isArray(data)) {
            callData = [];
            for (len = data.length; i < len; ++i) {
                callData.push(me.getCallData(data[i]));
            }
        } else {
            callData = me.getCallData(data);
        }

        if (enableUrlEncode) {
            params = {};
            params[Ext.isString(enableUrlEncode) ? enableUrlEncode : 'data'] = Ext.encode(callData);
            request.params = params;
        } else {
            request.jsonData = callData;
        }
        Ext.Ajax.request(request);
    },
    
    
    queueTransaction: function(transaction){
        var me = this,
            enableBuffer = me.enableBuffer;
        
        if (transaction.form) {
            me.sendFormRequest(transaction);
            return;
        }
        
        me.callBuffer.push(transaction);
        if (enableBuffer) {
            if (!me.callTask) {
                me.callTask = new Ext.util.DelayedTask(me.combineAndSend, me);
            }
            me.callTask.delay(Ext.isNumber(enableBuffer) ? enableBuffer : 10);
        } else {
            me.combineAndSend();
        }
    },
    
    
    combineAndSend : function(){
        var buffer = this.callBuffer,
            len = buffer.length;
            
        if (len > 0) {
            this.sendRequest(len == 1 ? buffer[0] : buffer);
            this.callBuffer = [];
        }
    },
    
    
    configureFormRequest : function(action, method, form, callback, scope){
        var me = this,
            transaction = new Ext.direct.Transaction({
                provider: me,
                action: action,
                method: method.name,
                args: [form, callback, scope],
                callback: scope && Ext.isFunction(callback) ? Ext.Function.bind(callback, scope) : callback,
                isForm: true
            }),
            isUpload,
            params;

        if (me.fireEvent('beforecall', me, transaction, method) !== false) {
            Ext.direct.Manager.addTransaction(transaction);
            isUpload = String(form.getAttribute("enctype")).toLowerCase() == 'multipart/form-data';
            
            params = {
                extTID: transaction.id,
                extAction: action,
                extMethod: method.name,
                extType: 'rpc',
                extUpload: String(isUpload)
            };
            
            
            
            Ext.apply(transaction, {
                form: Ext.getDom(form),
                isUpload: isUpload,
                params: callback && Ext.isObject(callback.params) ? Ext.apply(params, callback.params) : params
            });
            me.fireEvent('call', me, transaction, method);
            me.sendFormRequest(transaction);
        }
    },
    
    
    sendFormRequest: function(transaction){
        Ext.Ajax.request({
            url: this.url,
            params: transaction.params,
            callback: this.onData,
            scope: this,
            form: transaction.form,
            isUpload: transaction.isUpload,
            transaction: transaction
        });
    }
    
});


Ext.define('Ext.draw.CompositeSprite', {

    

    extend: 'Ext.util.MixedCollection',
    mixins: {
        animate: 'Ext.util.Animate'
    },
    autoDestroy: false,
    
    
    isCompositeSprite: true,
    constructor: function(config) {
        var me = this;
        
        config = config || {};
        Ext.apply(me, config);

        me.addEvents(
            
            'mousedown',
            
            'mouseup',
            
            'mouseover',
            
            'mouseout',
            
            'click'
        );
        me.id = Ext.id(null, 'ext-sprite-group-');
        me.callParent();
    },

    
    onClick: function(e) {
        this.fireEvent('click', e);
    },

    
    onMouseUp: function(e) {
        this.fireEvent('mouseup', e);
    },

    
    onMouseDown: function(e) {
        this.fireEvent('mousedown', e);
    },

    
    onMouseOver: function(e) {
        this.fireEvent('mouseover', e);
    },

    
    onMouseOut: function(e) {
        this.fireEvent('mouseout', e);
    },

    attachEvents: function(o) {
        var me = this;
        
        o.on({
            scope: me,
            mousedown: me.onMouseDown,
            mouseup: me.onMouseUp,
            mouseover: me.onMouseOver,
            mouseout: me.onMouseOut,
            click: me.onClick
        });
    },

    
    add: function(key, o) {
        var result = this.callParent(arguments);
        this.attachEvents(result);
        return result;
    },

    insert: function(index, key, o) {
        return this.callParent(arguments);
    },

    
    remove: function(o) {
        var me = this;
        
        o.un({
            scope: me,
            mousedown: me.onMouseDown,
            mouseup: me.onMouseUp,
            mouseover: me.onMouseOver,
            mouseout: me.onMouseOut,
            click: me.onClick
        });
        return me.callParent(arguments);
    },
    
    
    getBBox: function() {
        var i = 0,
            sprite,
            bb,
            items = this.items,
            len = this.length,
            infinity = Infinity,
            minX = infinity,
            maxHeight = -infinity,
            minY = infinity,
            maxWidth = -infinity,
            maxWidthBBox, maxHeightBBox;
        
        for (; i < len; i++) {
            sprite = items[i];
            if (sprite.el && ! sprite.bboxExcluded) {
                bb = sprite.getBBox();
                minX = Math.min(minX, bb.x);
                minY = Math.min(minY, bb.y);
                maxHeight = Math.max(maxHeight, bb.height + bb.y);
                maxWidth = Math.max(maxWidth, bb.width + bb.x);
            }
        }
        
        return {
            x: minX,
            y: minY,
            height: maxHeight - minY,
            width: maxWidth - minX
        };
    },

    
    setAttributes: function(attrs, redraw) {
        var i = 0,
            items = this.items,
            len = this.length;
            
        for (; i < len; i++) {
            items[i].setAttributes(attrs, redraw);
        }
        return this;
    },

    
    hide: function(redraw) {
        var i = 0,
            items = this.items,
            len = this.length;
            
        for (; i < len; i++) {
            items[i].hide(redraw);
        }
        return this;
    },

    
    show: function(redraw) {
        var i = 0,
            items = this.items,
            len = this.length;
            
        for (; i < len; i++) {
            items[i].show(redraw);
        }
        return this;
    },

    
    redraw: function() {
        var me = this,
            i = 0,
            items = me.items,
            surface = me.getSurface(),
            len = me.length;
        
        if (surface) {
            for (; i < len; i++) {
                surface.renderItem(items[i]);
            }
        }
        return me;
    },

    
    setStyle: function(obj) {
        var i = 0,
            items = this.items,
            len = this.length,
            item, el;
            
        for (; i < len; i++) {
            item = items[i];
            el = item.el;
            if (el) {
                el.setStyle(obj);
            }
        }
    },

    
    addCls: function(obj) {
        var i = 0,
            items = this.items,
            surface = this.getSurface(),
            len = this.length;
        
        if (surface) {
            for (; i < len; i++) {
                surface.addCls(items[i], obj);
            }
        }
    },

    
    removeCls: function(obj) {
        var i = 0,
            items = this.items,
            surface = this.getSurface(),
            len = this.length;
        
        if (surface) {
            for (; i < len; i++) {
                surface.removeCls(items[i], obj);
            }
        }
    },
    
    
    getSurface: function(){
        var first = this.first();
        if (first) {
            return first.surface;
        }
        return null;
    },
    
    
    destroy: function(){
        var me = this,
            surface = me.getSurface(),
            destroySprites = me.autoDestroy,
            item;
            
        if (surface) {
            while (me.getCount() > 0) {
                item = me.first();
                me.remove(item);
                surface.remove(item, destroySprites);
            }
        }
        me.clearListeners();
    }
});


Ext.define('Ext.chart.LegendItem', {

    

    extend: 'Ext.draw.CompositeSprite',

    requires: ['Ext.chart.Shape'],

    

    
    x: 0,
    y: 0,
    zIndex: 500,

    
    boldRe: /bold\s\d{1,}.*/i,

    constructor: function(config) {
        this.callParent(arguments);
        this.createLegend(config);
    },

    
    createLegend: function(config) {
        var me = this,
            index = config.yFieldIndex,
            series = me.series,
            seriesType = series.type,
            idx = me.yFieldIndex,
            legend = me.legend,
            surface = me.surface,
            refX = legend.x + me.x,
            refY = legend.y + me.y,
            bbox, z = me.zIndex,
            markerConfig, label, mask,
            radius, toggle = false,
            seriesStyle = Ext.apply(series.seriesStyle, series.style);

        function getSeriesProp(name) {
            var val = series[name];
            return (Ext.isArray(val) ? val[idx] : val);
        }
        
        label = me.add('label', surface.add({
            type: 'text',
            x: 20,
            y: 0,
            zIndex: (z || 0) + 2,
            fill: legend.labelColor,
            font: legend.labelFont,
            text: getSeriesProp('title') || getSeriesProp('yField'),
            style: {
                'cursor': 'pointer'
            }
        }));

        
        if (seriesType === 'line' || seriesType === 'scatter') {
            if(seriesType === 'line') {
                me.add('line', surface.add({
                    type: 'path',
                    path: 'M0.5,0.5L16.5,0.5',
                    zIndex: (z || 0) + 2,
                    "stroke-width": series.lineWidth,
                    "stroke-linejoin": "round",
                    "stroke-dasharray": series.dash,
                    stroke: seriesStyle.stroke || series.getLegendColor(index) || '#000',
                    style: {
                        cursor: 'pointer'
                    }
                }));
            }
            if (series.showMarkers || seriesType === 'scatter') {
                markerConfig = Ext.apply(series.markerStyle, series.markerConfig || {}, {
                    fill: series.getLegendColor(index)
                });
                me.add('marker', Ext.chart.Shape[markerConfig.type](surface, {
                    fill: markerConfig.fill,
                    x: 8.5,
                    y: 0.5,
                    zIndex: (z || 0) + 2,
                    radius: markerConfig.radius || markerConfig.size,
                    style: {
                        cursor: 'pointer'
                    }
                }));
            }
        }
        
        else {
            me.add('box', surface.add({
                type: 'rect',
                zIndex: (z || 0) + 2,
                x: 0,
                y: 0,
                width: 12,
                height: 12,
                fill: series.getLegendColor(index),
                style: {
                    cursor: 'pointer'
                }
            }));
        }
        
        me.setAttributes({
            hidden: false
        }, true);
        
        bbox = me.getBBox();
        
        mask = me.add('mask', surface.add({
            type: 'rect',
            x: bbox.x,
            y: bbox.y,
            width: bbox.width || 20,
            height: bbox.height || 20,
            zIndex: (z || 0) + 1,
            fill: me.legend.boxFill,
            style: {
                'cursor': 'pointer'
            }
        }));

        
        me.on('mouseover', function() {
            label.setStyle({
                'font-weight': 'bold'
            });
            mask.setStyle({
                'cursor': 'pointer'
            });
            series._index = index;
            series.highlightItem();
        }, me);

        me.on('mouseout', function() {
            label.setStyle({
                'font-weight': legend.labelFont && me.boldRe.test(legend.labelFont) ? 'bold' : 'normal'
            });
            series._index = index;
            series.unHighlightItem();
        }, me);
        
        if (!series.visibleInLegend(index)) {
            toggle = true;
            label.setAttributes({
               opacity: 0.5
            }, true);
        }

        me.on('mousedown', function() {
            if (!toggle) {
                series.hideAll(index);
                label.setAttributes({
                    opacity: 0.5
                }, true);
            } else {
                series.showAll(index);
                label.setAttributes({
                    opacity: 1
                }, true);
            }
            toggle = !toggle;
            me.legend.chart.redraw();
        }, me);
        me.updatePosition({x:0, y:0}); 
    },

    
    updatePosition: function(relativeTo) {
        var me = this,
            items = me.items,
            ln = items.length,
            i = 0,
            item;
        if (!relativeTo) {
            relativeTo = me.legend;
        }
        for (; i < ln; i++) {
            item = items[i];
            switch (item.type) {
                case 'text':
                    item.setAttributes({
                        x: 20 + relativeTo.x + me.x,
                        y: relativeTo.y + me.y
                    }, true);
                    break;
                case 'rect':
                    item.setAttributes({
                        translate: {
                            x: relativeTo.x + me.x,
                            y: relativeTo.y + me.y - 6
                        }
                    }, true);
                    break;
                default:
                    item.setAttributes({
                        translate: {
                            x: relativeTo.x + me.x,
                            y: relativeTo.y + me.y
                        }
                    }, true);
            }
        }
    }
});


Ext.define('Ext.chart.Legend', {

    

    requires: ['Ext.chart.LegendItem'],

    

    
    visible: true,
    
    
    update: true,

    
    position: 'bottom',

    
    x: 0,

    
    y: 0,

    
    labelColor: '#000',

    
    labelFont: '12px Helvetica, sans-serif',

    
    boxStroke: '#000',

    
    boxStrokeWidth: 1,

    
    boxFill: '#FFF',

    
    itemSpacing: 10,

    
    padding: 5,

    
    width: 0,
    
    height: 0,

    
    boxZIndex: 100,

    
    constructor: function(config) {
        var me = this;
        if (config) {
            Ext.apply(me, config);
        }
        me.items = [];
        
        me.isVertical = ("left|right|float".indexOf(me.position) !== -1);

        
        me.origX = me.x;
        me.origY = me.y;
    },

    
    create: function() {
        var me = this,
            seriesItems = me.chart.series.items,
            i, ln, series;

        me.createBox();
        
        if (me.rebuild !== false) {
            me.createItems();
        }
        
        if (!me.created && me.isDisplayed()) {
            me.created = true;

            
            for (i = 0, ln = seriesItems.length; i < ln; i++) {
                series = seriesItems[i];
                series.on('titlechange', function() {
                    me.create();
                    me.updatePosition();
                });
            }
        }
    },

    
    isDisplayed: function() {
        return this.visible && this.chart.series.findIndex('showInLegend', true) !== -1;
    },

    
    createItems: function() {
        var me = this,
            chart = me.chart,
            seriesItems = chart.series.items,
            ln, series,
            surface = chart.surface,
            items = me.items,
            padding = me.padding,
            itemSpacing = me.itemSpacing,
            spacingOffset = 2,
            maxWidth = 0,
            maxHeight = 0,
            totalWidth = 0,
            totalHeight = 0,
            vertical = me.isVertical,
            math = Math,
            mfloor = math.floor,
            mmax = math.max,
            index = 0,
            i = 0,
            len = items ? items.length : 0,
            x, y, spacing, item, bbox, height, width,
            fields, field, nFields, j;

        
        if (len) {
            for (; i < len; i++) {
                items[i].destroy();
            }
        }
        
        items.length = [];
        
        
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            if (series.showInLegend) {
                fields = [].concat(series.yField);
                for (j = 0, nFields = fields.length; j < nFields; j++) {
                    field = fields[j];
                    item = new Ext.chart.LegendItem({
                        legend: this,
                        series: series,
                        surface: chart.surface,
                        yFieldIndex: j
                    });
                    bbox = item.getBBox();

                    
                    width = bbox.width;
                    height = bbox.height;

                    if (i + j === 0) {
                        spacing = vertical ? padding + height / 2 : padding;
                    }
                    else {
                        spacing = itemSpacing / (vertical ? 2 : 1);
                    }
                    
                    item.x = mfloor(vertical ? padding : totalWidth + spacing);
                    item.y = mfloor(vertical ? totalHeight + spacing : padding + height / 2);

                    
                    totalWidth += width + spacing;
                    totalHeight += height + spacing;
                    maxWidth = mmax(maxWidth, width);
                    maxHeight = mmax(maxHeight, height);

                    items.push(item);
                }
            }
        }

        
        me.width = mfloor((vertical ? maxWidth : totalWidth) + padding * 2);
        if (vertical && items.length === 1) {
            spacingOffset = 1;
        }
        me.height = mfloor((vertical ? totalHeight - spacingOffset * spacing : maxHeight) + (padding * 2));
        me.itemHeight = maxHeight;
    },

    
    getBBox: function() {
        var me = this;
        return {
            x: Math.round(me.x) - me.boxStrokeWidth / 2,
            y: Math.round(me.y) - me.boxStrokeWidth / 2,
            width: me.width,
            height: me.height
        };
    },

    
    createBox: function() {
        var me = this,
            box, bbox;

        if (me.boxSprite) {
            me.boxSprite.destroy();
        }

        bbox = me.getBBox();
        
        
        
        
        
        if (isNaN(bbox.width) || isNaN(bbox.height)) {
            me.boxSprite = false;
            return;
        }
        
        box = me.boxSprite = me.chart.surface.add(Ext.apply({
            type: 'rect',
            stroke: me.boxStroke,
            "stroke-width": me.boxStrokeWidth,
            fill: me.boxFill,
            zIndex: me.boxZIndex
        }, bbox));

        box.redraw();
    },

    
    updatePosition: function() {
        var me = this,
            items = me.items,
            i, ln,
            x, y,
            legendWidth = me.width || 0,
            legendHeight = me.height || 0,
            padding = me.padding,
            chart = me.chart,
            chartBBox = chart.chartBBox,
            insets = chart.insetPadding,
            chartWidth = chartBBox.width - (insets * 2),
            chartHeight = chartBBox.height - (insets * 2),
            chartX = chartBBox.x + insets,
            chartY = chartBBox.y + insets,
            surface = chart.surface,
            mfloor = Math.floor,
            bbox;

        if (me.isDisplayed()) {
            
            switch(me.position) {
                case "left":
                    x = insets;
                    y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
                    break;
                case "right":
                    x = mfloor(surface.width - legendWidth) - insets;
                    y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
                    break;
                case "top":
                    x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
                    y = insets;
                    break;
                case "bottom":
                    x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
                    y = mfloor(surface.height - legendHeight) - insets;
                    break;
                default:
                    x = mfloor(me.origX) + insets;
                    y = mfloor(me.origY) + insets;
            }
            me.x = x;
            me.y = y;

            
            for (i = 0, ln = items.length; i < ln; i++) {
                items[i].updatePosition();
            }

            bbox = me.getBBox();

            
            
            
            
            
            if (isNaN(bbox.width) || isNaN(bbox.height)) {
                if (me.boxSprite) {
                    me.boxSprite.hide(true);
                }
            } else {
                if (!me.boxSprite) {
                    me.createBox();
                }
                
                me.boxSprite.setAttributes(bbox, true);
                me.boxSprite.show(true);
            }
        }
    },
    
    
    toggle: function(show) {
      var me = this,
          i = 0,
          items = me.items,
          len = items.length;

      if (me.boxSprite) {
          if (show) {
              me.boxSprite.show(true);
          } else {
              me.boxSprite.hide(true);
          }
      }

      for (; i < len; ++i) {
          if (show) {
            items[i].show(true);
          } else {
              items[i].hide(true);
          }
      }

      me.visible = show;
    }
});


Ext.define('Ext.draw.Surface', {

    

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: ['Ext.draw.CompositeSprite'],
    uses: ['Ext.draw.engine.Svg', 'Ext.draw.engine.Vml', 'Ext.draw.engine.SvgExporter', 'Ext.draw.engine.ImageExporter'],

    separatorRe: /[, ]+/,

    statics: {
        
        create: function(config, enginePriority) {
            enginePriority = enginePriority || ['Svg', 'Vml'];

            var i = 0,
                len = enginePriority.length,
                surfaceClass;

            for (; i < len; i++) {
                if (Ext.supports[enginePriority[i]] !== false) {
                    return Ext.create('Ext.draw.engine.' + enginePriority[i], config);
                }
            }
            return false;
        },
        
        
        save: function(surface, config) {
            config = config || {};
            var exportTypes = {
                    'image/png': 'Image',
                    'image/jpeg': 'Image',
                    'image/svg+xml': 'Svg'
                },
                prefix = exportTypes[config.type] || 'Svg',
                exporter = Ext.draw.engine[prefix + 'Exporter'];           

            return exporter.generate(surface, config);
            
        }
    },

    

    
    availableAttrs: {
        blur: 0,
        "clip-rect": "0 0 1e9 1e9",
        cursor: "default",
        cx: 0,
        cy: 0,
        'dominant-baseline': 'auto',
        fill: "none",
        "fill-opacity": 1,
        font: '10px "Arial"',
        "font-family": '"Arial"',
        "font-size": "10",
        "font-style": "normal",
        "font-weight": 400,
        gradient: "",
        height: 0,
        hidden: false,
        href: "http://sencha.com/",
        opacity: 1,
        path: "M0,0",
        radius: 0,
        rx: 0,
        ry: 0,
        scale: "1 1",
        src: "",
        stroke: "none",
        "stroke-dasharray": "",
        "stroke-linecap": "butt",
        "stroke-linejoin": "butt",
        "stroke-miterlimit": 0,
        "stroke-opacity": 1,
        "stroke-width": 1,
        target: "_blank",
        text: "",
        "text-anchor": "middle",
        title: "Ext Draw",
        width: 0,
        x: 0,
        y: 0,
        zIndex: 0
    },

    
    

    container: undefined,
    height: 352,
    width: 512,
    x: 0,
    y: 0,

    

    
    orderSpritesByZIndex: true,


    
    constructor: function(config) {
        var me = this;
        config = config || {};
        Ext.apply(me, config);

        me.domRef = Ext.getDoc().dom;

        me.customAttributes = {};

        me.addEvents(
            
            'mousedown',
            
            'mouseup',
            
            'mouseover',
            
            'mouseout',
            
            'mousemove',
            
            'mouseenter',
            
            'mouseleave',
            
            'click',
            
            'dblclick'
        );

        me.mixins.observable.constructor.call(me);

        me.getId();
        me.initGradients();
        me.initItems();
        if (me.renderTo) {
            me.render(me.renderTo);
            delete me.renderTo;
        }
        me.initBackground(config.background);
    },

    
    
    initSurface: Ext.emptyFn,

    
    
    renderItem: Ext.emptyFn,

    
    renderItems: Ext.emptyFn,

    
    setViewBox: function (x, y, width, height) {
        if (isFinite(x) && isFinite(y) && isFinite(width) && isFinite(height)) {
            this.viewBox = {x: x, y: y, width: width, height: height};
            this.applyViewBox();
        }
    },

    
    addCls: Ext.emptyFn,

    
    removeCls: Ext.emptyFn,

    
    setStyle: Ext.emptyFn,

    
    initGradients: function() {
        if (this.hasOwnProperty('gradients')) {
            var gradients = this.gradients,
                gLen      = gradients.length,
                fn        = this.addGradient,
                g;

            if (gradients) {
                for (g = 0; g < gLen; g++) {
                    if (fn.call(this, gradients[g], g, gLen) === false) {
                        break;
                    }
                }
            }
        }
    },

    
    initItems: function() {
        var items = this.items;
        this.items = new Ext.draw.CompositeSprite();
        this.items.autoDestroy = true;
        this.groups = new Ext.draw.CompositeSprite();
        if (items) {
            this.add(items);
        }
    },

    
    initBackground: function(config) {
        var me = this,
            width = me.width,
            height = me.height,
            gradientId, gradient, backgroundSprite;
        if (Ext.isString(config)) {
            config = {
                fill : config
            };
        }
        if (config) {
            if (config.gradient) {
                gradient = config.gradient;
                gradientId = gradient.id;
                me.addGradient(gradient);
                me.background = me.add({
                    type: 'rect',
                    x: 0,
                    y: 0,
                    width: width,
                    height: height,
                    fill: 'url(#' + gradientId + ')',
                    zIndex: -1
                });
            } else if (config.fill) {
                me.background = me.add({
                    type: 'rect',
                    x: 0,
                    y: 0,
                    width: width,
                    height: height,
                    fill: config.fill,
                    zIndex: -1
                });
            } else if (config.image) {
                me.background = me.add({
                    type: 'image',
                    x: 0,
                    y: 0,
                    width: width,
                    height: height,
                    src: config.image,
                    zIndex: -1
                });
            }
            
            me.background.bboxExcluded = true;
        }
    },

    
    setSize: function(w, h) {
        this.applyViewBox();
    },

    
    scrubAttrs: function(sprite) {
        var i,
            attrs = {},
            exclude = {},
            sattr = sprite.attr;
        for (i in sattr) {
            
            if (this.translateAttrs.hasOwnProperty(i)) {
                
                attrs[this.translateAttrs[i]] = sattr[i];
                exclude[this.translateAttrs[i]] = true;
            }
            else if (this.availableAttrs.hasOwnProperty(i) && !exclude[i]) {
                
                attrs[i] = sattr[i];
            }
        }
        return attrs;
    },

    
    onClick: function(e) {
        this.processEvent('click', e);
    },
    
    
    onDblClick: function(e) {
        this.processEvent('dblclick', e);
    },

    
    onMouseUp: function(e) {
        this.processEvent('mouseup', e);
    },

    
    onMouseDown: function(e) {
        this.processEvent('mousedown', e);
    },

    
    onMouseOver: function(e) {
        this.processEvent('mouseover', e);
    },

    
    onMouseOut: function(e) {
        this.processEvent('mouseout', e);
    },

    
    onMouseMove: function(e) {
        this.fireEvent('mousemove', e);
    },

    
    onMouseEnter: Ext.emptyFn,

    
    onMouseLeave: Ext.emptyFn,

    
    addGradient: Ext.emptyFn,

    
    add: function() {
        var args = Array.prototype.slice.call(arguments),
            sprite,
            index,
            hasMultipleArgs = args.length > 1,
            items,
            results,
            i,
            ln,
            item;
            
        if (hasMultipleArgs || Ext.isArray(args[0])) {
            items = hasMultipleArgs ? args : args[0];
            results = [];

            for (i = 0, ln = items.length; i < ln; i++) {
                item = items[i];
                item = this.add(item);
                results.push(item);
            }

            return results;
        }
        sprite = this.prepareItems(args[0], true)[0];
        this.insertByZIndex(sprite);
        this.onAdd(sprite);
        return sprite;
    },

    
    insertByZIndex: function(sprite) {
        var me = this,
            sprites = me.items.items,
            len = sprites.length,
            ceil = Math.ceil,
            zIndex = sprite.attr.zIndex,
            idx = len,
            high = idx - 1,
            low = 0,
            otherZIndex;

        if (me.orderSpritesByZIndex && len && zIndex < sprites[high].attr.zIndex) {
            
            while (low <= high) {
                idx = ceil((low + high) / 2);
                otherZIndex = sprites[idx].attr.zIndex;
                if (otherZIndex > zIndex) {
                    high = idx - 1;
                }
                else if (otherZIndex < zIndex) {
                    low = idx + 1;
                }
                else {
                    break;
                }
            }
            
            while (idx < len && sprites[idx].attr.zIndex <= zIndex) {
                idx++;
            }
        }

        me.items.insert(idx, sprite);
        return idx;
    },

    onAdd: function(sprite) {
        var group = sprite.group,
            draggable = sprite.draggable,
            groups, ln, i;
        if (group) {
            groups = [].concat(group);
            ln = groups.length;
            for (i = 0; i < ln; i++) {
                group = groups[i];
                this.getGroup(group).add(sprite);
            }
            delete sprite.group;
        }
        if (draggable) {
            sprite.initDraggable();
        }
    },

    
    remove: function(sprite, destroySprite) {
        if (sprite) {
            this.items.remove(sprite);

            var groups = [].concat(this.groups.items),
                gLen   = groups.length,
                g;

            for (g = 0; g < gLen; g++) {
                groups[g].remove(sprite);
            }

            sprite.onRemove();
            if (destroySprite === true) {
                sprite.destroy();
            }
        }
    },

    
    removeAll: function(destroySprites) {
        var items = this.items.items,
            ln = items.length,
            i;
        for (i = ln - 1; i > -1; i--) {
            this.remove(items[i], destroySprites);
        }
    },

    onRemove: Ext.emptyFn,

    onDestroy: Ext.emptyFn,

    
    applyViewBox: function() {
        var me = this,
            viewBox = me.viewBox,
            width = me.width || 1, 
            height = me.height || 1,
            viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight,
            relativeHeight, relativeWidth, size;

        if (viewBox && (width || height)) {
            viewBoxX = viewBox.x;
            viewBoxY = viewBox.y;
            viewBoxWidth = viewBox.width;
            viewBoxHeight = viewBox.height;
            relativeHeight = height / viewBoxHeight;
            relativeWidth = width / viewBoxWidth;
            size = Math.min(relativeWidth, relativeHeight);

            if (viewBoxWidth * size < width) {
                viewBoxX -= (width - viewBoxWidth * size) / 2 / size;
            }
            if (viewBoxHeight * size < height) {
                viewBoxY -= (height - viewBoxHeight * size) / 2 / size;
            }

            me.viewBoxShift = {
                dx: -viewBoxX,
                dy: -viewBoxY,
                scale: size
            };
            
            if (me.background) {
                me.background.setAttributes(Ext.apply({}, {
                    x: viewBoxX,
                    y: viewBoxY,
                    width: width / size,
                    height: height / size
                }, { hidden: false }), true);
            }
        } else {
            if (me.background && width && height) {
                me.background.setAttributes(Ext.apply({x: 0, y: 0, width: width, height: height}, { hidden: false }), true);
            }
        }
    },


    getBBox: function (sprite, isWithoutTransform) {
        var realPath = this["getPath" + sprite.type](sprite);
        if (isWithoutTransform) {
            sprite.bbox.plain = sprite.bbox.plain || Ext.draw.Draw.pathDimensions(realPath);
            return sprite.bbox.plain;
        }
        if (sprite.dirtyTransform) {
            this.applyTransformations(sprite, true);
        }
        sprite.bbox.transform = sprite.bbox.transform || Ext.draw.Draw.pathDimensions(Ext.draw.Draw.mapPath(realPath, sprite.matrix));
        return sprite.bbox.transform;
    },
    
    transformToViewBox: function (x, y) {
        if (this.viewBoxShift) {
            var me = this, shift = me.viewBoxShift;
            return [x / shift.scale - shift.dx, y / shift.scale - shift.dy];
        } else {
            return [x, y];
        }
    },

    
    applyTransformations: function(sprite, onlyMatrix) {
        if (sprite.type == 'text') {
            
            sprite.bbox.transform = 0;
            this.transform(sprite, false);
        }


        sprite.dirtyTransform = false;
        
        var me = this,
            attr = sprite.attr;

        if (attr.translation.x != null || attr.translation.y != null) {
            me.translate(sprite);
        }
        if (attr.scaling.x != null || attr.scaling.y != null) {
            me.scale(sprite);
        }
        if (attr.rotation.degrees != null) {
            me.rotate(sprite);
        }
        
        sprite.bbox.transform = 0;
        this.transform(sprite, onlyMatrix);
        sprite.transformations = [];
    },

    
    rotate: function (sprite) {
        var bbox,
            deg = sprite.attr.rotation.degrees,
            centerX = sprite.attr.rotation.x,
            centerY = sprite.attr.rotation.y;
        if (!Ext.isNumber(centerX) || !Ext.isNumber(centerY)) {
            bbox = this.getBBox(sprite, true);
            centerX = !Ext.isNumber(centerX) ? bbox.x + bbox.width / 2 : centerX;
            centerY = !Ext.isNumber(centerY) ? bbox.y + bbox.height / 2 : centerY;
        }
        sprite.transformations.push({
            type: "rotate",
            degrees: deg,
            x: centerX,
            y: centerY
        });
    },

    
    translate: function(sprite) {
        var x = sprite.attr.translation.x || 0,
            y = sprite.attr.translation.y || 0;
        sprite.transformations.push({
            type: "translate",
            x: x,
            y: y
        });
    },

    
    scale: function(sprite) {
        var bbox,
            x = sprite.attr.scaling.x || 1,
            y = sprite.attr.scaling.y || 1,
            centerX = sprite.attr.scaling.centerX,
            centerY = sprite.attr.scaling.centerY;

        if (!Ext.isNumber(centerX) || !Ext.isNumber(centerY)) {
            bbox = this.getBBox(sprite, true);
            centerX = !Ext.isNumber(centerX) ? bbox.x + bbox.width / 2 : centerX;
            centerY = !Ext.isNumber(centerY) ? bbox.y + bbox.height / 2 : centerY;
        }
        sprite.transformations.push({
            type: "scale",
            x: x,
            y: y,
            centerX: centerX,
            centerY: centerY
        });
    },

    
    rectPath: function (x, y, w, h, r) {
        if (r) {
            return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]];
        }
        return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]];
    },

    
    ellipsePath: function (x, y, rx, ry) {
        if (ry == null) {
            ry = rx;
        }
        return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]];
    },

    
    getPathpath: function (el) {
        return el.attr.path;
    },

    
    getPathcircle: function (el) {
        var a = el.attr;
        return this.ellipsePath(a.x, a.y, a.radius, a.radius);
    },

    
    getPathellipse: function (el) {
        var a = el.attr;
        return this.ellipsePath(a.x, a.y,
                                a.radiusX || (a.width / 2) || 0,
                                a.radiusY || (a.height / 2) || 0);
    },

    
    getPathrect: function (el) {
        var a = el.attr;
        return this.rectPath(a.x || 0, a.y || 0, a.width || 0, a.height || 0, a.r || 0);
    },

    
    getPathimage: function (el) {
        var a = el.attr;
        return this.rectPath(a.x || 0, a.y || 0, a.width, a.height);
    },

    
    getPathtext: function (el) {
        var bbox = this.getBBoxText(el);
        return this.rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
    },

    createGroup: function(id) {
        var group = this.groups.get(id);
        if (!group) {
            group = new Ext.draw.CompositeSprite({
                surface: this
            });
            group.id = id || Ext.id(null, 'ext-surface-group-');
            this.groups.add(group);
        }
        return group;
    },

    
    getGroup: function(id) {
        var group;
        if (typeof id == "string") {
            group = this.groups.get(id);
            if (!group) {
                group = this.createGroup(id);
            }
        } else {
            group = id;
        }
        return group;
    },

    
    prepareItems: function(items, applyDefaults) {
        items = [].concat(items);
        
        var item, i, ln;
        for (i = 0, ln = items.length; i < ln; i++) {
            item = items[i];
            if (!(item instanceof Ext.draw.Sprite)) {
                
                item.surface = this;
                items[i] = this.createItem(item);
            } else {
                item.surface = this;
            }
        }
        return items;
    },

    
    setText: Ext.emptyFn,

    
    
    createItem: Ext.emptyFn,

    
    getId: function() {
        return this.id || (this.id = Ext.id(null, 'ext-surface-'));
    },

    
    destroy: function() {
        var me = this;
        delete me.domRef;
        if (me.background) {
            me.background.destroy();
        }
        me.removeAll(true);
        Ext.destroy(me.groups.items);
    }
});



Ext.define('Ext.fx.Manager', {

    

    singleton: true,

    requires: ['Ext.util.MixedCollection',
               'Ext.fx.target.Element',
               'Ext.fx.target.ElementCSS',
               'Ext.fx.target.CompositeElement',
               'Ext.fx.target.CompositeElementCSS',
               'Ext.fx.target.Sprite',
               'Ext.fx.target.CompositeSprite',
               'Ext.fx.target.Component'],

    mixins: {
        queue: 'Ext.fx.Queue'
    },

    

    constructor: function() {
        this.items = new Ext.util.MixedCollection();
        this.mixins.queue.constructor.call(this);

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    },

    
    interval: 16,

    
    forceJS: true,

    
    createTarget: function(target) {
        var me = this,
            useCSS3 = !me.forceJS && Ext.supports.Transitions,
            targetObj;

        me.useCSS3 = useCSS3;

        if (target) {
            
            if (target.tagName || Ext.isString(target) || target.isFly) {
                target = Ext.get(target);
                targetObj = new Ext.fx.target['Element' + (useCSS3 ? 'CSS' : '')](target);
            }
            
            else if (target.dom) {
                targetObj = new Ext.fx.target['Element' + (useCSS3 ? 'CSS' : '')](target);
            }
            
            else if (target.isComposite) {
                targetObj = new Ext.fx.target['CompositeElement' + (useCSS3 ? 'CSS' : '')](target);
            }
            
            else if (target.isSprite) {
                targetObj = new Ext.fx.target.Sprite(target);
            }
            
            else if (target.isCompositeSprite) {
                targetObj = new Ext.fx.target.CompositeSprite(target);
            }
            
            else if (target.isComponent) {
                targetObj = new Ext.fx.target.Component(target);
            }
            else if (target.isAnimTarget) {
                return target;
            }
            else {
                return null;
            }
            me.targets.add(targetObj);
            return targetObj;
        }
        else {
            return null;
        }
    },

    
    addAnim: function(anim) {
        var items = this.items,
            task = this.task;

        
        
        
        items.add(anim.id, anim);
        

        
        if (!task && items.length) {
            task = this.task = {
                run: this.runner,
                interval: this.interval,
                scope: this
            };
            
            Ext.TaskManager.start(task);
        }
    },

    
    removeAnim: function(anim) {
        var me = this,
            items = me.items,
            task = me.task;
                
        items.removeAtKey(anim.id);
        
        
        
        if (task && !items.length) {
            
            Ext.TaskManager.stop(task);
            delete me.task;
        }
    },

    
    runner: function() {
        var me = this,
            items = me.items.getRange(),
            i = 0,
            len = items.length,
            anim;

        
        me.targetArr = {};

        
        me.timestamp = new Date();
        
        
        
        
        
        
        
        
        
        
        
        for (; i < len; i++) {
            anim = items[i];
            
            if (anim.isReady()) {
                
                me.startAnim(anim);
            }
        }
        
        for (i = 0; i < len; i++) {
            anim = items[i];
            
            if (anim.isRunning()) {
                
                me.runAnim(anim);
            }
        }

        
        me.applyPendingAttrs();
    },

    
    startAnim: function(anim) {
        anim.start(this.timestamp);
    },

    
    runAnim: function(anim) {
        if (!anim) {
            return;
        }
        var me = this,
            targetId = anim.target.getId(),
            useCSS3 = me.useCSS3 && anim.target.type == 'element',
            elapsedTime = me.timestamp - anim.startTime,
            lastFrame = (elapsedTime >= anim.duration),
            target, o;

        target = this.collectTargetData(anim, elapsedTime, useCSS3, lastFrame);
        
        
        
        if (useCSS3) {
            
            
            
            anim.target.setAttr(target.anims[anim.id].attributes, true);

            
            me.collectTargetData(anim, anim.duration, useCSS3, lastFrame);

            
            anim.paused = true;

            target = anim.target.target;
            
            if (anim.target.isComposite) {
                target = anim.target.target.last();
            }

            
            o = {};
            o[Ext.supports.CSS3TransitionEnd] = anim.lastFrame;
            o.scope = anim;
            o.single = true;
            target.on(o);
        }
    },

    
    collectTargetData: function(anim, elapsedTime, useCSS3, isLastFrame) {
        var targetId = anim.target.getId(),
            target = this.targetArr[targetId];
        
        if (!target) {
            
            
            
            
            target = this.targetArr[targetId] = {
                id: targetId,
                el: anim.target,
                anims: {}
            };
        }

        
        
        
        
        target.anims[anim.id] = {
            id: anim.id,
            anim: anim,
            elapsed: elapsedTime,
            isLastFrame: isLastFrame,
            
            attributes: [{
                duration: anim.duration,
                easing: (useCSS3 && anim.reverse) ? anim.easingFn.reverse().toCSS3() : anim.easing,
                
                
                attrs: anim.runAnim(elapsedTime)
            }]
        };
        
        return target;
    },
    
    
    applyPendingAttrs: function() {
        var targetArr = this.targetArr,
            target, targetId, animWrap, anim, animId;
        
        
        for (targetId in targetArr) {
            if (targetArr.hasOwnProperty(targetId)) {
                target = targetArr[targetId];
                
                
                for (animId in target.anims) {
                    if (target.anims.hasOwnProperty(animId)) {
                        animWrap = target.anims[animId];
                        anim = animWrap.anim;
                        
                        
                        if (animWrap.attributes && anim.isRunning()) {
                            
                            target.el.setAttr(animWrap.attributes, false, animWrap.isLastFrame);
                            
                            
                            if (animWrap.isLastFrame) {
                                
                                anim.lastFrame();
                            }
                        }
                    }
                }
            }
        }
    }
});


Ext.define('Ext.fx.Animator', {

    

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: ['Ext.fx.Manager'],

    

    
    isAnimator: true,

    
    duration: 250,

    
    delay: 0,

    
    delayStart: 0,

    
    dynamic: false,

    
    easing: 'ease',

    
    running: false,

    
    paused: false,

    
    damper: 1,

    
    iterations: 1,

    
    currentIteration: 0,

    
    keyframeStep: 0,

    
    animKeyFramesRE: /^(from|to|\d+%?)$/,

    

     
    constructor: function(config) {
        var me = this;
        config = Ext.apply(me, config || {});
        me.config = config;
        me.id = Ext.id(null, 'ext-animator-');
        me.addEvents(
            
            'beforeanimate',
            
            'keyframe',
            
            'afteranimate'
        );
        me.mixins.observable.constructor.call(me, config);
        me.timeline = [];
        me.createTimeline(me.keyframes);
        if (me.target) {
            me.applyAnimator(me.target);
            Ext.fx.Manager.addAnim(me);
        }
    },

    
    sorter: function (a, b) {
        return a.pct - b.pct;
    },

    
    createTimeline: function(keyframes) {
        var me = this,
            attrs = [],
            to = me.to || {},
            duration = me.duration,
            prevMs, ms, i, ln, pct, anim, nextAnim, attr;

        for (pct in keyframes) {
            if (keyframes.hasOwnProperty(pct) && me.animKeyFramesRE.test(pct)) {
                attr = {attrs: Ext.apply(keyframes[pct], to)};
                
                if (pct == "from") {
                    pct = 0;
                }
                else if (pct == "to") {
                    pct = 100;
                }
                
                attr.pct = parseInt(pct, 10);
                attrs.push(attr);
            }
        }
        
        Ext.Array.sort(attrs, me.sorter);
        
        
        
        

        ln = attrs.length;
        for (i = 0; i < ln; i++) {
            prevMs = (attrs[i - 1]) ? duration * (attrs[i - 1].pct / 100) : 0;
            ms = duration * (attrs[i].pct / 100);
            me.timeline.push({
                duration: ms - prevMs,
                attrs: attrs[i].attrs
            });
        }
    },

    
    applyAnimator: function(target) {
        var me = this,
            anims = [],
            timeline = me.timeline,
            reverse = me.reverse,
            ln = timeline.length,
            anim, easing, damper, initial, attrs, lastAttrs, i;

        if (me.fireEvent('beforeanimate', me) !== false) {
            for (i = 0; i < ln; i++) {
                anim = timeline[i];
                attrs = anim.attrs;
                easing = attrs.easing || me.easing;
                damper = attrs.damper || me.damper;
                delete attrs.easing;
                delete attrs.damper;
                anim = new Ext.fx.Anim({
                    target: target,
                    easing: easing,
                    damper: damper,
                    duration: anim.duration,
                    paused: true,
                    to: attrs
                });
                anims.push(anim);
            }
            me.animations = anims;
            me.target = anim.target;
            for (i = 0; i < ln - 1; i++) {
                anim = anims[i];
                anim.nextAnim = anims[i + 1];
                anim.on('afteranimate', function() {
                    this.nextAnim.paused = false;
                });
                anim.on('afteranimate', function() {
                    this.fireEvent('keyframe', this, ++this.keyframeStep);
                }, me);
            }
            anims[ln - 1].on('afteranimate', function() {
                this.lastFrame();
            }, me);
        }
    },

    
    start: function(startTime) {
        var me = this,
            delay = me.delay,
            delayStart = me.delayStart,
            delayDelta;
        if (delay) {
            if (!delayStart) {
                me.delayStart = startTime;
                return;
            }
            else {
                delayDelta = startTime - delayStart;
                if (delayDelta < delay) {
                    return;
                }
                else {
                    
                    startTime = new Date(delayStart.getTime() + delay);
                }
            }
        }
        if (me.fireEvent('beforeanimate', me) !== false) {
            me.startTime = startTime;
            me.running = true;
            me.animations[me.keyframeStep].paused = false;
        }
    },

    
    lastFrame: function() {
        var me = this,
            iter = me.iterations,
            iterCount = me.currentIteration;

        iterCount++;
        if (iterCount < iter) {
            me.startTime = new Date();
            me.currentIteration = iterCount;
            me.keyframeStep = 0;
            me.applyAnimator(me.target);
            me.animations[me.keyframeStep].paused = false;
        }
        else {
            me.currentIteration = 0;
            me.end();
        }
    },

    
    end: function() {
        var me = this;
        me.fireEvent('afteranimate', me, me.startTime, new Date() - me.startTime);
    },
    
    isReady: function() {
        return this.paused === false && this.running === false && this.iterations > 0;
    },
    
    isRunning: function() {
        
        return false;
    }
});

Ext.define('Ext.fx.Anim', {

    

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: ['Ext.fx.Manager', 'Ext.fx.Animator', 'Ext.fx.Easing', 'Ext.fx.CubicBezier', 'Ext.fx.PropertyHandler'],

    

    
    isAnimation: true,

    

    

    
    duration: 250,

    
    delay: 0,

    
    delayStart: 0,

    
    dynamic: false,

    
    easing: 'ease',

    

    
    damper: 1,

    
    bezierRE: /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,

    
    reverse: false,

    
    running: false,

    
    paused: false,

    
    iterations: 1,

    
    alternate: false,

    
    currentIteration: 0,

    
    startTime: 0,

    

    

    

    
    
    
    frameCount: 0,

    
    constructor: function(config) {
        var me = this,
            curve;
            
        config = config || {};
        
        if (config.keyframes) {
            return new Ext.fx.Animator(config);
        }
        Ext.apply(me, config);
        if (me.from === undefined) {
            me.from = {};
        }
        me.propHandlers = {};
        me.config = config;
        me.target = Ext.fx.Manager.createTarget(me.target);
        me.easingFn = Ext.fx.Easing[me.easing];
        me.target.dynamic = me.dynamic;

        
        if (!me.easingFn) {
            me.easingFn = String(me.easing).match(me.bezierRE);
            if (me.easingFn && me.easingFn.length == 5) {
                curve = me.easingFn;
                me.easingFn = Ext.fx.CubicBezier.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]);
            }
        }
        me.id = Ext.id(null, 'ext-anim-');
        me.addEvents(
            
            'beforeanimate',
             
            'afteranimate',
             
            'lastframe'
        );
        me.mixins.observable.constructor.call(me);
        Ext.fx.Manager.addAnim(me);
    },

    
    setAttr: function(attr, value) {
        return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value);
    },

    
    initAttrs: function() {
        var me = this,
            from = me.from,
            to = me.to,
            initialFrom = me.initialFrom || {},
            out = {},
            start, end, propHandler, attr;

        for (attr in to) {
            if (to.hasOwnProperty(attr)) {
                start = me.target.getAttr(attr, from[attr]);
                end = to[attr];
                
                if (!Ext.fx.PropertyHandler[attr]) {
                    if (Ext.isObject(end)) {
                        propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.object;
                    } else {
                        propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler.defaultHandler;
                    }
                }
                
                else {
                    propHandler = me.propHandlers[attr] = Ext.fx.PropertyHandler[attr];
                }
                out[attr] = propHandler.get(start, end, me.damper, initialFrom[attr], attr);
            }
        }
        me.currentAttrs = out;
    },

    
    start: function(startTime) {
        var me = this,
            delay = me.delay,
            delayStart = me.delayStart,
            delayDelta;
        
        if (delay) {
            if (!delayStart) {
                me.delayStart = startTime;
                return;
            }
            else {
                delayDelta = startTime - delayStart;
                if (delayDelta < delay) {
                    return;
                }
                else {
                    
                    startTime = new Date(delayStart.getTime() + delay);
                }
            }
        }
        if (me.fireEvent('beforeanimate', me) !== false) {
            me.startTime = startTime;
            if (!me.paused && !me.currentAttrs) {
                me.initAttrs();
            }
            me.running = true;
            me.frameCount = 0;
        }
    },

    
    runAnim: function(elapsedTime) {
        var me = this,
            attrs = me.currentAttrs,
            duration = me.duration,
            easingFn = me.easingFn,
            propHandlers = me.propHandlers,
            ret = {},
            easing, values, attr, lastFrame;

        if (elapsedTime >= duration) {
            elapsedTime = duration;
            lastFrame = true;
        }
        if (me.reverse) {
            elapsedTime = duration - elapsedTime;
        }

        for (attr in attrs) {
            if (attrs.hasOwnProperty(attr)) {
                values = attrs[attr];
                easing = lastFrame ? 1 : easingFn(elapsedTime / duration);
                ret[attr] = propHandlers[attr].set(values, easing);
            }
        }
        me.frameCount++;
            
        return ret;
    },

    
    lastFrame: function() {
        var me = this,
            iter = me.iterations,
            iterCount = me.currentIteration;

        iterCount++;
        if (iterCount < iter) {
            if (me.alternate) {
                me.reverse = !me.reverse;
            }
            me.startTime = new Date();
            me.currentIteration = iterCount;
            
            me.paused = false;
        }
        else {
            me.currentIteration = 0;
            me.end();
            me.fireEvent('lastframe', me, me.startTime);
        }
    },

    endWasCalled: 0,

    
    end: function() {
        if (this.endWasCalled++) {
            return;
        }
        var me = this;
        me.startTime = 0;
        me.paused = false;
        me.running = false;
        Ext.fx.Manager.removeAnim(me);
        me.fireEvent('afteranimate', me, me.startTime);
        Ext.callback(me.callback, me.scope, [me, me.startTime]);
    },
    
    isReady: function() {
        return this.paused === false && this.running === false && this.iterations > 0;
    },
    
    isRunning: function() {
        return this.paused === false && this.running === true && this.isAnimator !== true;
    }
});

Ext.enableFx = true;


Ext.define('Ext.chart.Highlight', {

    

    requires: ['Ext.fx.Anim'],

    

    
    highlight: false,

    highlightCfg : {
        fill: '#fdd',
        "stroke-width": 5,
        stroke: '#f55'
    },

    constructor: function(config) {
        if (config.highlight) {
            if (config.highlight !== true) { 
                this.highlightCfg = Ext.merge(this.highlightCfg, config.highlight);
            }
        }
    },

    
    highlightItem: function(item) {
        if (!item) {
            return;
        }
        
        var me = this,
            sprite = item.sprite,
            opts = Ext.merge({}, me.highlightCfg, me.highlight),
            surface = me.chart.surface,
            animate = me.chart.animate,
            p, from, to, pi;

        if (!me.highlight || !sprite || sprite._highlighted) {
            return;
        }
        if (sprite._anim) {
            sprite._anim.paused = true;
        }
        sprite._highlighted = true;
        if (!sprite._defaults) {
            sprite._defaults = Ext.apply({}, sprite.attr);
            from = {};
            to = {};
            for (p in opts) {
                if (! (p in sprite._defaults)) {
                    sprite._defaults[p] = surface.availableAttrs[p];
                }
                from[p] = sprite._defaults[p];
                to[p] = opts[p];
                if (Ext.isObject(opts[p])) {
                    from[p] = {};
                    to[p] = {};
                    Ext.apply(sprite._defaults[p], sprite.attr[p]);
                    Ext.apply(from[p], sprite._defaults[p]);
                    for (pi in sprite._defaults[p]) {
                        if (! (pi in opts[p])) {
                            to[p][pi] = from[p][pi];
                        } else {
                            to[p][pi] = opts[p][pi];
                        }
                    }
                    for (pi in opts[p]) {
                        if (! (pi in to[p])) {
                            to[p][pi] = opts[p][pi];
                        }
                    }
                }
            }
            sprite._from = from;
            sprite._to = to;
            sprite._endStyle = to;
        }
        if (animate) {
            sprite._anim = new Ext.fx.Anim({
                target: sprite,
                from: sprite._from,
                to: sprite._to,
                duration: 150
            });
        } else {
            sprite.setAttributes(sprite._to, true);
        }
    },

    
    unHighlightItem: function() {
        if (!this.highlight || !this.items) {
            return;
        }

        var me = this,
            items = me.items,
            len = items.length,
            opts = Ext.merge({}, me.highlightCfg, me.highlight),
            animate = me.chart.animate,
            i = 0,
            obj, p, sprite;
        for (; i < len; i++) {
            if (!items[i]) {
                continue;
            }
            sprite = items[i].sprite;
            if (sprite && sprite._highlighted) {
                if (sprite._anim) {
                    sprite._anim.paused = true;
                }
                obj = {};
                for (p in opts) {
                    if (Ext.isObject(sprite._defaults[p])) {
                        obj[p] = {};
                        Ext.apply(obj[p], sprite._defaults[p]);
                    }
                    else {
                        obj[p] = sprite._defaults[p];
                    }
                }
                if (animate) {
                    
                    sprite._endStyle = obj;
                    sprite._anim = new Ext.fx.Anim({
                        target: sprite,
                        to: obj,
                        duration: 150
                    });
                }
                else {
                    sprite.setAttributes(obj, true);
                }
                delete sprite._highlighted;
                
            }
        }
    },

    cleanHighlights: function() {
        if (!this.highlight) {
            return;
        }

        var group = this.group,
            markerGroup = this.markerGroup,
            i = 0,
            l;
        for (l = group.getCount(); i < l; i++) {
            delete group.getAt(i)._defaults;
        }
        if (markerGroup) {
            for (l = markerGroup.getCount(); i < l; i++) {
                delete markerGroup.getAt(i)._defaults;
            }
        }
    }
});

Ext.define('Ext.layout.Context', {
    requires: [
        'Ext.util.Queue',
        'Ext.layout.ContextItem',
        'Ext.layout.Layout',
        'Ext.fx.Anim',
        'Ext.fx.Manager'
    ],

    remainingLayouts: 0,

    
    state: 0,

    constructor: function (config) {
        var me = this;

        Ext.apply(me, config);

        
        me.items = {};

        
        me.layouts = {};

        
        me.blockCount = 0;
        
        me.cycleCount = 0;
        
        me.flushCount = 0;
        
        me.calcCount = 0;

        me.animateQueue = me.newQueue();
        me.completionQueue = me.newQueue();
        me.finalizeQueue = me.newQueue();
        me.finishQueue = me.newQueue();
        me.flushQueue = me.newQueue();

        me.invalidateData = {};

        
        me.layoutQueue = me.newQueue();

        
        
        me.invalidQueue = [];

        me.triggers = {
            data: {
                
            },
            dom: {}
        };
    },

    callLayout: function (layout, methodName) {
        this.currentLayout = layout;
        layout[methodName](this.getCmp(layout.owner));
    },

    cancelComponent: function (comp, isChild, isDestroying) {
        var me = this,
            components = comp,
            isArray = !comp.isComponent,
            length = isArray ? components.length : 1,
            i, k, klen, items, layout, newQueue, oldQueue, entry, temp,
            ownerCtContext;

        for (i = 0; i < length; ++i) {
            if (isArray) {
                comp = components[i];
            }

            
            if (isDestroying && comp.ownerCt) {
                ownerCtContext = this.items[comp.ownerCt.el.id];
                if (ownerCtContext) {
                    Ext.Array.remove(ownerCtContext.childItems, me.getCmp(comp));
                }
            }

            if (!isChild) {
                oldQueue = me.invalidQueue;
                klen = oldQueue.length;

                if (klen) {
                    me.invalidQueue = newQueue = [];
                    for (k = 0; k < klen; ++k) {
                        entry = oldQueue[k];
                        temp = entry.item.target;
                        if (temp != comp && !temp.isDescendant(comp)) {
                            newQueue.push(entry);
                        }
                    }
                }
            }

            layout = comp.componentLayout;
            me.cancelLayout(layout);

            if (layout.getLayoutItems) {
                items = layout.getLayoutItems();
                if (items.length) {
                    me.cancelComponent(items, true);
                }
            }

            if (comp.isContainer && !comp.collapsed) {
                layout = comp.layout;
                me.cancelLayout(layout);

                items = layout.getVisibleItems();
                if (items.length) {
                    me.cancelComponent(items, true);
                }
            }
        }
    },

    cancelLayout: function (layout) {
        var me = this;

        me.completionQueue.remove(layout);
        me.finalizeQueue.remove(layout);
        me.finishQueue.remove(layout);
        me.layoutQueue.remove(layout);

        if (layout.running) {
            me.layoutDone(layout);
        }

        layout.ownerContext = null;
    },

    clearTriggers: function (layout, inDom) {
        var id = layout.id,
            collection = this.triggers[inDom ? 'dom' : 'data'],
            triggers = collection && collection[id],
            length = (triggers && triggers.length) || 0,
            collection, i, item, trigger;

        for (i = 0; i < length; ++i) {
            trigger = triggers[i];
            item = trigger.item;

            collection = inDom ? item.domTriggers : item.triggers;
            delete collection[trigger.prop][id];
        }
    },

    
    flush: function () {
        var me = this,
            items = me.flushQueue.clear(),
            length = items.length, i;

        if (length) {
            ++me.flushCount;

            for (i = 0; i < length; ++i) {
                items[i].flush();
            }
        }
    },

    flushAnimations: function() {
        var me = this,
            items = me.animateQueue.clear(),
            len = items.length,
            i;

        if (len) {
            for (i = 0; i < len; i++) {
                
                
                
                if (items[i].target.animate !== false) {
                    items[i].flushAnimations();
                }
            }

            
            
            Ext.fx.Manager.runner();
        }
    },

    flushInvalidates: function () {
        var me = this,
            queue = me.invalidQueue,
            length = queue && queue.length,
            comp, components, entry, i;

        me.invalidQueue = [];

        if (length) {
            components = [];
            for (i = 0; i < length; ++i) {
                comp = (entry = queue[i]).item.target;
                
                
                
                
                if (!comp.container.isDetachedBody) {
                    components.push(comp);

                    if (entry.options) {
                        me.invalidateData[comp.id] = entry.options;
                    }
                }
            }

            me.invalidate(components, null);
        }
    },

    flushLayouts: function (queueName, methodName, dontClear) {
        var me = this,
            layouts = dontClear ? me[queueName].items : me[queueName].clear(),
            length = layouts.length,
            i, layout;

        if (length) {
            for (i = 0; i < length; ++i) {
                layout = layouts[i];
                if (!layout.running) {
                    me.callLayout(layout, methodName);
                }
            }
            me.currentLayout = null;
        }
    },

    
    getCmp: function (cmp) {
        return this.getItem(cmp, cmp.el);
    },

    
    getEl: function (parent, el) {
        var item = this.getItem(el, el);

        if (!item.parent) {
            item.parent = parent;

            
            
            
            if (parent.children.length) {
                parent.children.push(item);
            } else {
                parent.children = [ item ]; 
            }
        }

        return item;
    },

    getItem: function (target, el) {
        var id = el.id,
            items = this.items,
            item = items[id] ||
                  (items[id] = new Ext.layout.ContextItem({
                                    context: this,
                                    target: target,
                                    el: el
                                }));

        return item;
    },

    handleFailure: function () {
        
        
        
        var layouts = this.layouts,
            layout, key;

        Ext.failedLayouts = (Ext.failedLayouts || 0) + 1;

        for (key in layouts) {
            layout = layouts[key];

            if (layouts.hasOwnProperty(key)) {
                layout.running      = false;
                layout.ownerContext = null;
            }
        }
    },

    
    invalidate: function (components, full) {
        var me = this,
            isArray = !components.isComponent,
            componentChildrenDone, containerChildrenDone, containerLayoutDone,
            firstTime, i, comp, item, items, length, componentLayout, layout,
            invalidateOptions, token;

        for (i = 0, length = isArray ? components.length : 1; i < length; ++i) {
            comp = isArray ? components[i] : components;

            if (comp.rendered && !comp.hidden) {
                item = me.getCmp(comp);
                componentLayout = comp.componentLayout;
                firstTime = !componentLayout.ownerContext;
                layout = (comp.isContainer && !comp.collapsed) ? comp.layout : null;

                
                invalidateOptions = me.invalidateData[item.id];
                delete me.invalidateData[item.id];

                
                
                
                
                
                
                token = item.init(full, invalidateOptions);

                if (invalidateOptions) {
                    me.processInvalidate(invalidateOptions, item, 'before');
                }

                
                
                
                if (componentLayout.beforeLayoutCycle) {
                    componentLayout.beforeLayoutCycle(item);
                }

                
                
                token = item.initContinue(token);

                
                
                componentChildrenDone = containerChildrenDone = containerLayoutDone = true;

                
                
                
                
                if (componentLayout.getLayoutItems) {
                    componentLayout.renderChildren();

                    items = componentLayout.getLayoutItems();
                    if (items.length) {
                        me.invalidate(items, true);
                        componentChildrenDone = false;
                    }
                }

                if (layout) {
                    containerLayoutDone = false;
                    layout.renderChildren();

                    items = layout.getVisibleItems();
                    if (items.length) {
                        me.invalidate(items, true);
                        containerChildrenDone = false;
                    }
                }

                
                
                item.initDone(token, componentChildrenDone, containerChildrenDone,
                              containerLayoutDone);

                
                
                me.resetLayout(componentLayout, item, firstTime);
                if (layout) {
                    me.resetLayout(layout, item, firstTime);
                }

                
                
                
                item.initAnimation();

                if (invalidateOptions) {
                    me.processInvalidate(invalidateOptions, item, 'after');
                }
            }
        }

        me.currentLayout = null;
    },

    layoutDone: function (layout) {
        var ownerContext = layout.ownerContext,
            ownerCtContext;

        layout.running = false;

        
        
        
        if (layout.isComponentLayout) {
            if (ownerContext.measuresBox) {
                ownerContext.onBoxMeasured(); 
            }

            ownerContext.setProp('done', true);

            ownerCtContext = ownerContext.ownerCtContext;
            if (ownerCtContext) {
                if (ownerContext.target.ownerLayout.isComponentLayout) {
                    if (! --ownerCtContext.remainingComponentChildLayouts) {
                        ownerCtContext.setProp('componentChildrenDone', true);
                    }
                } else {
                    if (! --ownerCtContext.remainingContainerChildLayouts) {
                        ownerCtContext.setProp('containerChildrenDone', true);
                    }
                }
                if (! --ownerCtContext.remainingChildLayouts) {
                    ownerCtContext.setProp('childrenDone', true);
                }
            }
        } else {
            ownerContext.setProp('containerLayoutDone', true);
        }

        --this.remainingLayouts;
        ++this.progressCount; 
    },

    newQueue: function () {
        return new Ext.util.Queue();
    },

    processInvalidate: function (options, item, name) {
        
        
        if (options[name]) {
            var me = this,
                currentLayout = me.currentLayout;

            me.currentLayout = options.layout || null;

            options[name](item, options);

            me.currentLayout = currentLayout;
        }
    },

    
    queueAnimation: function (item) {
        this.animateQueue.add(item);
    },

    
    queueCompletion: function (layout) {
        this.completionQueue.add(layout);
    },

    
    queueFinalize: function (layout) {
        this.finalizeQueue.add(layout);
    },

    
    queueFlush: function (item) {
        this.flushQueue.add(item);
    },

    chainFns: function (oldOptions, newOptions, funcName) {
        var me = this,
            oldLayout = oldOptions.layout,
            newLayout = newOptions.layout,
            oldFn = oldOptions[funcName],
            newFn = newOptions[funcName];

        
        
        return function (contextItem) {
            var prev = me.currentLayout;
            if (oldFn) {
                me.currentLayout = oldLayout;
                oldFn.call(oldOptions.scope || oldOptions, contextItem, oldOptions);
            }
            me.currentLayout = newLayout;
            newFn.call(newOptions.scope || newOptions, contextItem, newOptions);
            me.currentLayout = prev;
        };
    },

    
    queueInvalidate: function (item, options) {
        var me = this,
            newQueue = [],
            oldQueue = me.invalidQueue,
            index = oldQueue.length,
            comp, old, oldComp, oldOptions, oldState;

        if (item.isComponent) {
            item = me.getCmp(comp = item);
        } else {
            comp = item.target;
        }

        item.invalid = true;

        
        
        
        while (index--) {
            old = oldQueue[index];
            oldComp = old.item.target;

            if (comp.isDescendant(oldComp)) {
                return; 
            }

            if (oldComp == comp) {
                
                if (!(oldOptions = old.options)) {
                    old.options = options;
                } else if (options) {
                    if (options.widthModel) {
                        oldOptions.widthModel = options.widthModel;
                    }
                    if (options.heightModel) {
                        oldOptions.heightModel = options.heightModel;
                    }
                    if (!(oldState = oldOptions.state)) {
                        oldOptions.state = options.state;
                    } else if (options.state) {
                        Ext.apply(oldState, options.state);
                    }

                    if (options.before) {
                        oldOptions.before = me.chainFns(oldOptions, options, 'before');
                    }
                    if (options.after) {
                        oldOptions.after = me.chainFns(oldOptions, options, 'after');
                    }
                }

                
                return;
            }

            if (!oldComp.isDescendant(comp)) {
                newQueue.push(old); 
            }
            
        }
        

        
        
        newQueue.push({ item: item, options: options });

        me.invalidQueue = newQueue;
    },

    queueItemLayouts: function (item) {
        var comp = item.isComponent ? item : item.target,
            layout = comp.componentLayout;

        if (!layout.pending && !layout.invalid && !layout.done) {
            this.queueLayout(layout);
        }

        layout = comp.layout;
        if (layout && !layout.pending && !layout.invalid && !layout.done) {
            this.queueLayout(layout);
        }
    },

    
    queueLayout: function (layout) {
        this.layoutQueue.add(layout);
        layout.pending = true;
    },

    
    resetLayout: function (layout, ownerContext, firstTime) {
        var me = this,
            ownerCtContext;

        me.currentLayout = layout;

        layout.done = false;
        layout.pending = true;
        layout.firedTriggers = 0;

        me.layoutQueue.add(layout);

        if (firstTime) {
            me.layouts[layout.id] = layout; 
            layout.running = true;

            if (layout.finishedLayout) {
                me.finishQueue.add(layout);
            }

            

            ++me.remainingLayouts;
            ++layout.layoutCount; 

            layout.ownerContext = ownerContext;
            layout.beginCount = 0; 
            layout.blockCount = 0; 
            layout.calcCount = 0; 
            layout.triggerCount = 0; 

            
            if (layout.isComponentLayout && (ownerCtContext = ownerContext.ownerCtContext)) {
                
                
                
                
                if (ownerContext.target.ownerLayout.isComponentLayout) {
                    ++ownerCtContext.remainingComponentChildLayouts;
                } else {
                    ++ownerCtContext.remainingContainerChildLayouts;
                }
                ++ownerCtContext.remainingChildLayouts;
            }

            if (!layout.initialized) {
                layout.initLayout();
            }

            layout.beginLayout(ownerContext);
        } else {
            ++layout.beginCount;

            if (!layout.running) {
                
                ++me.remainingLayouts;
                layout.running = true;

                if (layout.isComponentLayout) {
                    
                    
                    
                    ownerContext.unsetProp('done');

                    
                    
                    
                    ownerCtContext = ownerContext.ownerCtContext;
                    if (ownerCtContext) {
                        if (ownerContext.target.ownerLayout.isComponentLayout) {
                            if (++ownerCtContext.remainingComponentChildLayouts == 1) {
                                ownerCtContext.unsetProp('componentChildrenDone');
                            }
                        } else {
                            if (++ownerCtContext.remainingContainerChildLayouts == 1) {
                                ownerCtContext.unsetProp('containerChildrenDone');
                            }
                        }
                        if (++ownerCtContext.remainingChildLayouts == 1) {
                            ownerCtContext.unsetProp('childrenDone');
                        }
                    }
                }

                
                me.completionQueue.remove(layout);
                me.finalizeQueue.remove(layout);
            }
        }

        layout.beginLayoutCycle(ownerContext, firstTime);
    },

    
    run: function () {
        var me = this,
            flushed = false,
            watchDog = 100;

        me.flushInvalidates();

        me.state = 1;
        me.totalCount = me.layoutQueue.getCount();

        
        
        
        
        
        
        me.flush();

        
        while ((me.remainingLayouts || me.invalidQueue.length) && watchDog--) {
            if (me.invalidQueue.length) {
                me.flushInvalidates();
            }

            
            if (me.runCycle()) {
                flushed = false; 
                
            } else if (!flushed) {
                
                
                me.flush();
                flushed = true; 

                me.flushLayouts('completionQueue', 'completeLayout');
            } else {
                
                me.state = 2;
                break;
            }

            if (!(me.remainingLayouts || me.invalidQueue.length)) {
                me.flush();
                me.flushLayouts('completionQueue', 'completeLayout');
                me.flushLayouts('finalizeQueue', 'finalizeLayout');
            }
        }

        return me.runComplete();
    },

    runComplete: function () {
        var me = this;

        me.state = 2;

        if (me.remainingLayouts) {
            me.handleFailure();
            return false;
        }

        me.flush();

        
        me.flushLayouts('finishQueue', 'finishedLayout', true);

        
        me.flushLayouts('finishQueue', 'notifyOwner');

        me.flush(); 

        me.flushAnimations();

        return true;
    },

    
    runCycle: function () {
        var me = this,
            layouts = me.layoutQueue.clear(),
            length = layouts.length,
            i;

        ++me.cycleCount;

        
        
        me.progressCount = 0;

        for (i = 0; i < length; ++i) {
            me.runLayout(me.currentLayout = layouts[i]);
        }

        me.currentLayout = null;

        return me.progressCount > 0;
    },

    
    runLayout: function (layout) {
        var me = this,
            ownerContext = me.getCmp(layout.owner);

        layout.pending = false;

        if (ownerContext.state.blocks) {
            return;
        }

        
        
        
        
        layout.done = true;

        ++layout.calcCount;
        ++me.calcCount;

        layout.calculate(ownerContext);

        if (layout.done) {
            me.layoutDone(layout);

            if (layout.completeLayout) {
                me.queueCompletion(layout);
            }
            if (layout.finalizeLayout) {
                me.queueFinalize(layout);
            }
        } else if (!layout.pending && !layout.invalid && !(layout.blockCount + layout.triggerCount - layout.firedTriggers)) {
            
            
            me.queueLayout(layout);
        }
    },

    
    setItemSize: function(item, width, height) {
        var items = item,
            len = 1,
            contextItem, i;

        
        
        
        
        

        if (item.isComposite) {
            items = item.elements;
            len = items.length;
            item = items[0];
        } else if (!item.dom && !item.el) { 
            len = items.length;
            item = items[0];
        }
        

        for (i = 0; i < len; ) {
            contextItem = this.get(item);
            contextItem.setSize(width, height);

            item = items[++i]; 
        }
    }
});


Ext.define('Ext.selection.Model', {
    extend: 'Ext.util.Observable',
    alternateClassName: 'Ext.AbstractSelectionModel',
    requires: ['Ext.data.StoreManager'],
    mixins: {
        bindable: 'Ext.util.Bindable'    
    },
    

    

    
    allowDeselect: false,

    
    selected: null,

    
    pruneRemoved: true,

    constructor: function(cfg) {
        var me = this;

        cfg = cfg || {};
        Ext.apply(me, cfg);

        me.addEvents(
            
            'selectionchange',
            
            'focuschange'
        );

        me.modes = {
            SINGLE: true,
            SIMPLE: true,
            MULTI: true
        };

        
        me.setSelectionMode(cfg.mode || me.mode);

        
        me.selected = new Ext.util.MixedCollection();

        me.callParent(arguments);
    },

    
    bindStore: function(store, initial){
        var me = this;
        me.mixins.bindable.bindStore.apply(me, arguments);
        if(me.store && !initial) {
            me.refresh();
        }
    },
    
    getStoreListeners: function() {
        var me = this;
        return {
            add: me.onStoreAdd,
            clear: me.onStoreClear,
            remove: me.onStoreRemove,
            update: me.onStoreUpdate    
        }; 
    },

    
    selectAll: function(suppressEvent) {
        var me = this,
            selections = me.store.getRange(),
            i = 0,
            len = selections.length,
            start = me.getSelection().length;

        me.bulkChange = true;
        for (; i < len; i++) {
            me.doSelect(selections[i], true, suppressEvent);
        }
        delete me.bulkChange;
        
        me.maybeFireSelectionChange(me.getSelection().length !== start);
    },

    
    deselectAll: function(suppressEvent) {
        var me = this,
            selections = me.getSelection(),
            i = 0,
            len = selections.length,
            start = me.getSelection().length;

        me.bulkChange = true;
        for (; i < len; i++) {
            me.doDeselect(selections[i], suppressEvent);
        }
        delete me.bulkChange;
        
        me.maybeFireSelectionChange(me.getSelection().length !== start);
    },

    
    
    
    selectWithEvent: function(record, e, keepExisting) {
        var me = this;

        switch (me.selectionMode) {
            case 'MULTI':
                if (e.ctrlKey && me.isSelected(record)) {
                    me.doDeselect(record, false);
                } else if (e.shiftKey && me.lastFocused) {
                    me.selectRange(me.lastFocused, record, e.ctrlKey);
                } else if (e.ctrlKey) {
                    me.doSelect(record, true, false);
                } else if (me.isSelected(record) && !e.shiftKey && !e.ctrlKey && me.selected.getCount() > 1) {
                    me.doSelect(record, keepExisting, false);
                } else {
                    me.doSelect(record, false);
                }
                break;
            case 'SIMPLE':
                if (me.isSelected(record)) {
                    me.doDeselect(record);
                } else {
                    me.doSelect(record, true);
                }
                break;
            case 'SINGLE':
                
                if (me.allowDeselect && me.isSelected(record)) {
                    me.doDeselect(record);
                
                } else {
                    me.doSelect(record, false);
                }
                break;
        }
    },

    
    selectRange : function(startRow, endRow, keepExisting, dir){
        var me = this,
            store = me.store,
            selectedCount = 0,
            i,
            tmp,
            dontDeselect,
            records = [];

        if (me.isLocked()){
            return;
        }

        if (!keepExisting) {
            me.deselectAll(true);
        }

        if (!Ext.isNumber(startRow)) {
            startRow = store.indexOf(startRow);
        }
        if (!Ext.isNumber(endRow)) {
            endRow = store.indexOf(endRow);
        }

        
        if (startRow > endRow){
            tmp = endRow;
            endRow = startRow;
            startRow = tmp;
        }

        for (i = startRow; i <= endRow; i++) {
            if (me.isSelected(store.getAt(i))) {
                selectedCount++;
            }
        }

        if (!dir) {
            dontDeselect = -1;
        } else {
            dontDeselect = (dir == 'up') ? startRow : endRow;
        }

        for (i = startRow; i <= endRow; i++){
            if (selectedCount == (endRow - startRow + 1)) {
                if (i != dontDeselect) {
                    me.doDeselect(i, true);
                }
            } else {
                records.push(store.getAt(i));
            }
        }
        me.doMultiSelect(records, true);
    },

    
    select: function(records, keepExisting, suppressEvent) {
        
        if (Ext.isDefined(records)) {
            this.doSelect(records, keepExisting, suppressEvent);
        }
    },

    
    deselect: function(records, suppressEvent) {
        this.doDeselect(records, suppressEvent);
    },

    doSelect: function(records, keepExisting, suppressEvent) {
        var me = this,
            record;

        if (me.locked || !me.store) {
            return;
        }
        if (typeof records === "number") {
            records = [me.store.getAt(records)];
        }
        if (me.selectionMode == "SINGLE" && records) {
            record = records.length ? records[0] : records;
            me.doSingleSelect(record, suppressEvent);
        } else {
            me.doMultiSelect(records, keepExisting, suppressEvent);
        }
    },

    doMultiSelect: function(records, keepExisting, suppressEvent) {
        var me = this,
            selected = me.selected,
            change = false,
            i = 0,
            len, record;

        if (me.locked) {
            return;
        }


        records = !Ext.isArray(records) ? [records] : records;
        len = records.length;
        if (!keepExisting && selected.getCount() > 0) {
            if (me.doDeselect(me.getSelection(), suppressEvent) === false) {
                return;
            }
            
        }

        function commit () {
            selected.add(record);
            change = true;
        }

        for (; i < len; i++) {
            record = records[i];
            if (keepExisting && me.isSelected(record)) {
                continue;
            }
            me.lastSelected = record;

            me.onSelectChange(record, true, suppressEvent, commit);
        }
        if (!me.preventFocus) {
            me.setLastFocused(record, suppressEvent);
        }
        
        me.maybeFireSelectionChange(change && !suppressEvent);
    },

    
    doDeselect: function(records, suppressEvent) {
        var me = this,
            selected = me.selected,
            i = 0,
            len, record,
            attempted = 0,
            accepted = 0;

        if (me.locked || !me.store) {
            return false;
        }

        if (typeof records === "number") {
            records = [me.store.getAt(records)];
        } else if (!Ext.isArray(records)) {
            records = [records];
        }

        function commit () {
            ++accepted;
            selected.remove(record);
        }

        len = records.length;

        for (; i < len; i++) {
            record = records[i];
            if (me.isSelected(record)) {
                if (me.lastSelected == record) {
                    me.lastSelected = selected.last();
                }
                ++attempted;
                me.onSelectChange(record, false, suppressEvent, commit);
            }
        }

        
        me.maybeFireSelectionChange(accepted > 0 && !suppressEvent);
        return accepted === attempted;
    },

    doSingleSelect: function(record, suppressEvent) {
        var me = this,
            changed = false,
            selected = me.selected;

        if (me.locked) {
            return;
        }
        
        
        if (me.isSelected(record)) {
            return;
        }

        function commit () {
            me.bulkChange = true;
            if (selected.getCount() > 0 && me.doDeselect(me.lastSelected, suppressEvent) === false) {
                delete me.bulkChange;
                return false;
            }
            delete me.bulkChange;

            selected.add(record);
            me.lastSelected = record;
            changed = true;
        }

        me.onSelectChange(record, true, suppressEvent, commit);

        if (changed) {
            if (!suppressEvent) {
                me.setLastFocused(record);
            }
            me.maybeFireSelectionChange(!suppressEvent);
        }
    },

    
    setLastFocused: function(record, supressFocus) {
        var me = this,
            recordBeforeLast = me.lastFocused;

        me.lastFocused = record;
         
        
        if (record !== recordBeforeLast) {
            me.onLastFocusChanged(recordBeforeLast, record, supressFocus);
        }
    },

    
    isFocused: function(record) {
        return record === this.getLastFocused();
    },


    
    
    maybeFireSelectionChange: function(fireEvent) {
        var me = this;
        if (fireEvent && !me.bulkChange) {
            me.fireEvent('selectionchange', me, me.getSelection());
        }
    },

    
    getLastSelected: function() {
        return this.lastSelected;
    },

    getLastFocused: function() {
        return this.lastFocused;
    },

    
    getSelection: function() {
        return this.selected.getRange();
    },

    
    getSelectionMode: function() {
        return this.selectionMode;
    },

    
    setSelectionMode: function(selMode) {
        selMode = selMode ? selMode.toUpperCase() : 'SINGLE';
        
        
        this.selectionMode = this.modes[selMode] ? selMode : 'SINGLE';
    },

    
    isLocked: function() {
        return this.locked;
    },

    
    setLocked: function(locked) {
        this.locked = !!locked;
    },

    
    isSelected: function(record) {
        record = Ext.isNumber(record) ? this.store.getAt(record) : record;
        return this.selected.indexOf(record) !== -1;
    },

    
    hasSelection: function() {
        return this.selected.getCount() > 0;
    },

    refresh: function() {
        var me = this,
            store = me.store,
            toBeSelected = [],
            oldSelections = me.getSelection(),
            len = oldSelections.length,
            selection,
            change,
            i = 0,
            lastFocused = me.getLastFocused();

        
        if (!store) {
            return;
        }

        
        
        
        for (; i < len; i++) {
            selection = oldSelections[i];
            if (!me.pruneRemoved || store.indexOf(selection) !== -1) {
                toBeSelected.push(selection);
            }
        }

        
        
        if (me.selected.getCount() != toBeSelected.length) {
            change = true;
        }

        me.clearSelections();

        if (store.indexOf(lastFocused) !== -1) {
            
            me.setLastFocused(lastFocused, true);
        }

        if (toBeSelected.length) {
            
            me.doSelect(toBeSelected, false, true);
        }

        me.maybeFireSelectionChange(change);
    },

    
    clearSelections: function() {
        
        this.selected.clear();
        this.lastSelected = null;
        this.setLastFocused(null);
    },

    
    onStoreAdd: Ext.emptyFn,

    
    
    onStoreClear: function() {
        if (this.selected.getCount > 0) {
            this.clearSelections();
            this.maybeFireSelectionChange(true);
        }
    },

    
    
    
    onStoreRemove: function(store, record, index) {
        var me = this,
            selected = me.selected;

        if (me.locked || !me.pruneRemoved) {
            return;
        }

        if (selected.remove(record)) {
            if (me.lastSelected == record) {
                me.lastSelected = null;
            }
            if (me.getLastFocused() == record) {
                me.setLastFocused(null);
            }
            me.maybeFireSelectionChange(true);
        }
    },

    
    getCount: function() {
        return this.selected.getCount();
    },

    
    destroy: Ext.emptyFn,

    
    onStoreUpdate: Ext.emptyFn,

    
    onStoreLoad: Ext.emptyFn,

    
    onSelectChange: Ext.emptyFn,

    
    onLastFocusChanged: function(oldFocused, newFocused) {
        this.fireEvent('focuschange', this, oldFocused, newFocused);
    },

    
    onEditorKey: Ext.emptyFn,

    
    bindComponent: Ext.emptyFn,

    
    beforeViewRender: Ext.emptyFn

});


Ext.define('Ext.selection.DataViewModel', {
    extend: 'Ext.selection.Model',

    requires: ['Ext.util.KeyNav'],

    deselectOnContainerClick: true,

    
    enableKeyNav: true,

    constructor: function(cfg){
        this.addEvents(
            
            'beforedeselect',

            
            'beforeselect',

            
            'deselect',

            
            'select'
        );
        this.callParent(arguments);
    },

    bindComponent: function(view) {
        var me = this,
            eventListeners = {
                refresh: me.refresh,
                scope: me
            };

        me.view = view;
        me.bindStore(view.getStore());

        eventListeners[view.triggerEvent] = me.onItemClick;
        eventListeners[view.triggerCtEvent] = me.onContainerClick;

        view.on(eventListeners);

        if (me.enableKeyNav) {
            me.initKeyNav(view);
        }
    },

    onItemClick: function(view, record, item, index, e) {
        this.selectWithEvent(record, e);
    },

    onContainerClick: function() {
        if (this.deselectOnContainerClick) {
            this.deselectAll();
        }
    },

    initKeyNav: function(view) {
        var me = this;

        if (!view.rendered) {
            view.on({
                render: Ext.Function.bind(me.initKeyNav, me, [view]),
                single: true
            });
            return;
        }

        view.el.set({
            tabIndex: -1
        });
        me.keyNav = new Ext.util.KeyNav({
            target: view.el,
            ignoreInputFields: true,
            down: Ext.pass(me.onNavKey, [1], me),
            right: Ext.pass(me.onNavKey, [1], me),
            left: Ext.pass(me.onNavKey, [-1], me),
            up: Ext.pass(me.onNavKey, [-1], me),
            scope: me
        });
    },

    onNavKey: function(step) {
        step = step || 1;
        var me = this,
            view = me.view,
            selected = me.getSelection()[0],
            numRecords = me.view.store.getCount(),
            idx;

        if (selected) {
            idx = view.indexOf(view.getNode(selected)) + step;
        } else {
            idx = 0;
        }

        if (idx < 0) {
            idx = numRecords - 1;
        } else if (idx >= numRecords) {
            idx = 0;
        }

        me.select(idx);
    },

    
    onSelectChange: function(record, isSelected, suppressEvent, commitFn) {
        var me = this,
            view = me.view,
            eventName = isSelected ? 'select' : 'deselect';

        if ((suppressEvent || me.fireEvent('before' + eventName, me, record)) !== false &&
                commitFn() !== false) {

            if (view) {
                if (isSelected) {
                    view.onItemSelect(record);
                } else {
                    view.onItemDeselect(record);
                }
            }

            if (!suppressEvent) {
                me.fireEvent(eventName, me, record);
            }
        }
    },
    
    destroy: function(){
        Ext.destroy(this.keyNav);
        this.callParent();
    }
});


Ext.define('Ext.Component', {

    

    alias: ['widget.component', 'widget.box'],

    extend: 'Ext.AbstractComponent',

    requires: [
        'Ext.util.DelayedTask'
    ],

    uses: [
        'Ext.Layer',
        'Ext.resizer.Resizer',
        'Ext.util.ComponentDragger'
    ],

    mixins: {
        floating: 'Ext.util.Floating'
    },

    statics: {
        
        DIRECTION_TOP: 'top',
        DIRECTION_RIGHT: 'right',
        DIRECTION_BOTTOM: 'bottom',
        DIRECTION_LEFT: 'left',

        VERTICAL_DIRECTION_Re: /^(?:top|bottom)$/,

        
        
        INVALID_ID_CHARS_Re: /[\.,\s]/g
    },

    

    

    
    resizeHandles: 'all',

    

    

    

    
    floating: false,

    
    toFrontOnShow: true,

    

    

    

    
    
    

    

    

    hideMode: 'display',

    bubbleEvents: [],

    monPropRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,

    
    
    
    
    
    

    
    constructor: function(config) {
        var me = this;

        config = config || {};
        if (config.initialConfig) {

            
            if (config.isAction) {
                me.baseAction = config;
            }
            config = config.initialConfig;
            
        }
        else if (config.tagName || config.dom || Ext.isString(config)) {
            
            config = {
                applyTo: config,
                id: config.id || config
            };
        }

        me.callParent([config]);

        
        
        if (me.baseAction){
            me.baseAction.addComponent(me);
        }
    },

    
    initComponent: function() {
        var me = this;

        me.callParent();

        if (me.listeners) {
            me.on(me.listeners);
            me.listeners = null; 
        }
        me.enableBubble(me.bubbleEvents);
        me.mons = [];
    },


    
    afterRender: function() {
        var me = this;

        me.callParent();

        if (!(me.x && me.y) && (me.pageX || me.pageY)) {
            me.setPagePosition(me.pageX, me.pageY);
        }
    },

    
    setAutoScroll : function(scroll) {
        var me = this;

        me.autoScroll = !!scroll;

        
        
        
        if (me.rendered) {
            me.getTargetEl().setStyle(me.getOverflowStyle());
        }
        me.updateLayout();
        return me;
    },

    
    setOverflowXY: function(overflowX, overflowY) {
        var me = this,
            argCount = arguments.length;

        if (argCount) {
            me.overflowX = overflowX || '';
            if (argCount > 1) {
                me.overflowY = overflowY || '';
            }
        }

        
        
        
        if (me.rendered) {
            me.getTargetEl().setStyle(me.getOverflowStyle());
        }
        me.updateLayout();
        return me;
    },

    beforeRender: function () {
        var me = this,
            floating = me.floating,
            cls;

        if (floating) {
            me.addCls(Ext.baseCSSPrefix + 'layer');

            cls = floating.cls;
            if (cls) {
                me.addCls(cls);
            }
        }

        return me.callParent();
    },
    
    afterComponentLayout: function(){
        this.callParent(arguments);
        if (this.floating) {
            this.onAfterFloatLayout();
        }
    },

    
    makeFloating : function (dom) {
        this.mixins.floating.constructor.call(this, dom);
    },

    wrapPrimaryEl: function (dom) {
        if (this.floating) {
            this.makeFloating(dom);
        } else {
            this.callParent(arguments);
        }
    },

    initResizable: function(resizable) {
        var me = this;

        resizable = Ext.apply({
            target: me,
            dynamic: false,
            constrainTo: me.constrainTo || (me.floatParent ? me.floatParent.getTargetEl() : null),
            handles: me.resizeHandles
        }, resizable);
        resizable.target = me;
        me.resizer = new Ext.resizer.Resizer(resizable);
    },

    getDragEl: function() {
        return this.el;
    },

    initDraggable: function() {
        var me = this,

            
            
            
            dragTarget = (me.resizer && me.resizer.el !== me.el) ? me.resizerComponent = new Ext.Component({
                el: me.resizer.el,
                rendered: true,
                container: me.container
            }) : me,
            ddConfig = Ext.applyIf({
                el: dragTarget.getDragEl(),
                constrainTo: me.constrain ? (me.constrainTo || (me.floatParent ? me.floatParent.getTargetEl() : me.el.getScopeParent())) : undefined
            }, me.draggable);

        
        if (me.constrain || me.constrainDelegate) {
            ddConfig.constrain = me.constrain;
            ddConfig.constrainDelegate = me.constrainDelegate;
        }

        me.dd = new Ext.util.ComponentDragger(dragTarget, ddConfig);
    },

    
    scrollBy: function(deltaX, deltaY, animate) {
        var el;

        if ((el = this.getTargetEl()) && el.dom) {
            el.scrollBy.apply(el, arguments);
        }
    },

    
    setLoading : function(load, targetEl) {
        var me = this,
            config;

        if (me.rendered) {
            Ext.destroy(me.loadMask);
            me.loadMask = null;

            if (load !== false && !me.collapsed) {
                if (Ext.isObject(load)) {
                    config = Ext.apply({}, load);
                } else if (Ext.isString(load)) {
                    config = {msg: load};
                } else {
                    config = {};
                }
                if (targetEl) {
                    Ext.applyIf(config, {
                        useTargetEl: true
                    });
                }
                me.loadMask = new Ext.LoadMask(me, config);
                me.loadMask.show();
            }
        }
        return me.loadMask;
    },

    beforeSetPosition: function () {
        var me = this,
            pos = me.callParent(arguments), 
            adj;

        if (pos) {
            adj = me.adjustPosition(pos.x, pos.y);
            pos.x = adj.x;
            pos.y = adj.y;
        }
        return pos || null;
    },

    afterSetPosition: function(ax, ay) {
        this.onPosition(ax, ay);
        this.fireEvent('move', this, ax, ay);
    },

    
    showAt: function(x, y, animate) {
        var me = this;

        if (!me.rendered && (me.autoRender || me.floating)) {
            me.doAutoRender();
            
            me.hidden = true;
        }
        if (me.floating) {
            me.setPosition(x, y, animate);
        } else {
            me.setPagePosition(x, y, animate);
        }
        me.show();
    },

    
    setPagePosition: function(x, y, animate) {
        var me = this,
            p,
            floatParentBox;

        if (Ext.isArray(x)) {
            y = x[1];
            x = x[0];
        }
        me.pageX = x;
        me.pageY = y;

        if (me.floating) {

            
            if (me.isContainedFloater()) {
                floatParentBox = me.floatParent.getTargetEl().getViewRegion();
                if (Ext.isNumber(x) && Ext.isNumber(floatParentBox.left)) {
                    x -= floatParentBox.left;
                }
                if (Ext.isNumber(y) && Ext.isNumber(floatParentBox.top)) {
                    y -= floatParentBox.top;
                }
            } else {
                p = me.el.translatePoints(x, y);
                x = p.left;
                y = p.top;
            }

            me.setPosition(x, y, animate);
        } else {
            p = me.el.translatePoints(x, y);
            me.setPosition(p.left, p.top, animate);
        }

        return me;
    },

    
    
    isContainedFloater: function() {
        return (this.floating && this.floatParent);
    },

    
    getBox : function(local){
        var pos = local ? this.getPosition(local) : this.el.getXY(),
            size = this.getSize();

        size.x = pos[0];
        size.y = pos[1];
        return size;
    },

    
    updateBox : function(box){
        this.setSize(box.width, box.height);
        this.setPagePosition(box.x, box.y);
        return this;
    },

    
    getOuterSize: function() {
        var el = this.el;
        return {
            width: el.getWidth() + el.getMargin('lr'),
            height: el.getHeight() + el.getMargin('tb')
        };
    },

    
    adjustPosition: function(x, y) {
        var me = this,
            floatParentBox;

        
        if (me.isContainedFloater()) {
            floatParentBox = me.floatParent.getTargetEl().getViewRegion();
            x += floatParentBox.left;
            y += floatParentBox.top;
        }

        return {
            x: x,
            y: y
        };
    },

    
    getPosition: function(local) {
        var me = this,
            el = me.el,
            xy,
            isContainedFloater = me.isContainedFloater(),
            floatParentBox;

        
        if ((local === true) && !isContainedFloater) {
            return [el.getLocalX(), el.getLocalY()];
        }

        xy = me.el.getXY();

        
        if ((local === true) && isContainedFloater) {
            floatParentBox = me.floatParent.getTargetEl().getViewRegion();
            xy[0] -= floatParentBox.left;
            xy[1] -= floatParentBox.top;
        }
        return xy;
    },

    getId: function() {
        var me = this,
            xtype;

        if (!me.id) {
            xtype = me.getXType();
            if (xtype) {
                xtype = xtype.replace(Ext.Component.INVALID_ID_CHARS_Re, '-');
            } else {
                xtype = Ext.name.toLowerCase() + '-comp';
            }
            me.id = xtype + '-' + me.getAutoId();
        }
        return me.id;
    },

    
    show: function(animateTarget, cb, scope) {
        var me = this,
            rendered = me.rendered;

        if (rendered && me.isVisible()) {
            if (me.toFrontOnShow && me.floating) {
                me.toFront();
            }
        } else {
            if (me.fireEvent('beforeshow', me) !== false) {
                
                me.hidden = false;
                if (!rendered && (me.autoRender || me.floating)) {
                    me.doAutoRender();
                    rendered = me.rendered;
                }
            
                if (rendered) {
                    me.beforeShow();
                    me.onShow.apply(me, arguments);
                    me.afterShow.apply(me, arguments);
                }
            } else {
                me.onShowVeto();
            }
        }
        return me;
    },
    
    onShowVeto: Ext.emptyFn,

    
    beforeShow: Ext.emptyFn,

    
    onShow: function() {
        var me = this;

        me.el.show();
        me.callParent(arguments);

        
        if (me.floating) {
            if (me.maximized) {
                me.fitContainer();
            }
            else if (me.constrain) {
                me.doConstrain();
            }
        }
    },

    
    afterShow: function(animateTarget, cb, scope) {
        var me = this,
            fromBox,
            toBox,
            ghostPanel;

        
        animateTarget = animateTarget || me.animateTarget;

        
        if (!me.ghost) {
            animateTarget = null;
        }
        
        if (animateTarget) {
            animateTarget = animateTarget.el ? animateTarget.el : Ext.get(animateTarget);
            toBox = me.el.getBox();
            fromBox = animateTarget.getBox();
            me.el.addCls(Ext.baseCSSPrefix + 'hide-offsets');
            ghostPanel = me.ghost();
            ghostPanel.el.stopAnimation();

            
            ghostPanel.el.setX(-10000);

            ghostPanel.el.animate({
                from: fromBox,
                to: toBox,
                listeners: {
                    afteranimate: function() {
                        delete ghostPanel.componentLayout.lastComponentSize;
                        me.unghost();
                        me.el.removeCls(Ext.baseCSSPrefix + 'hide-offsets');
                        me.onShowComplete(cb, scope);
                    }
                }
            });
        }
        else {
            me.onShowComplete(cb, scope);
        }
    },

    
    onShowComplete: function(cb, scope) {
        var me = this;
        if (me.floating) {
            me.toFront();
            me.onFloatShow();
        }
        Ext.callback(cb, scope || me);
        me.fireEvent('show', me);
        delete me.hiddenByLayout;
    },

    
    hide: function() {
        var me = this;

        
        
        me.showOnParentShow = false;

        if (!(me.rendered && !me.isVisible()) && me.fireEvent('beforehide', me) !== false) {
            me.hidden = true;
            if (me.rendered) {
                me.onHide.apply(me, arguments);
            }
        }
        return me;
    },

    
    onHide: function(animateTarget, cb, scope) {
        var me = this,
            ghostPanel,
            toBox;

        
        animateTarget = animateTarget || me.animateTarget;

        
        if (!me.ghost) {
            animateTarget = null;
        }
        
        if (animateTarget) {
            animateTarget = animateTarget.el ? animateTarget.el : Ext.get(animateTarget);
            ghostPanel = me.ghost();
            ghostPanel.el.stopAnimation();
            toBox = animateTarget.getBox();
            toBox.width += 'px';
            toBox.height += 'px';
            ghostPanel.el.animate({
                to: toBox,
                listeners: {
                    afteranimate: function() {
                        delete ghostPanel.componentLayout.lastComponentSize;
                        ghostPanel.el.hide();
                        me.afterHide(cb, scope);
                    }
                }
            });
        }
        me.el.hide();
        if (!animateTarget) {
            me.afterHide(cb, scope);
        }
    },

    
    afterHide: function(cb, scope) {
        var me = this;
        delete me.hiddenByLayout;

        
        
        Ext.AbstractComponent.prototype.onHide.call(this);

        Ext.callback(cb, scope || me);
        me.fireEvent('hide', me);
    },

    
    onDestroy: function() {
        var me = this;

        
        if (me.rendered) {
            Ext.destroy(
                me.proxy,
                me.proxyWrap,
                me.resizer,
                me.resizerComponent
            );
        }
        delete me.focusTask;
        me.callParent();
    },

    deleteMembers: function() {
        var args = arguments,
            len = args.length,
            i = 0;
        for (; i < len; ++i) {
            delete this[args[i]];
        }
    },

    
    focus: function(selectText, delay) {
        var me = this,
            focusEl,
            focusElDom,
            containerScrollTop;

        
        if (delay) {
            if (!me.focusTask) {
                me.focusTask = new Ext.util.DelayedTask(me.focus);
            }
            me.focusTask.delay(Ext.isNumber(delay) ? delay : 10, null, me, [selectText, false]);
            return me;
        }

        if (me.rendered && !me.isDestroyed && me.isVisible(true) && (focusEl = me.getFocusEl())) {

            
            
            if (focusEl.isComponent) {
                return focusEl.focus(selectText, delay);
            }

            
            if ((focusElDom = focusEl.dom)) {

                
                if (focusEl.needsTabIndex()) {
                    focusElDom.tabIndex = -1;
                }

                if (me.floating) {
                    containerScrollTop = me.container.dom.scrollTop;
                }

                
                
                
                focusEl.focus();
                if (selectText === true) {
                    focusElDom.select();
                }
            }

            
            
            if (me.floating) {
                me.toFront(true);
                if (containerScrollTop !== undefined) {
                    me.container.dom.scrollTop = containerScrollTop;
                }
            }
        }
        return me;
    },

    
    cancelFocus: function() {
        var task = this.focusTask;
        if (task) {
            task.cancel();
        }
    },

    
    blur: function() {
        var focusEl;
        if (this.rendered && (focusEl = this.getFocusEl())) {
            focusEl.blur();
        }
        return this;
    },

    getEl: function() {
        return this.el;
    },

    
    getResizeEl: function() {
        return this.el;
    },

    
    getPositionEl: function() {
        return this.el;
    },

    
    getActionEl: function() {
        return this.el;
    },

    
    getVisibilityEl: function() {
        return this.el;
    },

    
    onResize: Ext.emptyFn,

    
    
    
    
    
    getBubbleTarget: function() {
        return this.ownerCt || this.floatParent;
    },

    
    getContentTarget: function() {
        return this.el;
    },

    
    cloneConfig: function(overrides) {
        overrides = overrides || {};
        var id = overrides.id || Ext.id(),
            cfg = Ext.applyIf(overrides, this.initialConfig),
            self;

        cfg.id = id;

        self = Ext.getClass(this);

        
        return new self(cfg);
    },

    
    getXType: function() {
        return this.self.xtype;
    },

    
    findParentBy: function(fn) {
        var p;

        
        for (p = this.getBubbleTarget(); p && !fn(p, this); p = p.getBubbleTarget()) {
            
        }
        return p || null;
    },

    
    findParentByType: function(xtype) {
        return Ext.isFunction(xtype) ?
            this.findParentBy(function(p) {
                return p.constructor === xtype;
            })
        :
            this.up(xtype);
    },

    
    bubble: function(fn, scope, args) {
        var p = this;
        while (p) {
            if (fn.apply(scope || p, args || [p]) === false) {
                break;
            }
            p = p.getBubbleTarget();
        }
        return this;
    },

    getProxy: function() {
        var me = this,
            target;

        if (!me.proxy) {
            target = Ext.getBody();
            if (Ext.scopeResetCSS) {
                me.proxyWrap = target = Ext.getBody().createChild({
                    cls: Ext.resetCls
                });
            }
            me.proxy = me.el.createProxy(Ext.baseCSSPrefix + 'proxy-el', target, true);
        }
        return me.proxy;
    }
});


Ext.define('Ext.app.EventBus', {
    requires: [
        'Ext.util.Event',
        'Ext.Component'
    ],
    mixins: {
        observable: 'Ext.util.Observable'
    },

    constructor: function() {
        this.mixins.observable.constructor.call(this);

        this.bus = {};

        var me = this;
        Ext.override(Ext.Component, {
            fireEvent: function(ev) {
                if (Ext.util.Observable.prototype.fireEvent.apply(this, arguments) !== false) {
                    return me.dispatch.call(me, ev, this, arguments);
                }
                return false;
            }
        });
    },

    dispatch: function(ev, target, args) {
        var bus = this.bus,
            selectors = bus[ev],
            selector, controllers, id, events, event, i, ln;

        if (selectors) {
            
            for (selector in selectors) {
                
                if (selectors.hasOwnProperty(selector) && target.is(selector)) {
                    
                    controllers = selectors[selector];
                    for (id in controllers) {
                        if (controllers.hasOwnProperty(id)) {
                            
                            events = controllers[id];
                            for (i = 0, ln = events.length; i < ln; i++) {
                                event = events[i];
                                
                                if (event.fire.apply(event, Array.prototype.slice.call(args, 1)) === false) {
                                    return false;
                                }
                            }
                        }
                    }
                }
            }
        }
        return true;
    },

    control: function(selectors, listeners, controller) {
        var bus = this.bus,
            hasListeners, tree, list,
            selector, options, listener, scope, event, listenerList, ev;

        if (Ext.isString(selectors)) {
            selector = selectors;
            selectors = {};
            selectors[selector] = listeners;
            this.control(selectors, null, controller);
            return;
        }

        hasListeners = Ext.util.Observable.HasListeners.prototype;
        for (selector in selectors) {
            if (selectors.hasOwnProperty(selector)) {
                listenerList = selectors[selector] || {};

                for (ev in listenerList) {
                    if (listenerList.hasOwnProperty(ev)) {
                        options  = {};
                        listener = listenerList[ev];
                        scope    = controller;
                        event    = new Ext.util.Event(controller, ev);

                        
                        if (Ext.isObject(listener)) {
                            options  = listener;
                            listener = options.fn;
                            scope    = options.scope || controller;

                            delete options.fn;
                            delete options.scope;
                        }

                        event.addListener(listener, scope, options);

                        hasListeners[ev] = 1;

                        
                        tree = bus[ev] || (bus[ev] = {});
                        tree = tree[selector] || (tree[selector] = {});
                        list = tree[controller.id] || (tree[controller.id] = []);

                        
                        list.push(event);
                    }
                } 
            }
        } 
    }
});


Ext.define('Ext.chart.MaskLayer', {
    extend: 'Ext.Component',
    
    constructor: function(config) {
        config = Ext.apply(config || {}, {
            style: 'position:absolute;background-color:#888;cursor:move;opacity:0.6;border:1px solid #222;'
        });
        this.callParent([config]);    
    },
    
    initComponent: function() {
        var me = this;
        me.callParent(arguments);
        me.addEvents(
            'mousedown',
            'mouseup',
            'mousemove',
            'mouseenter',
            'mouseleave'
        );
    },

    initDraggable: function() {
        this.callParent(arguments);
        this.dd.onStart = function (e) {
            var me = this,
                comp = me.comp;
    
            
            this.startPosition = comp.getPosition(true);
    
            
            
            if (comp.ghost && !comp.liveDrag) {
                 me.proxy = comp.ghost();
                 me.dragTarget = me.proxy.header.el;
            }
    
            
            if (me.constrain || me.constrainDelegate) {
                me.constrainTo = me.calculateConstrainRegion();
            }
        };
    }
});

Ext.define('Ext.chart.Mask', {
    requires: [
        'Ext.chart.MaskLayer'
    ],
    
    

    
    constructor: function(config) {
        var me = this,
            resizeHandler;

        me.addEvents('select');

        if (config) {
            Ext.apply(me, config);
        }
        if (me.enableMask) {
            me.on('afterrender', function() {
                
                var comp = new Ext.chart.MaskLayer({
                    renderTo: me.el,
                    hidden: true
                });
                comp.el.on({
                    'mousemove': function(e) {
                        me.onMouseMove(e);
                    },
                    'mouseup': function(e) {
                        me.resized(e);
                    }
                });
                
                resizeHandler = new Ext.resizer.Resizer({
                    el: comp.el,
                    handles: 'all',
                    pinned: true
                });
                resizeHandler.on({
                    'resize': function(e) {
                        me.resized(e);    
                    }    
                });
                comp.initDraggable();
                me.maskType = me.mask;
                me.mask = comp;
                me.maskSprite = me.surface.add({
                    type: 'path',
                    path: ['M', 0, 0],
                    zIndex: 1001,
                    opacity: 0.7,
                    hidden: true,
                    stroke: '#444'
                });
            }, me, { single: true });
        }
    },
    
    resized: function(e) {
        var me = this,
            bbox = me.bbox || me.chartBBox,
            x = bbox.x,
            y = bbox.y,
            width = bbox.width,
            height = bbox.height,
            box = me.mask.getBox(true),
            max = Math.max,
            min = Math.min,
            staticX = box.x - x,
            staticY = box.y - y;
        
        staticX = max(staticX, x);
        staticY = max(staticY, y);
        staticX = min(staticX, width);
        staticY = min(staticY, height);
        box.x = staticX;
        box.y = staticY;
        me.fireEvent('select', me, box);
    },

    onMouseUp: function(e) {
        var me = this,
            bbox = me.bbox || me.chartBBox,
            sel = me.maskSelection;
        me.maskMouseDown = false;
        me.mouseDown = false;
        if (me.mouseMoved) {
            me.onMouseMove(e);
            me.mouseMoved = false;
            me.fireEvent('select', me, {
                x: sel.x - bbox.x,
                y: sel.y - bbox.y,
                width: sel.width,
                height: sel.height
            });
        }
    },

    onMouseDown: function(e) {
        var me = this;
        me.mouseDown = true;
        me.mouseMoved = false;
        me.maskMouseDown = {
            x: e.getPageX() - me.el.getX(),
            y: e.getPageY() - me.el.getY()
        };
    },

    onMouseMove: function(e) {
        var me = this,
            mask = me.maskType,
            bbox = me.bbox || me.chartBBox,
            x = bbox.x,
            y = bbox.y,
            math = Math,
            floor = math.floor,
            abs = math.abs,
            min = math.min,
            max = math.max,
            height = floor(y + bbox.height),
            width = floor(x + bbox.width),
            posX = e.getPageX(),
            posY = e.getPageY(),
            staticX = posX - me.el.getX(),
            staticY = posY - me.el.getY(),
            maskMouseDown = me.maskMouseDown,
            path;
        
        me.mouseMoved = me.mouseDown;
        staticX = max(staticX, x);
        staticY = max(staticY, y);
        staticX = min(staticX, width);
        staticY = min(staticY, height);
        if (maskMouseDown && me.mouseDown) {
            if (mask == 'horizontal') {
                staticY = y;
                maskMouseDown.y = height;
                posY = me.el.getY() + bbox.height + me.insetPadding;
            }
            else if (mask == 'vertical') {
                staticX = x;
                maskMouseDown.x = width;
            }
            width = maskMouseDown.x - staticX;
            height = maskMouseDown.y - staticY;
            path = ['M', staticX, staticY, 'l', width, 0, 0, height, -width, 0, 'z'];
            me.maskSelection = {
                x: width > 0 ? staticX : staticX + width,
                y: height > 0 ? staticY : staticY + height,
                width: abs(width),
                height: abs(height)
            };
            me.mask.updateBox(me.maskSelection);
            me.mask.show();
            me.maskSprite.setAttributes({
                hidden: true    
            }, true);
        }
        else {
            if (mask == 'horizontal') {
                path = ['M', staticX, y, 'L', staticX, height];
            }
            else if (mask == 'vertical') {
                path = ['M', x, staticY, 'L', width, staticY];
            }
            else {
                path = ['M', staticX, y, 'L', staticX, height, 'M', x, staticY, 'L', width, staticY];
            }
            me.maskSprite.setAttributes({
                path: path,
                fill: me.maskMouseDown ? me.maskSprite.stroke : false,
                'stroke-width': mask === true ? 1 : 3,
                hidden: false
            }, true);
        }
    },

    onMouseLeave: function(e) {
        var me = this;
        me.mouseMoved = false;
        me.mouseDown = false;
        me.maskMouseDown = false;
        me.mask.hide();
        me.maskSprite.hide(true);
    }
});
    


Ext.define('Ext.draw.Component', {

    

    alias: 'widget.draw',

    extend: 'Ext.Component',

    requires: [
        'Ext.draw.Surface',
        'Ext.layout.component.Draw'
    ],

    

    
    enginePriority: ['Svg', 'Vml'],

    baseCls: Ext.baseCSSPrefix + 'surface',

    componentLayout: 'draw',

    
    viewBox: true,

    shrinkWrap: 3,
    
    
    autoSize: false,

    

    

    

    initComponent: function() {
        this.callParent(arguments);

        this.addEvents(
            
            'mousedown',
            
            'mouseup',
            
            'mousemove',
            
            'mouseenter',
            
            'mouseleave',
            
            'click',
            
            'dblclick'
        );
    },

    
    onRender: function() {
        var me = this,
            viewBox = me.viewBox,
            autoSize = me.autoSize,
            bbox, items, width, height, x, y;
        me.callParent(arguments);

        if (me.createSurface() !== false) {
            items = me.surface.items;

            if (viewBox || autoSize) {
                bbox = items.getBBox();
                width = bbox.width;
                height = bbox.height;
                x = bbox.x;
                y = bbox.y;
                if (me.viewBox) {
                    me.surface.setViewBox(x, y, width, height);
                } else {
                    me.autoSizeSurface();
                }
            }
        }
    },

    
    autoSizeSurface: function() {
        var bbox = this.surface.items.getBBox();
        this.setSurfaceSize(bbox.width, bbox.height);
    },

    setSurfaceSize: function (width, height) {
        this.surface.setSize(width, height);
        if (this.autoSize) {
            var bbox = this.surface.items.getBBox();
            this.surface.setViewBox(bbox.x, bbox.y - (+Ext.isOpera), width, height);
        }
    },
    
    
    createSurface: function() {
        var me = this,
            cfg = Ext.applyIf({
                renderTo: me.el,
                height: me.height,
                width: me.width,
                items: me.items
            }, me.initialConfig), surface;

        
        delete cfg.listeners;
        surface = Ext.draw.Surface.create(cfg);
        if (!surface) {
            
            return false;
        }
        me.surface = surface;


        function refire(eventName) {
            return function(e) {
                me.fireEvent(eventName, e);
            };
        }

        surface.on({
            scope: me,
            mouseup: refire('mouseup'),
            mousedown: refire('mousedown'),
            mousemove: refire('mousemove'),
            mouseenter: refire('mouseenter'),
            mouseleave: refire('mouseleave'),
            click: refire('click'),
            dblclick: refire('dblclick')
        });
    },


    
    onDestroy: function() {
        Ext.destroy(this.surface);
        this.callParent(arguments);
    }

});


Ext.define('Ext.chart.Chart', {

    

    alias: 'widget.chart',

    extend: 'Ext.draw.Component',
    
    mixins: {
        themeManager: 'Ext.chart.theme.Theme',
        mask: 'Ext.chart.Mask',
        navigation: 'Ext.chart.Navigation',
        bindable: 'Ext.util.Bindable',
        observable: 'Ext.util.Observable'
    },

    uses: [
        'Ext.chart.series.Series'
    ],
    
    requires: [
        'Ext.util.MixedCollection',
        'Ext.data.StoreManager',
        'Ext.chart.Legend',
        'Ext.chart.theme.Base',
        'Ext.chart.theme.Theme',
        'Ext.util.DelayedTask'
    ],

    

    
    viewBox: false,

    

    
    animate: false,

    
    legend: false,

    
    insetPadding: 10,

    
    enginePriority: ['Svg', 'Vml'],

    
    background: false,

    

    

    

    

    constructor: function(config) {
        var me = this,
            defaultAnim;

        config = Ext.apply({}, config);
        me.initTheme(config.theme || me.theme);
        if (me.gradients) {
            Ext.apply(config, { gradients: me.gradients });
        }
        if (me.background) {
            Ext.apply(config, { background: me.background });
        }
        if (config.animate) {
            defaultAnim = {
                easing: 'ease',
                duration: 500
            };
            if (Ext.isObject(config.animate)) {
                config.animate = Ext.applyIf(config.animate, defaultAnim);
            }
            else {
                config.animate = defaultAnim;
            }
        }

        me.mixins.observable.constructor.call(me, config);
        if (config.enableMask) {
            me.mixins.mask.constructor.call(me);
        }
        me.mixins.navigation.constructor.call(me);
        me.callParent([config]);
    },
    
    getChartStore: function(){
        return this.substore || this.store;
    },

    initComponent: function() {
        var me = this,
            axes,
            series;
        me.callParent();
        me.addEvents(
            'itemmousedown',
            'itemmouseup',
            'itemmouseover',
            'itemmouseout',
            'itemclick',
            'itemdblclick',
            'itemdragstart',
            'itemdrag',
            'itemdragend',
            
            'beforerefresh',
            
            'refresh'
        );
        Ext.applyIf(me, {
            zoom: {
                width: 1,
                height: 1,
                x: 0,
                y: 0
            }
        });
        me.maxGutter = [0, 0];
        me.store = Ext.data.StoreManager.lookup(me.store);
        axes = me.axes;
        me.axes = new Ext.util.MixedCollection(false, function(a) { return a.position; });
        if (axes) {
            me.axes.addAll(axes);
        }
        series = me.series;
        me.series = new Ext.util.MixedCollection(false, function(a) { return a.seriesId || (a.seriesId = Ext.id(null, 'ext-chart-series-')); });
        if (series) {
            me.series.addAll(series);
        }
        if (me.legend !== false) {
            me.legend = new Ext.chart.Legend(Ext.applyIf({chart:me}, me.legend));
        }

        me.on({
            mousemove: me.onMouseMove,
            mouseleave: me.onMouseLeave,
            mousedown: me.onMouseDown,
            mouseup: me.onMouseUp,
            click: me.onClick,
            dblclick: me.onDblClick,
            scope: me
        });
    },

    
    afterComponentLayout: function(width, height) {
        var me = this;
        if (Ext.isNumber(width) && Ext.isNumber(height)) {
            if (width !== me.curWidth || height !== me.curHeight) {
                me.curWidth = width;
                me.curHeight = height;
                me.redraw(true);
            } else if (me.needsRedraw) {
                delete me.needsRedraw;
                me.redraw();
            }
        }
        this.callParent(arguments);
    },

    
    redraw: function(resize) {
        var me = this,
            seriesItems = me.series.items,
            seriesLen = seriesItems.length,
            axesItems = me.axes.items,
            axesLen = axesItems.length,
            i,
            chartBBox = me.chartBBox = {
                x: 0,
                y: 0,
                height: me.curHeight,
                width: me.curWidth
            },
            legend = me.legend;
        me.surface.setSize(chartBBox.width, chartBBox.height);
        
        for (i = 0; i < seriesLen; i++) {
            me.initializeSeries(seriesItems[i],i);
        }
        for (i = 0; i < axesLen; i++) {
            me.initializeAxis(axesItems[i]);
        }
        
        
        for (i = 0; i < axesLen; i++) {
            axesItems[i].processView();
        }
        for (i = 0; i < axesLen; i++) {
            axesItems[i].drawAxis(true);
        }

        
        if (legend !== false && legend.visible) {
            if (legend.update || !legend.created) {
              legend.create();
            }
        }

        
        me.alignAxes();

        
        if (legend !== false && legend.visible) {
            legend.updatePosition();
        }

        
        me.getMaxGutter();

        
        me.resizing = !!resize;

        for (i = 0; i < axesLen; i++) {
            axesItems[i].drawAxis();
        }
        for (i = 0; i < seriesLen; i++) {
            me.drawCharts(seriesItems[i]);
        }
        me.resizing = false;
    },

    
    afterRender: function() {
        var ref,
            me = this;
        this.callParent();

        if (me.categoryNames) {
            me.setCategoryNames(me.categoryNames);
        }

        if (me.tipRenderer) {
            ref = me.getFunctionRef(me.tipRenderer);
            me.setTipRenderer(ref.fn, ref.scope);
        }
        me.bindStore(me.store, true);
        me.refresh();

        if (me.surface.engine === 'Vml') {
            me.on('added', me.onAddedVml, me);
            me.mon(Ext.container.Container.hierarchyEventSource, 'added', me.onContainerAddedVml, me);
        }
    },

    
    
    
    
    
    onAddedVml: function() {
        this.needsRedraw = true; 
    },

    onContainerAddedVml: function(container) {
        if (this.isDescendantOf(container)) {
            this.needsRedraw = true; 
        }
    },

    
    getEventXY: function(e) {
        var me = this,
            box = this.surface.getRegion(),
            pageXY = e.getXY(),
            x = pageXY[0] - box.left,
            y = pageXY[1] - box.top;
        return [x, y];
    },
    
    onClick: function(e) {
        this.handleClick('itemclick', e);
    },
    
    onDblClick: function(e) {
        this.handleClick('itemdblclick', e);
    },

    
    handleClick: function(name, e) {
        var me = this,
            position = me.getEventXY(e),
            seriesItems = me.series.items,
            i, ln, series,
            item;

        
        
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
                if (series.getItemForPoint) {
                    item = series.getItemForPoint(position[0], position[1]);
                    if (item) {
                        series.fireEvent(name, item);
                    }
                }
            }
        }
    },

    
    onMouseDown: function(e) {
        var me = this,
            position = me.getEventXY(e),
            seriesItems = me.series.items,
            i, ln, series,
            item;

        if (me.enableMask) {
            me.mixins.mask.onMouseDown.call(me, e);
        }
        
        
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
                if (series.getItemForPoint) {
                    item = series.getItemForPoint(position[0], position[1]);
                    if (item) {
                        series.fireEvent('itemmousedown', item);
                    }
                }
            }
        }
    },

    
    onMouseUp: function(e) {
        var me = this,
            position = me.getEventXY(e),
            seriesItems = me.series.items,
            i, ln, series,
            item;

        if (me.enableMask) {
            me.mixins.mask.onMouseUp.call(me, e);
        }
        
        
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
                if (series.getItemForPoint) {
                    item = series.getItemForPoint(position[0], position[1]);
                    if (item) {
                        series.fireEvent('itemmouseup', item);
                    }
                }
            }
        }
    },

    
    onMouseMove: function(e) {
        var me = this,
            position = me.getEventXY(e),
            seriesItems = me.series.items,
            i, ln, series,
            item, last, storeItem, storeField;

        
        if (me.enableMask) {
            me.mixins.mask.onMouseMove.call(me, e);
        }
        
        
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            if (Ext.draw.Draw.withinBox(position[0], position[1], series.bbox)) {
                if (series.getItemForPoint) {
                    item = series.getItemForPoint(position[0], position[1]);
                    last = series._lastItemForPoint;
                    storeItem = series._lastStoreItem;
                    storeField = series._lastStoreField;


                    if (item !== last || item && (item.storeItem != storeItem || item.storeField != storeField)) {
                        if (last) {
                            series.fireEvent('itemmouseout', last);
                            delete series._lastItemForPoint;
                            delete series._lastStoreField;
                            delete series._lastStoreItem;
                        }
                        if (item) {
                            series.fireEvent('itemmouseover', item);
                            series._lastItemForPoint = item;
                            series._lastStoreItem = item.storeItem;
                            series._lastStoreField = item.storeField;
                        }
                    }
                }
            } else {
                last = series._lastItemForPoint;
                if (last) {
                    series.fireEvent('itemmouseout', last);
                    delete series._lastItemForPoint;
                    delete series._lastStoreField;
                    delete series._lastStoreItem;
                }
            }
        }
    },

    
    onMouseLeave: function(e) {
        var me = this,
            seriesItems = me.series.items,
            i, ln, series;

        if (me.enableMask) {
            me.mixins.mask.onMouseLeave.call(me, e);
        }
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            delete series._lastItemForPoint;
        }
    },

    
    delayRefresh: function() {
        var me = this;
        if (!me.refreshTask) {
            me.refreshTask = new Ext.util.DelayedTask(me.refresh, me);
        }
        me.refreshTask.delay(me.refreshBuffer);
    },

    
    refresh: function() {
        var me = this;
            
        if (me.rendered && me.curWidth !== undefined && me.curHeight !== undefined) {
            if (!me.isVisible(true) && !me.refreshPending) {
                me.setShowListeners('mon');
                me.refreshPending = true;
                return;
            }
            if (me.fireEvent('beforerefresh', me) !== false) {
                me.redraw();
                me.fireEvent('refresh', me);
            }
        }
    },
    
    onShow: function(){
        var me = this;
        me.callParent(arguments);
        if (me.refreshPending) {
            me.delayRefresh();
            me.setShowListeners('mun');
        }
        delete me.refreshPending;
    },
    
    setShowListeners: function(method){
        var me = this;
        me[method](Ext.container.Container.hierarchyEventSource, {
            scope: me,
            single: true,
            show: me.forceRefresh,
            expand: me.forceRefresh
        });
    },
    
    forceRefresh: function(container) {
        var me = this;
        if (me.isDescendantOf(container) && me.refreshPending) {
            
            
            me.setShowListeners('mun');
            me.delayRefresh();
        }    
        delete me.refreshPending;
    },

    bindStore: function(store, initial) {
        var me = this;
        me.mixins.bindable.bindStore.apply(me, arguments);
        if (me.store && !initial) {
            me.refresh();
        }
    },
    
    getStoreListeners: function() {
        var refresh = this.refresh,
            delayRefresh = this.delayRefresh;
            
        return {
            refresh: refresh,
            add: delayRefresh,
            remove: delayRefresh,
            update: delayRefresh,
            clear: refresh
        };
    },

    
    initializeAxis: function(axis) {
        var me = this,
            chartBBox = me.chartBBox,
            w = chartBBox.width,
            h = chartBBox.height,
            x = chartBBox.x,
            y = chartBBox.y,
            themeAttrs = me.themeAttrs,
            config = {
                chart: me
            };
        if (themeAttrs) {
            config.axisStyle = Ext.apply({}, themeAttrs.axis);
            config.axisLabelLeftStyle = Ext.apply({}, themeAttrs.axisLabelLeft);
            config.axisLabelRightStyle = Ext.apply({}, themeAttrs.axisLabelRight);
            config.axisLabelTopStyle = Ext.apply({}, themeAttrs.axisLabelTop);
            config.axisLabelBottomStyle = Ext.apply({}, themeAttrs.axisLabelBottom);
            config.axisTitleLeftStyle = Ext.apply({}, themeAttrs.axisTitleLeft);
            config.axisTitleRightStyle = Ext.apply({}, themeAttrs.axisTitleRight);
            config.axisTitleTopStyle = Ext.apply({}, themeAttrs.axisTitleTop);
            config.axisTitleBottomStyle = Ext.apply({}, themeAttrs.axisTitleBottom);
        }
        switch (axis.position) {
            case 'top':
                Ext.apply(config, {
                    length: w,
                    width: h,
                    x: x,
                    y: y
                });
            break;
            case 'bottom':
                Ext.apply(config, {
                    length: w,
                    width: h,
                    x: x,
                    y: h
                });
            break;
            case 'left':
                Ext.apply(config, {
                    length: h,
                    width: w,
                    x: x,
                    y: h
                });
            break;
            case 'right':
                Ext.apply(config, {
                    length: h,
                    width: w,
                    x: w,
                    y: h
                });
            break;
        }
        if (!axis.chart) {
            Ext.apply(config, axis);
            axis = me.axes.replace(Ext.createByAlias('axis.' + axis.type.toLowerCase(), config));
        }
        else {
            Ext.apply(axis, config);
        }
    },


    
    alignAxes: function() {
        var me = this,
            axes = me.axes,
            axesItems = axes.items,
            axis,
            legend = me.legend,
            edges = ['top', 'right', 'bottom', 'left'],
            edge,
            i, ln,
            chartBBox,
            insetPadding = me.insetPadding,
            insets = {
                top: insetPadding,
                right: insetPadding,
                bottom: insetPadding,
                left: insetPadding
            },
            isVertical, bbox, pos;

        function getAxis(edge) {
            var i = axes.findIndex('position', edge);
            return (i < 0) ? null : axes.getAt(i);
        }

        
        for (i = 0, ln = edges.length; i < ln; i++) {
            edge = edges[i];
            isVertical = (edge === 'left' || edge === 'right');
            axis = getAxis(edge);

            
            if (legend !== false) {
                if (legend.position === edge) {
                    bbox = legend.getBBox();
                    insets[edge] += (isVertical ? bbox.width : bbox.height) + insets[edge];
                }
            }

            
            
            if (axis && axis.bbox) {
                bbox = axis.bbox;
                insets[edge] += (isVertical ? bbox.width : bbox.height);
            }
        }
        
        chartBBox = {
            x: insets.left,
            y: insets.top,
            width: me.curWidth - insets.left - insets.right,
            height: me.curHeight - insets.top - insets.bottom
        };
        me.chartBBox = chartBBox;

        
        
        for (i = 0, ln = axesItems.length; i < ln; i++) {
            axis = axesItems[i];
            pos = axis.position;
            isVertical = (pos === 'left' || pos === 'right');

            axis.x = (pos === 'right' ? chartBBox.x + chartBBox.width : chartBBox.x);
            axis.y = (pos === 'top' ? chartBBox.y : chartBBox.y + chartBBox.height);
            axis.width = (isVertical ? chartBBox.width : chartBBox.height);
            axis.length = (isVertical ? chartBBox.height : chartBBox.width);
        }
    },

    
    initializeSeries: function(series, idx) {
        var me = this,
            themeAttrs = me.themeAttrs,
            seriesObj, markerObj, seriesThemes, st,
            markerThemes, colorArrayStyle = [],
            i = 0, l,
            config = {
                chart: me,
                seriesId: series.seriesId
            };
        if (themeAttrs) {
            seriesThemes = themeAttrs.seriesThemes;
            markerThemes = themeAttrs.markerThemes;
            seriesObj = Ext.apply({}, themeAttrs.series);
            markerObj = Ext.apply({}, themeAttrs.marker);
            config.seriesStyle = Ext.apply(seriesObj, seriesThemes[idx % seriesThemes.length]);
            config.seriesLabelStyle = Ext.apply({}, themeAttrs.seriesLabel);
            config.markerStyle = Ext.apply(markerObj, markerThemes[idx % markerThemes.length]);
            if (themeAttrs.colors) {
                config.colorArrayStyle = themeAttrs.colors;
            } else {
                colorArrayStyle = [];
                for (l = seriesThemes.length; i < l; i++) {
                    st = seriesThemes[i];
                    if (st.fill || st.stroke) {
                        colorArrayStyle.push(st.fill || st.stroke);
                    }
                }
                if (colorArrayStyle.length) {
                    config.colorArrayStyle = colorArrayStyle;
                }
            }
            config.seriesIdx = idx;
        }
        if (series instanceof Ext.chart.series.Series) {
            Ext.apply(series, config);
        } else {
            Ext.applyIf(config, series);
            series = me.series.replace(Ext.createByAlias('series.' + series.type.toLowerCase(), config));
        }
        if (series.initialize) {
            series.initialize();
        }
    },

    
    getMaxGutter: function() {
        var me = this,
            seriesItems = me.series.items,
            i, ln, series,
            maxGutter = [0, 0],
            gutter;
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            gutter = series.getGutters && series.getGutters() || [0, 0];
            maxGutter[0] = Math.max(maxGutter[0], gutter[0]);
            maxGutter[1] = Math.max(maxGutter[1], gutter[1]);
        }
        me.maxGutter = maxGutter;
    },

    
    drawAxis: function(axis) {
        axis.drawAxis();
    },

    
    drawCharts: function(series) {
        series.triggerafterrender = false;
        series.drawSeries();
        if (!this.animate) {
            series.fireEvent('afterrender');
        }
    },
    
    save: function(config){
        return Ext.draw.Surface.save(this.surface, config);
    },
    
    destroy: function() {
        Ext.destroy(this.surface);
        this.bindStore(null);
        this.callParent(arguments);
    }
});


Ext.define('Ext.chart.TipSurface', {

    

    extend: 'Ext.draw.Component',

    

    spriteArray: false,
    renderFirst: true,

    constructor: function(config) {
        this.callParent([config]);
        if (config.sprites) {
            this.spriteArray = [].concat(config.sprites);
            delete config.sprites;
        }
    },

    onRender: function() {
        var me = this,
            i = 0,
            l = 0,
            sp,
            sprites;
            this.callParent(arguments);
        sprites = me.spriteArray;
        if (me.renderFirst && sprites) {
            me.renderFirst = false;
            for (l = sprites.length; i < l; i++) {
                sp = me.surface.add(sprites[i]);
                sp.setAttributes({
                    hidden: false
                },
                true);
            }
        }
    }
});


Ext.define('Ext.chart.axis.Abstract', {

    

    requires: ['Ext.chart.Chart'],

    
    
    

    

    
    constructor: function(config) {
        config = config || {};

        var me = this,
            pos = config.position || 'left';

        pos = pos.charAt(0).toUpperCase() + pos.substring(1);
        
        config.label = Ext.apply(config['axisLabel' + pos + 'Style'] || {}, config.label || {});
        config.axisTitleStyle = Ext.apply(config['axisTitle' + pos + 'Style'] || {}, config.labelTitle || {});
        Ext.apply(me, config);
        me.fields = Ext.Array.from(me.fields);
        this.callParent();
        me.labels = [];
        me.getId();
        me.labelGroup = me.chart.surface.getGroup(me.axisId + "-labels");
    },

    alignment: null,
    grid: false,
    steps: 10,
    x: 0,
    y: 0,
    minValue: 0,
    maxValue: 0,

    getId: function() {
        return this.axisId || (this.axisId = Ext.id(null, 'ext-axis-'));
    },

    
    processView: Ext.emptyFn,

    drawAxis: Ext.emptyFn,
    addDisplayAndLabels: Ext.emptyFn
});


Ext.define('Ext.chart.axis.Axis', {

    

    extend: 'Ext.chart.axis.Abstract',

    alternateClassName: 'Ext.chart.Axis',

    requires: ['Ext.draw.Draw'],

    

    

    

    

    

    
    forceMinMax: false,

    
    dashSize: 3,

    
    position: 'bottom',

    
    skipFirst: false,

    
    length: 0,

    
    width: 0,

    
    adjustEnd: true,

    majorTickSteps: false,

    
    applyData: Ext.emptyFn,

    getRange: function () {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            data = store.data.items,
            series = chart.series.items,
            position = me.position,
            boundedAxes,
            seriesClasses = Ext.chart.series,
            aggregations = [],
            min = Infinity, max = -Infinity,
            vertical = me.position === 'left' || me.position === 'right',
            i, ln, ln2, j, k, dataLength = data.length, aggregates,
            countedFields = {},
            allFields = {},
            excludable = true,
            fields, fieldMap, record, field, value;

        fields = me.fields;
        for (j = 0, ln = fields.length; j < ln; j++) {
            allFields[fields[j]] = true;
        }

        for (i = 0, ln = series.length; i < ln; i++) {
            if (series[i].seriesIsHidden) {
                continue;
            }
            if (!series[i].getAxesForXAndYFields) {
                continue;
            }

            boundedAxes = series[i].getAxesForXAndYFields();
            if (boundedAxes.xAxis && boundedAxes.xAxis !== position && boundedAxes.yAxis && boundedAxes.yAxis !== position) {
                
                continue;
            }

            if (seriesClasses.Bar && series[i] instanceof seriesClasses.Bar && !series[i].column) {
                
                fields = vertical ? Ext.Array.from(series[i].xField) : Ext.Array.from(series[i].yField);
            } else {
                fields = vertical ? Ext.Array.from(series[i].yField) : Ext.Array.from(series[i].xField);
            }

            if (me.fields.length) {
                for (j = 0, ln2 = fields.length; j < ln2; j++) {
                    if (allFields[fields[j]]) {
                        break;
                    }
                }
                if (j == ln2) {
                    
                    continue;
                }
            }

            if (aggregates = series[i].stacked) {
                
                if (seriesClasses.Bar && series[i] instanceof seriesClasses.Bar) {
                    if (series[i].column != vertical) {
                        aggregates = false;
                        excludable = false;
                    }
                }
                
                else if (!vertical) {
                    aggregates = false;
                    excludable = false;
                }
            }


            if (aggregates) {
                fieldMap = {};
                for (j = 0; j < fields.length; j++) {
                    if (excludable && series[i].__excludes && series[i].__excludes[j]) {
                        continue;
                    }
                    if (!allFields[fields[j]]) {
                        Ext.Logger.warn('Field `' + fields[j] + '` is not included in the ' + position + ' axis config.');
                    }
                    allFields[fields[j]] = fieldMap[fields[j]] = true;
                }
                aggregations.push({
                    fields: fieldMap,
                    value: 0
                });
            } else {

                if (!fields || fields.length == 0) {
                    fields = me.fields;
                }
                for (j = 0; j < fields.length; j++) {
                    if (excludable && series[i].__excludes && series[i].__excludes[j]) {
                        continue;
                    }
                    allFields[fields[j]] = countedFields[fields[j]] = true;
                }
            }
        }

        for (i = 0; i < dataLength; i++) {
            record = data[i];
            for (k = 0; k < aggregations.length; k++) {
                aggregations[k].value = 0;
            }
            for (field in allFields) {
                value = record.get(field);
                if (isNaN(value)) {
                    continue;
                }
                if (value === undefined) {
                    value = 0;
                }
                if (countedFields[field]) {
                    if (min > value) {
                        min = value;
                    }
                    if (max < value) {
                        max = value;
                    }
                }
                for (k = 0; k < aggregations.length; k++) {
                    if (aggregations[k].fields[field]) {
                        aggregations[k].value += value;
                        
                        if (min > 0) {
                            min = 0;
                        }
                        if (max < aggregations[k].value) {
                            max = aggregations[k].value;
                        }
                    }
                }
            }
        }

        if (!isFinite(max)) {
            max = me.prevMax || 0;
        }
        if (!isFinite(min)) {
            min = me.prevMin || 0;
        }

        
        if (min != max && (max != Math.floor(max))) {
            max = Math.floor(max) + 1;
        }

        if (!isNaN(me.minimum)) {
            min = me.minimum;
        }

        if (!isNaN(me.maximum)) {
            max = me.maximum;
        }

        if (min >= max) {
            
            max = min + 1;
        }

        return {min: min, max: max};
    },

    
    calcEnds: function () {
        var me = this,
            range = me.getRange(),
            min = range.min,
            max = range.max,
            steps, prettyNumbers, out, changedRange;

        steps = (Ext.isNumber(me.majorTickSteps) ? me.majorTickSteps + 1 : me.steps);
        prettyNumbers = !(Ext.isNumber(me.maximum) && Ext.isNumber(me.minimum) && Ext.isNumber(me.majorTickSteps) && me.majorTickSteps > 0);

        out = Ext.draw.Draw.snapEnds(min, max, steps, prettyNumbers);

        if (Ext.isNumber(me.maximum)) {
            out.to = me.maximum;
            changedRange = true;
        }
        if (Ext.isNumber(me.minimum)) {
            out.from = me.minimum;
            changedRange = true;
        }
        if (me.adjustMaximumByMajorUnit) {
            out.to = Math.ceil(out.to / out.step) * out.step;
            changedRange = true;
        }
        if (me.adjustMinimumByMajorUnit) {
            out.from = Math.floor(out.from / out.step) * out.step;
            changedRange = true;
        }

        if (changedRange) {
            out.steps = Math.ceil((out.to - out.from) / out.step);            
        }

        me.prevMin = (min == max ? 0 : min);
        me.prevMax = max;
        return out;
    },

    
    drawAxis: function (init) {
        var me = this,
            i, 
            x = me.x,
            y = me.y,
            gutterX = me.chart.maxGutter[0],
            gutterY = me.chart.maxGutter[1],
            dashSize = me.dashSize,
            subDashesX = me.minorTickSteps || 0,
            subDashesY = me.minorTickSteps || 0,
            length = me.length,
            position = me.position,
            inflections = [],
            calcLabels = false,
            stepCalcs = me.applyData(),
            step = stepCalcs.step,
            steps = stepCalcs.steps,
            from = stepCalcs.from,
            to = stepCalcs.to,
            trueLength,
            currentX,
            currentY,
            path,
            dashesX,
            dashesY,
            delta;

        
        
        
        if (me.hidden || isNaN(step) || (from > to)) {
            return;
        }

        me.from = stepCalcs.from;
        me.to = stepCalcs.to;

        if (position == 'left' || position == 'right') {
            currentX = Math.floor(x) + 0.5;
            path = ["M", currentX, y, "l", 0, -length];
            trueLength = length - (gutterY * 2);
        }
        else {
            currentY = Math.floor(y) + 0.5;
            path = ["M", x, currentY, "l", length, 0];
            trueLength = length - (gutterX * 2);
        }

        
        delta = steps && trueLength / steps;
        dashesX = Math.max(subDashesX + 1, 0);
        dashesY = Math.max(subDashesY + 1, 0);
        if (me.type == 'Numeric' || me.type == 'Time') {
            calcLabels = true;
            me.labels = [stepCalcs.from];
        }

        if (position == 'right' || position == 'left') {
            currentY = y - gutterY;
            currentX = x - ((position == 'left') * dashSize * 2);
            while (currentY >= y - gutterY - trueLength) {
                path.push("M", currentX, Math.floor(currentY) + 0.5, "l", dashSize * 2 + 1, 0);
                if (currentY != y - gutterY) {
                    for (i = 1; i < dashesY; i++) {
                        path.push("M", currentX + dashSize, Math.floor(currentY + delta * i / dashesY) + 0.5, "l", dashSize + 1, 0);
                    }
                }
                inflections.push([ Math.floor(x), Math.floor(currentY) ]);
                currentY -= delta;

                if (calcLabels) {
                    me.labels.push(me.labels[me.labels.length - 1] + step);
                }

                if (delta === 0) {
                    break;
                }
            }
            if (Math.round(currentY + delta - (y - gutterY - trueLength))) {
                path.push("M", currentX, Math.floor(y - length + gutterY) + 0.5, "l", dashSize * 2 + 1, 0);
                for (i = 1; i < dashesY; i++) {
                    path.push("M", currentX + dashSize, Math.floor(y - length + gutterY + delta * i / dashesY) + 0.5, "l", dashSize + 1, 0);
                }
                inflections.push([ Math.floor(x), Math.floor(currentY) ]);
                if (calcLabels) {
                    me.labels.push(me.labels[me.labels.length - 1] + step);
                }
            }
        } else {
            currentX = x + gutterX;
            currentY = y - ((position == 'top') * dashSize * 2);
            while (currentX <= x + gutterX + trueLength) {
                path.push("M", Math.floor(currentX) + 0.5, currentY, "l", 0, dashSize * 2 + 1);
                if (currentX != x + gutterX) {
                    for (i = 1; i < dashesX; i++) {
                        path.push("M", Math.floor(currentX - delta * i / dashesX) + 0.5, currentY, "l", 0, dashSize + 1);
                    }
                }
                inflections.push([ Math.floor(currentX), Math.floor(y) ]);
                currentX += delta;
                if (calcLabels) {
                    me.labels.push(me.labels[me.labels.length - 1] + step);
                }
                if (delta === 0) {
                    break;
                }
            }
            if (Math.round(currentX - delta - (x + gutterX + trueLength))) {
                path.push("M", Math.floor(x + length - gutterX) + 0.5, currentY, "l", 0, dashSize * 2 + 1);
                for (i = 1; i < dashesX; i++) {
                    path.push("M", Math.floor(x + length - gutterX - delta * i / dashesX) + 0.5, currentY, "l", 0, dashSize + 1);
                }
                inflections.push([ Math.floor(currentX), Math.floor(y) ]);
                if (calcLabels) {
                    me.labels.push(me.labels[me.labels.length - 1] + step);
                }
            }
        }

        
        if (calcLabels) {
            me.labels[inflections.length - 1] = +(me.labels[inflections.length - 1]).toFixed(10);
        }

        if (!me.axis) {
            me.axis = me.chart.surface.add(Ext.apply({
                type: 'path',
                path: path
            }, me.axisStyle));
        }
        me.axis.setAttributes({
            path: path
        }, true);
        me.inflections = inflections;
        if (!init && me.grid) {
            me.drawGrid();
        }
        me.axisBBox = me.axis.getBBox();
        me.drawLabel();
    },

    
    drawGrid: function () {
        var me = this,
            surface = me.chart.surface,
            grid = me.grid,
            odd = grid.odd,
            even = grid.even,
            inflections = me.inflections,
            ln = inflections.length - ((odd || even) ? 0 : 1),
            position = me.position,
            gutter = me.chart.maxGutter,
            width = me.width - 2,
            point, prevPoint,
            i = 1,
            path = [], styles, lineWidth, dlineWidth,
            oddPath = [], evenPath = [];

        if ((gutter[1] !== 0 && (position == 'left' || position == 'right')) ||
            (gutter[0] !== 0 && (position == 'top' || position == 'bottom'))) {
            i = 0;
            ln++;
        }
        for (; i < ln; i++) {
            point = inflections[i];
            prevPoint = inflections[i - 1];
            if (odd || even) {
                path = (i % 2) ? oddPath : evenPath;
                styles = ((i % 2) ? odd : even) || {};
                lineWidth = (styles.lineWidth || styles['stroke-width'] || 0) / 2;
                dlineWidth = 2 * lineWidth;
                if (position == 'left') {
                    path.push("M", prevPoint[0] + 1 + lineWidth, prevPoint[1] + 0.5 - lineWidth,
                        "L", prevPoint[0] + 1 + width - lineWidth, prevPoint[1] + 0.5 - lineWidth,
                        "L", point[0] + 1 + width - lineWidth, point[1] + 0.5 + lineWidth,
                        "L", point[0] + 1 + lineWidth, point[1] + 0.5 + lineWidth, "Z");
                }
                else if (position == 'right') {
                    path.push("M", prevPoint[0] - lineWidth, prevPoint[1] + 0.5 - lineWidth,
                        "L", prevPoint[0] - width + lineWidth, prevPoint[1] + 0.5 - lineWidth,
                        "L", point[0] - width + lineWidth, point[1] + 0.5 + lineWidth,
                        "L", point[0] - lineWidth, point[1] + 0.5 + lineWidth, "Z");
                }
                else if (position == 'top') {
                    path.push("M", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] + 1 + lineWidth,
                        "L", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] + 1 + width - lineWidth,
                        "L", point[0] + 0.5 - lineWidth, point[1] + 1 + width - lineWidth,
                        "L", point[0] + 0.5 - lineWidth, point[1] + 1 + lineWidth, "Z");
                }
                else {
                    path.push("M", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] - lineWidth,
                        "L", prevPoint[0] + 0.5 + lineWidth, prevPoint[1] - width + lineWidth,
                        "L", point[0] + 0.5 - lineWidth, point[1] - width + lineWidth,
                        "L", point[0] + 0.5 - lineWidth, point[1] - lineWidth, "Z");
                }
            } else {
                if (position == 'left') {
                    path = path.concat(["M", point[0] + 0.5, point[1] + 0.5, "l", width, 0]);
                }
                else if (position == 'right') {
                    path = path.concat(["M", point[0] - 0.5, point[1] + 0.5, "l", -width, 0]);
                }
                else if (position == 'top') {
                    path = path.concat(["M", point[0] + 0.5, point[1] + 0.5, "l", 0, width]);
                }
                else {
                    path = path.concat(["M", point[0] + 0.5, point[1] - 0.5, "l", 0, -width]);
                }
            }
        }
        if (odd || even) {
            if (oddPath.length) {
                if (!me.gridOdd && oddPath.length) {
                    me.gridOdd = surface.add({
                        type: 'path',
                        path: oddPath
                    });
                }
                me.gridOdd.setAttributes(Ext.apply({
                    path: oddPath,
                    hidden: false
                }, odd || {}), true);
            }
            if (evenPath.length) {
                if (!me.gridEven) {
                    me.gridEven = surface.add({
                        type: 'path',
                        path: evenPath
                    });
                }
                me.gridEven.setAttributes(Ext.apply({
                    path: evenPath,
                    hidden: false
                }, even || {}), true);
            }
        }
        else {
            if (path.length) {
                if (!me.gridLines) {
                    me.gridLines = me.chart.surface.add({
                        type: 'path',
                        path: path,
                        "stroke-width": me.lineWidth || 1,
                        stroke: me.gridColor || '#ccc'
                    });
                }
                me.gridLines.setAttributes({
                    hidden: false,
                    path: path
                }, true);
            }
            else if (me.gridLines) {
                me.gridLines.hide(true);
            }
        }
    },

    
    getOrCreateLabel: function (i, text) {
        var me = this,
            labelGroup = me.labelGroup,
            textLabel = labelGroup.getAt(i),
            surface = me.chart.surface;
        if (textLabel) {
            if (text != textLabel.attr.text) {
                textLabel.setAttributes(Ext.apply({
                    text: text
                }, me.label), true);
                textLabel._bbox = textLabel.getBBox();
            }
        }
        else {
            textLabel = surface.add(Ext.apply({
                group: labelGroup,
                type: 'text',
                x: 0,
                y: 0,
                text: text
            }, me.label));
            surface.renderItem(textLabel);
            textLabel._bbox = textLabel.getBBox();
        }
        
        if (me.label.rotation) {
            textLabel.setAttributes({
                rotation: {
                    degrees: 0
                }
            }, true);
            textLabel._ubbox = textLabel.getBBox();
            textLabel.setAttributes(me.label, true);
        } else {
            textLabel._ubbox = textLabel._bbox;
        }
        return textLabel;
    },

    rect2pointArray: function (sprite) {
        var surface = this.chart.surface,
            rect = surface.getBBox(sprite, true),
            p1 = [rect.x, rect.y],
            p1p = p1.slice(),
            p2 = [rect.x + rect.width, rect.y],
            p2p = p2.slice(),
            p3 = [rect.x + rect.width, rect.y + rect.height],
            p3p = p3.slice(),
            p4 = [rect.x, rect.y + rect.height],
            p4p = p4.slice(),
            matrix = sprite.matrix;
        
        p1[0] = matrix.x.apply(matrix, p1p);
        p1[1] = matrix.y.apply(matrix, p1p);

        p2[0] = matrix.x.apply(matrix, p2p);
        p2[1] = matrix.y.apply(matrix, p2p);

        p3[0] = matrix.x.apply(matrix, p3p);
        p3[1] = matrix.y.apply(matrix, p3p);

        p4[0] = matrix.x.apply(matrix, p4p);
        p4[1] = matrix.y.apply(matrix, p4p);
        return [p1, p2, p3, p4];
    },

    intersect: function (l1, l2) {
        var r1 = this.rect2pointArray(l1),
            r2 = this.rect2pointArray(l2);
        return !!Ext.draw.Draw.intersect(r1, r2).length;
    },

    drawHorizontalLabels: function () {
        var me = this,
            labelConf = me.label,
            floor = Math.floor,
            max = Math.max,
            axes = me.chart.axes,
            insetPadding = me.chart.insetPadding,
            position = me.position,
            inflections = me.inflections,
            ln = inflections.length,
            labels = me.labels,
            maxHeight = 0,
            ratio,
            bbox, point, prevLabel, prevLabelId,
            adjustEnd = me.adjustEnd,
            hasLeft = axes.findIndex('position', 'left') != -1,
            hasRight = axes.findIndex('position', 'right') != -1,
            textLabel, text,
            last, x, y, i, firstLabel;

        last = ln - 1;
        
        point = inflections[0];
        firstLabel = me.getOrCreateLabel(0, me.label.renderer(labels[0]));
        ratio = Math.floor(Math.abs(Math.sin(labelConf.rotate && (labelConf.rotate.degrees * Math.PI / 180) || 0)));

        for (i = 0; i < ln; i++) {
            point = inflections[i];
            text = me.label.renderer(labels[i]);
            textLabel = me.getOrCreateLabel(i, text);
            bbox = textLabel._bbox;
            maxHeight = max(maxHeight, bbox.height + me.dashSize + me.label.padding);
            x = floor(point[0] - (ratio ? bbox.height : bbox.width) / 2);
            if (adjustEnd && me.chart.maxGutter[0] == 0) {
                if (i == 0 && !hasLeft) {
                    x = point[0];
                }
                else if (i == last && !hasRight) {
                    x = Math.min(x, point[0] - bbox.width + insetPadding);
                }
            }
            if (position == 'top') {
                y = point[1] - (me.dashSize * 2) - me.label.padding - (bbox.height / 2);
            }
            else {
                y = point[1] + (me.dashSize * 2) + me.label.padding + (bbox.height / 2);
            }

            textLabel.setAttributes({
                hidden: false,
                x: x,
                y: y
            }, true);

            
            if (i != 0 && (me.intersect(textLabel, prevLabel)
                || me.intersect(textLabel, firstLabel))) {
                if (i === last && prevLabelId !== 0) {
                    prevLabel.hide(true);
                } else {
                    textLabel.hide(true);
                    continue;
                }
            }

            prevLabel = textLabel;
            prevLabelId = i;
        }

        return maxHeight;
    },

    drawVerticalLabels: function () {
        var me = this,
            inflections = me.inflections,
            position = me.position,
            ln = inflections.length,
            chart = me.chart,
            insetPadding = chart.insetPadding,
            labels = me.labels,
            maxWidth = 0,
            max = Math.max,
            floor = Math.floor,
            ceil = Math.ceil,
            axes = me.chart.axes,
            gutterY = me.chart.maxGutter[1],
            bbox, point, prevLabel, prevLabelId,
            hasTop = axes.findIndex('position', 'top') != -1,
            hasBottom = axes.findIndex('position', 'bottom') != -1,
            adjustEnd = me.adjustEnd,
            textLabel, text,
            last = ln - 1, x, y, i;

        for (i = 0; i < ln; i++) {
            point = inflections[i];
            text = me.label.renderer(labels[i]);
            textLabel = me.getOrCreateLabel(i, text);
            bbox = textLabel._bbox;

            maxWidth = max(maxWidth, bbox.width + me.dashSize + me.label.padding);
            y = point[1];
            if (adjustEnd && gutterY < bbox.height / 2) {
                if (i == last && !hasTop) {
                    y = Math.max(y, me.y - me.length + ceil(bbox.height / 2) - insetPadding);
                }
                else if (i == 0 && !hasBottom) {
                    y = me.y + gutterY - floor(bbox.height / 2);
                }
            }
            if (position == 'left') {
                x = point[0] - bbox.width - me.dashSize - me.label.padding - 2;
            }
            else {
                x = point[0] + me.dashSize + me.label.padding + 2;
            }
            textLabel.setAttributes(Ext.apply({
                hidden: false,
                x: x,
                y: y
            }, me.label), true);
            
            if (i != 0 && me.intersect(textLabel, prevLabel)) {
                if (i === last && prevLabelId !== 0) {
                    prevLabel.hide(true);
                } else {
                    textLabel.hide(true);
                    continue;
                }
            }
            prevLabel = textLabel;
            prevLabelId = i;
        }

        return maxWidth;
    },

    
    drawLabel: function () {
        var me = this,
            position = me.position,
            labelGroup = me.labelGroup,
            inflections = me.inflections,
            maxWidth = 0,
            maxHeight = 0,
            ln, i;

        if (position == 'left' || position == 'right') {
            maxWidth = me.drawVerticalLabels();
        } else {
            maxHeight = me.drawHorizontalLabels();
        }

        
        ln = labelGroup.getCount();
        i = inflections.length;
        for (; i < ln; i++) {
            labelGroup.getAt(i).hide(true);
        }

        me.bbox = {};
        Ext.apply(me.bbox, me.axisBBox);
        me.bbox.height = maxHeight;
        me.bbox.width = maxWidth;
        if (Ext.isString(me.title)) {
            me.drawTitle(maxWidth, maxHeight);
        }
    },

    
    setTitle: function (title) {
        this.title = title;
        this.drawLabel();
    },

    
    drawTitle: function (maxWidth, maxHeight) {
        var me = this,
            position = me.position,
            surface = me.chart.surface,
            displaySprite = me.displaySprite,
            title = me.title,
            rotate = (position == 'left' || position == 'right'),
            x = me.x,
            y = me.y,
            base, bbox, pad;

        if (displaySprite) {
            displaySprite.setAttributes({text: title}, true);
        } else {
            base = {
                type: 'text',
                x: 0,
                y: 0,
                text: title
            };
            displaySprite = me.displaySprite = surface.add(Ext.apply(base, me.axisTitleStyle, me.labelTitle));
            surface.renderItem(displaySprite);
        }
        bbox = displaySprite.getBBox();
        pad = me.dashSize + me.label.padding;

        if (rotate) {
            y -= ((me.length / 2) - (bbox.height / 2));
            if (position == 'left') {
                x -= (maxWidth + pad + (bbox.width / 2));
            }
            else {
                x += (maxWidth + pad + bbox.width - (bbox.width / 2));
            }
            me.bbox.width += bbox.width + 10;
        }
        else {
            x += (me.length / 2) - (bbox.width * 0.5);
            if (position == 'top') {
                y -= (maxHeight + pad + (bbox.height * 0.3));
            }
            else {
                y += (maxHeight + pad + (bbox.height * 0.8));
            }
            me.bbox.height += bbox.height + 10;
        }
        displaySprite.setAttributes({
            translate: {
                x: x,
                y: y
            }
        }, true);
    }
});


Ext.define('Ext.chart.axis.Category', {

    

    extend: 'Ext.chart.axis.Axis',

    alternateClassName: 'Ext.chart.CategoryAxis',

    alias: 'axis.category',

    

    
    categoryNames: null,

    
    calculateCategoryCount: false,

    
    setLabels: function() {
        var store = this.chart.getChartStore(),
            data = store.data.items,
            d, dLen, record,
            fields = this.fields,
            ln = fields.length,
            i;

        this.labels = [];
        for (d = 0, dLen = data.length; d < dLen; d++) {
            record = data[d];
            for (i = 0; i < ln; i++) {
                this.labels.push(record.get(fields[i]));
            }
        }
    },

    
    applyData: function() {
        this.callParent();
        this.setLabels();
        var count = this.chart.getChartStore().getCount();
        return {
            from: 0,
            to: count - 1,
            power: 1,
            step: 1,
            steps: count - 1
        };
    }
});


Ext.define('Ext.chart.axis.Gauge', {

    

    extend: 'Ext.chart.axis.Abstract',

    

    

    

    

    

    

    position: 'gauge',

    alias: 'axis.gauge',

    drawAxis: function(init) {
        var chart = this.chart,
            surface = chart.surface,
            bbox = chart.chartBBox,
            centerX = bbox.x + (bbox.width / 2),
            centerY = bbox.y + bbox.height,
            margin = this.margin || 10,
            rho = Math.min(bbox.width, 2 * bbox.height) /2 + margin,
            sprites = [], sprite,
            steps = this.steps,
            i, pi = Math.PI,
            cos = Math.cos,
            sin = Math.sin;

        if (this.sprites && !chart.resizing) {
            this.drawLabel();
            return;
        }

        if (this.margin >= 0) {
            if (!this.sprites) {
                
                for (i = 0; i <= steps; i++) {
                    sprite = surface.add({
                        type: 'path',
                        path: ['M', centerX + (rho - margin) * cos(i / steps * pi - pi),
                                    centerY + (rho - margin) * sin(i / steps * pi - pi),
                                    'L', centerX + rho * cos(i / steps * pi - pi),
                                    centerY + rho * sin(i / steps * pi - pi), 'Z'],
                        stroke: '#ccc'
                    });
                    sprite.setAttributes({
                        hidden: false
                    }, true);
                    sprites.push(sprite);
                }
            } else {
                sprites = this.sprites;
                
                for (i = 0; i <= steps; i++) {
                    sprites[i].setAttributes({
                        path: ['M', centerX + (rho - margin) * cos(i / steps * pi - pi),
                                    centerY + (rho - margin) * sin(i / steps * pi - pi),
                               'L', centerX + rho * cos(i / steps * pi - pi),
                                    centerY + rho * sin(i / steps * pi - pi), 'Z'],
                        stroke: '#ccc'
                    }, true);
                }
            }
        }
        this.sprites = sprites;
        this.drawLabel();
        if (this.title) {
            this.drawTitle();
        }
    },

    drawTitle: function() {
        var me = this,
            chart = me.chart,
            surface = chart.surface,
            bbox = chart.chartBBox,
            labelSprite = me.titleSprite,
            labelBBox;

        if (!labelSprite) {
            me.titleSprite = labelSprite = surface.add({
                type: 'text',
                zIndex: 2
            });
        }
        labelSprite.setAttributes(Ext.apply({
            text: me.title
        }, me.label || {}), true);
        labelBBox = labelSprite.getBBox();
        labelSprite.setAttributes({
            x: bbox.x + (bbox.width / 2) - (labelBBox.width / 2),
            y: bbox.y + bbox.height - (labelBBox.height / 2) - 4
        }, true);
    },

    
    setTitle: function(title) {
        this.title = title;
        this.drawTitle();
    },

    drawLabel: function() {
        var chart = this.chart,
            surface = chart.surface,
            bbox = chart.chartBBox,
            centerX = bbox.x + (bbox.width / 2),
            centerY = bbox.y + bbox.height,
            margin = this.margin || 10,
            rho = Math.min(bbox.width, 2 * bbox.height) /2 + 2 * margin,
            round = Math.round,
            labelArray = [], label,
            maxValue = this.maximum || 0,
            minValue = this.minimum || 0,
            steps = this.steps, i = 0,
            adjY,
            pi = Math.PI,
            cos = Math.cos,
            sin = Math.sin,
            labelConf = this.label,
            renderer = labelConf.renderer || function(v) { return v; };

        if (!this.labelArray) {
            
            for (i = 0; i <= steps; i++) {
                
                adjY = (i === 0 || i === steps) ? 7 : 0;
                label = surface.add({
                    type: 'text',
                    text: renderer(round(minValue + i / steps * (maxValue - minValue))),
                    x: centerX + rho * cos(i / steps * pi - pi),
                    y: centerY + rho * sin(i / steps * pi - pi) - adjY,
                    'text-anchor': 'middle',
                    'stroke-width': 0.2,
                    zIndex: 10,
                    stroke: '#333'
                });
                label.setAttributes({
                    hidden: false
                }, true);
                labelArray.push(label);
            }
        }
        else {
            labelArray = this.labelArray;
            
            for (i = 0; i <= steps; i++) {
                
                adjY = (i === 0 || i === steps) ? 7 : 0;
                labelArray[i].setAttributes({
                    text: renderer(round(minValue + i / steps * (maxValue - minValue))),
                    x: centerX + rho * cos(i / steps * pi - pi),
                    y: centerY + rho * sin(i / steps * pi - pi) - adjY
                }, true);
            }
        }
        this.labelArray = labelArray;
    }
});

Ext.define('Ext.chart.axis.Numeric', {

    

    extend: 'Ext.chart.axis.Axis',

    alternateClassName: 'Ext.chart.NumericAxis',

    

    type: 'numeric',

    alias: 'axis.numeric',

    uses: ['Ext.data.Store'],

    constructor: function(config) {
        var me = this,
            hasLabel = !!(config.label && config.label.renderer),
            label;

        me.callParent([config]);
        label = me.label;

        if (config.constrain == null) {
            me.constrain = (config.minimum != null && config.maximum != null);
        }

        if (!hasLabel) {
            label.renderer = function(v) {
                return me.roundToDecimal(v, me.decimals);
            };
        }
    },

    roundToDecimal: function(v, dec) {
        var val = Math.pow(10, dec || 0);
        return Math.round(v * val) / val;
    },

    
    minimum: NaN,

    
    maximum: NaN,

    
    constrain: true,

    
    decimals: 2,

    
    scale: "linear",

    
    doConstrain: function() {
        var me = this,
            store = me.chart.store,
            items = store.data.items,
            d, dLen, record,
            series = me.chart.series.items,
            fields = me.fields,
            ln = fields.length,
            range = me.calcEnds(),
            min = range.from, max = range.to, i, l,
            useAcum = false,
            value, data = [],
            addRecord;

        for (i = 0, l = series.length; i < l; i++) {
            if (series[i].type === 'bar' && series[i].stacked) {
                
                return;
            }
        }

        for (d = 0, dLen = items.length; d < dLen; d++) {
            addRecord = true;
            record = items[d];
            for (i = 0; i < ln; i++) {
                value = record.get(fields[i]);
                if (+value < +min) {
                    addRecord = false;
                    break;
                }
                if (+value > +max) {
                    addRecord = false;
                    break;
                }
            }
            if (addRecord) {
                data.push(record);
            }
        }
        me.chart.substore = Ext.create('Ext.data.Store', { model: store.model });
        me.chart.substore.loadData(data); 
    },
    
    position: 'left',

    
    adjustMaximumByMajorUnit: false,

    
    adjustMinimumByMajorUnit: false,

    
    processView: function() {
        var me = this,
            constrain = me.constrain;
        if (constrain) {
            me.doConstrain();
        }
    },

    
    applyData: function() {
        this.callParent();
        return this.calcEnds();
    }
});


Ext.define('Ext.chart.axis.Radial', {

    

    extend: 'Ext.chart.axis.Abstract',

    

    position: 'radial',

    alias: 'axis.radial',

    drawAxis: function(init) {
        var chart = this.chart,
            surface = chart.surface,
            bbox = chart.chartBBox,
            store = chart.store,
            l = store.getCount(),
            centerX = bbox.x + (bbox.width / 2),
            centerY = bbox.y + (bbox.height / 2),
            rho = Math.min(bbox.width, bbox.height) /2,
            sprites = [], sprite,
            steps = this.steps,
            i, j, pi2 = Math.PI * 2,
            cos = Math.cos, sin = Math.sin;

        if (this.sprites && !chart.resizing) {
            this.drawLabel();
            return;
        }

        if (!this.sprites) {
            
            for (i = 1; i <= steps; i++) {
                sprite = surface.add({
                    type: 'circle',
                    x: centerX,
                    y: centerY,
                    radius: Math.max(rho * i / steps, 0),
                    stroke: '#ccc'
                });
                sprite.setAttributes({
                    hidden: false
                }, true);
                sprites.push(sprite);
            }
            
            for (i = 0; i < l; i++) {
                sprite = surface.add({
                    type: 'path',
                    path: ['M', centerX, centerY, 'L', centerX + rho * cos(i / l * pi2), centerY + rho * sin(i / l * pi2), 'Z'],
                    stroke: '#ccc'
                });
                sprite.setAttributes({
                    hidden: false
                }, true);
                sprites.push(sprite);
            }
        } else {
            sprites = this.sprites;
            
            for (i = 0; i < steps; i++) {
                sprites[i].setAttributes({
                    x: centerX,
                    y: centerY,
                    radius: Math.max(rho * (i + 1) / steps, 0),
                    stroke: '#ccc'
                }, true);
            }
            
            for (j = 0; j < l; j++) {
                sprites[i + j].setAttributes({
                    path: ['M', centerX, centerY, 'L', centerX + rho * cos(j / l * pi2), centerY + rho * sin(j / l * pi2), 'Z'],
                    stroke: '#ccc'
                }, true);
            }
        }
        this.sprites = sprites;

        this.drawLabel();
    },

    drawLabel: function() {
        var chart = this.chart,
            seriesItems = chart.series.items,
            series,
            surface = chart.surface,
            bbox = chart.chartBBox,
            store = chart.store,
            data = store.data.items,
            ln, record,
            centerX = bbox.x + (bbox.width / 2),
            centerY = bbox.y + (bbox.height / 2),
            rho = Math.min(bbox.width, bbox.height) /2,
            max = Math.max, round = Math.round,
            labelArray = [], label,
            fields = [], nfields,
            categories = [], xField,
            aggregate = !this.maximum,
            maxValue = this.maximum || 0,
            steps = this.steps, i = 0, j, dx, dy,
            pi2 = Math.PI * 2,
            cos = Math.cos, sin = Math.sin,
            display = this.label.display,
            draw = display !== 'none',
            margin = 10;

        if (!draw) {
            return;
        }

        
        for (i = 0, ln = seriesItems.length; i < ln; i++) {
            series = seriesItems[i];
            fields.push(series.yField);
            xField = series.xField;
        }
        
        
        for (j = 0, ln = data.length; j < ln; j++) {
            record = data[j];
            if (aggregate) {
                for (i = 0, nfields = fields.length; i < nfields; i++) {
                    maxValue = max(+record.get(fields[i]), maxValue);
                }
            }
            categories.push(record.get(xField));
        }
        if (!this.labelArray) {
            if (display != 'categories') {
                
                for (i = 1; i <= steps; i++) {
                    label = surface.add({
                        type: 'text',
                        text: round(i / steps * maxValue),
                        x: centerX,
                        y: centerY - rho * i / steps,
                        'text-anchor': 'middle',
                        'stroke-width': 0.1,
                        stroke: '#333'
                    });
                    label.setAttributes({
                        hidden: false
                    }, true);
                    labelArray.push(label);
                }
            }
            if (display != 'scale') {
                
                for (j = 0, steps = categories.length; j < steps; j++) {
                    dx = cos(j / steps * pi2) * (rho + margin);
                    dy = sin(j / steps * pi2) * (rho + margin);
                    label = surface.add({
                        type: 'text',
                        text: categories[j],
                        x: centerX + dx,
                        y: centerY + dy,
                        'text-anchor': dx * dx <= 0.001? 'middle' : (dx < 0? 'end' : 'start')
                    });
                    label.setAttributes({
                        hidden: false
                    }, true);
                    labelArray.push(label);
                }
            }
        }
        else {
            labelArray = this.labelArray;
            if (display != 'categories') {
                
                for (i = 0; i < steps; i++) {
                    labelArray[i].setAttributes({
                        text: round((i + 1) / steps * maxValue),
                        x: centerX,
                        y: centerY - rho * (i + 1) / steps,
                        'text-anchor': 'middle',
                        'stroke-width': 0.1,
                        stroke: '#333'
                    }, true);
                }
            }
            if (display != 'scale') {
                
                for (j = 0, steps = categories.length; j < steps; j++) {
                    dx = cos(j / steps * pi2) * (rho + margin);
                    dy = sin(j / steps * pi2) * (rho + margin);
                    if (labelArray[i + j]) {
                        labelArray[i + j].setAttributes({
                            type: 'text',
                            text: categories[j],
                            x: centerX + dx,
                            y: centerY + dy,
                            'text-anchor': dx * dx <= 0.001? 'middle' : (dx < 0? 'end' : 'start')
                        }, true);
                    }
                }
            }
        }
        this.labelArray = labelArray;
    }
});

Ext.define('Ext.chart.axis.Time', {

    

    extend: 'Ext.chart.axis.Numeric',

    alternateClassName: 'Ext.chart.TimeAxis',

    alias: 'axis.time',

    uses: ['Ext.data.Store'],

    

    
    dateFormat: false,

    
    fromDate: false,

    
    toDate: false,

    
    step: [Ext.Date.DAY, 1],

    
    constrain: false,

    constructor: function (config) {
        var me = this, label, f, df;
        me.callParent([config]);
        label = me.label || {};
        df = this.dateFormat;
        if (df) {
            if (label.renderer) {
                f = label.renderer;
                label.renderer = function(v) {
                    v = f(v);
                    return Ext.Date.format(new Date(f(v)), df);
                };
            } else {
                label.renderer = function(v) {
                    return Ext.Date.format(new Date(v >> 0), df);
                };
            }
        }
    },

    
    processView: function () {
        var me = this;
        if (me.fromDate) {
            me.minimum = +me.fromDate;
        }
        if (me.toDate) {
            me.maximum = +me.toDate;
        }
        if(me.constrain){
            me.doConstrain();
        }
     },

    
    calcEnds: function() {
        var me = this, range, step = me.step;
        if (step) {
            range = me.getRange();
            range = Ext.draw.Draw.snapEndsByDateAndStep(new Date(range.min), new Date(range.max), Ext.isNumber(step) ? [Date.MILLI, step]: step);
            if (me.minimum) {
                range.from = me.minimum;
            }
            if (me.maximum) {
                range.to = me.maximum;
            }
            range.step = (range.to - range.from) / range.steps;
            return range;
        } else {
            return me.callParent(arguments);
        }
    }
 });



Ext.define('Ext.draw.Text', {
    extend: 'Ext.draw.Component',
    uses: ['Ext.util.CSS'],
    alias: 'widget.text',

    
    text: '',

    

    

    focusable: false,
    viewBox: false,
    autoSize: true,
    baseCls: Ext.baseCSSPrefix + 'surface ' + Ext.baseCSSPrefix + 'draw-text',

    initComponent: function() {
        var me = this;

        me.textConfig = Ext.apply({
            type: 'text',
            text: me.text,
            rotate: {
                degrees: me.degrees || 0
            }
        }, me.textStyle);
        Ext.apply(me.textConfig, me.getStyles(me.styleSelectors || me.styleSelector));

        
        
        me.initialConfig.items = [me.textConfig];
        me.callParent(arguments);
    },

    
    getStyles: function(selectors) {
        selectors = Ext.Array.from(selectors);
        var i = 0,
            len = selectors.length,
            rule,
            style,
            prop,
            result = {};

        for (; i < len; i++) {
            
            rule = Ext.util.CSS.getRule(selectors[i]);
            if (rule) {
                style = rule.style;
                if (style) {
                    Ext.apply(result, {
                        'font-family': style.fontFamily,
                        'font-weight': style.fontWeight,
                        'line-height': style.lineHeight,
                        'font-size': style.fontSize,
                        fill: style.color
                    });
                }
            }
        }
        return result;
    },

    
    setAngle: function(degrees) {
        var me = this,
            surface,
            sprite;
            
        if (me.rendered) {
            surface = me.surface;
            sprite = surface.items.items[0];

            me.degrees = degrees;
            sprite.setAttributes({
                rotate: {
                    degrees: degrees
                }
            }, true);
            if (me.autoSize || me.viewBox) {
                me.updateLayout();
            }
        } else {
            me.degrees = degrees;
        }
    },

    
    setText: function(text) {
        var me = this,
            surface,
            sprite;
            
        if (me.rendered) {
            surface = me.surface;
            sprite = surface.items.items[0];

            me.text = text || '';
            surface.remove(sprite);
            me.textConfig.type = 'text';
            me.textConfig.text = me.text;
            sprite = surface.add(me.textConfig);
            sprite.setAttributes({
                rotate: {
                    degrees: me.degrees
                }
            }, true);
            if (me.autoSize || me.viewBox) {
                me.updateLayout();
            }
        } else {
            me.on({
                render: function() {
                    me.setText(text);
                },
                single: true
            });
        }
    }
});


Ext.define('Ext.FocusManager', {
    singleton: true,
    alternateClassName: ['Ext.FocusMgr' ],

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: [
        'Ext.AbstractComponent',
        'Ext.Component',
        'Ext.ComponentManager',
        'Ext.ComponentQuery',
        'Ext.util.HashMap',
        'Ext.util.KeyNav'
    ],

    
    enabled: false,

    

    focusElementCls: Ext.baseCSSPrefix + 'focus-element',

    focusFrameCls: Ext.baseCSSPrefix + 'focus-frame',

    
    whitelist: [
        'textfield'
    ],

    constructor: function(config) {
        var me = this,
            CQ = Ext.ComponentQuery;

        me.mixins.observable.constructor.call(me, config);

        me.addEvents(
            
            'beforecomponentfocus',

            
            'componentfocus',

            
            'disable',

            
            'enable'
        );

        me.focusTask = new Ext.util.DelayedTask(me.handleComponentFocus, me);

        
        Ext.override(Ext.AbstractComponent, {
            onFocus: function() {
                this.callParent(arguments);
                if (me.enabled && this.hasFocus) {
                    Array.prototype.unshift.call(arguments, this);
                    me.onComponentFocus.apply(me, arguments);
                }
            },
            onBlur: function() {
                this.callParent(arguments);
                if (me.enabled && !this.hasFocus) {
                    Array.prototype.unshift.call(arguments, this);
                    me.onComponentBlur.apply(me, arguments);
                }
            },
            onDestroy: function() {
                this.callParent(arguments);
                if (me.enabled) {
                    Array.prototype.unshift.call(arguments, this);
                    me.onComponentDestroy.apply(me, arguments);
                }
            }
        });
        Ext.override(Ext.Component, {
            afterHide: function() {
                this.callParent(arguments);
                if (me.enabled) {
                    Array.prototype.unshift.call(arguments, this);
                    me.onComponentHide.apply(me, arguments);
                }
            }
        });
        
        
        me.keyNav = new Ext.util.KeyNav(Ext.getDoc(), {
            disabled: true,
            scope: me,

            backspace: me.focusLast,
            enter: me.navigateIn,
            esc: me.navigateOut,
            tab: me.navigateSiblings,
            space: me.navigateIn,
            del: me.focusLast,
            left: me.navigateSiblings,
            right: me.navigateSiblings,
            down: me.navigateSiblings,
            up: me.navigateSiblings
        });

        me.focusData = {};
        me.subscribers = new Ext.util.HashMap();
        me.focusChain = {};

        
        Ext.apply(CQ.pseudos, {
            focusable: function(cmps) {
                var len = cmps.length,
                    results = [],
                    i = 0,
                    c;

                for (; i < len; i++) {
                    c = cmps[i];
                    if (c.isFocusable()) {
                        results.push(c);
                    }
                }

                return results;
            },

            
            nextFocus: function(cmps, idx, step) {
                step = step || 1;
                idx = parseInt(idx, 10);

                var len = cmps.length,
                    i = idx, c;

                for (;;) {
                    
                    if ((i += step) >= len) {
                        i = 0;
                    } else if (i < 0) {
                        i = len - 1;
                    }

                    
                    if (i === idx) {
                        return [];
                    }

                    
                    if ((c = cmps[i]).isFocusable()) {
                        return [c];
                    }
                }

                return [];
            },

            prevFocus: function(cmps, idx) {
                return this.nextFocus(cmps, idx, -1);
            },

            root: function(cmps) {
                var len = cmps.length,
                    results = [],
                    i = 0,
                    c;

                for (; i < len; i++) {
                    c = cmps[i];
                    if (!c.ownerCt) {
                        results.push(c);
                    }
                }

                return results;
            }
        });
    },

    
    addXTypeToWhitelist: function(xtype) {
        var me = this;

        if (Ext.isArray(xtype)) {
            Ext.Array.forEach(xtype, me.addXTypeToWhitelist, me);
            return;
        }

        if (!Ext.Array.contains(me.whitelist, xtype)) {
            me.whitelist.push(xtype);
        }
    },

    clearComponent: function(cmp) {
        clearTimeout(this.cmpFocusDelay);
        if (!cmp.isDestroyed) {
            cmp.blur();
        }
    },

    
    disable: function() {
        var me = this;

        if (!me.enabled) {
            return;
        }

        delete me.options;
        me.enabled = false;

        me.removeDOM();

        
        me.keyNav.disable();

        me.fireEvent('disable', me);
    },

    
    enable: function(options) {
        var me = this;

        if (options === true) {
            options = { focusFrame: true };
        }
        me.options = options = options || {};

        if (me.enabled) {
            return;
        }

        
        me.enabled = true;
        me.initDOM(options);

        
        me.keyNav.enable();

        
        me.focusEl.focus();
        delete me.focusedCmp;

        me.fireEvent('enable', me);
    },

    focusLast: function(e) {
        var me = this;

        if (me.isWhitelisted(me.focusedCmp)) {
            return true;
        }

        
        if (me.previousFocusedCmp) {
            me.previousFocusedCmp.focus();
        }
    },

    getRootComponents: function() {
        var me = this,
            CQ = Ext.ComponentQuery,
            inline = CQ.query(':focusable:root:not([floating])'),
            floating = CQ.query(':focusable:root[floating]');

        
        
        floating.sort(function(a, b) {
            return a.el.getZIndex() > b.el.getZIndex();
        });

        return floating.concat(inline);
    },

    initDOM: function(options) {
        var me = this,
            cls = me.focusFrameCls,
            needListeners = Ext.ComponentQuery.query('{getFocusEl()}:not([focusListenerAdded])'),
            i = 0, len = needListeners.length;

        if (!Ext.isReady) {
            return Ext.onReady(me.initDOM, me);
        }

        
        
        
        for (; i < len; i++) {
            needListeners[i].addFocusListener();
        }

        
        if (!me.focusEl) {
            me.focusEl = Ext.getBody();
            me.focusEl.dom.tabIndex = -1;
        }

        
        if (!me.focusFrame && options.focusFrame) {
            me.focusFrame = Ext.getBody().createChild({
                cls: cls,
                children: [
                    { cls: cls + '-top' },
                    { cls: cls + '-bottom' },
                    { cls: cls + '-left' },
                    { cls: cls + '-right' }
                ],
                style: 'top: -100px; left: -100px;'
            });
            me.focusFrame.setVisibilityMode(Ext.Element.DISPLAY);
            me.focusFrame.hide().setLeftTop(0, 0);
        }
    },

    isWhitelisted: function(cmp) {
        return cmp && Ext.Array.some(this.whitelist, function(x) {
            return cmp.isXType(x);
        });
    },

    navigateIn: function(e) {
        var me = this,
            focusedCmp = me.focusedCmp,
            defaultRoot,
            firstChild;

        if (me.isWhitelisted(focusedCmp)) {
            return true;
        }

        if (!focusedCmp) {
            
            defaultRoot = me.getRootComponents()[0];
            if (defaultRoot) {
                
                
                if (defaultRoot.getFocusEl() === me.focusEl) {
                    me.focusEl.blur();
                }
                defaultRoot.focus();
            }
        } else {
            
            
            firstChild = focusedCmp.hasFocus ? Ext.ComponentQuery.query('>:focusable', focusedCmp)[0] : focusedCmp;
            if (firstChild) {
                firstChild.focus();
            } else {
                
                if (Ext.isFunction(focusedCmp.onClick)) {
                    e.button = 0;
                    focusedCmp.onClick(e);
                    if (focusedCmp.isVisible(true)) {
                        focusedCmp.focus();
                    } else {
                        me.navigateOut();
                    }
                }
            }
        }
    },

    navigateOut: function(e) {
        var me = this,
            parent;

        if (!me.focusedCmp || !(parent = me.focusedCmp.up(':focusable'))) {
            me.focusEl.focus();
        } else {
            parent.focus();
        }

        
        
        
        return true;
    },

    navigateSiblings: function(e, source, parent) {
        var me = this,
            src = source || me,
            key = e.getKey(),
            EO = Ext.EventObject,
            goBack = e.shiftKey || key == EO.LEFT || key == EO.UP,
            checkWhitelist = key == EO.LEFT || key == EO.RIGHT || key == EO.UP || key == EO.DOWN,
            nextSelector = goBack ? 'prev' : 'next',
            idx, next, focusedCmp, siblings;

        focusedCmp = (src.focusedCmp && src.focusedCmp.comp) || src.focusedCmp;
        if (!focusedCmp && !parent) {
            return true;
        }

        if (checkWhitelist && me.isWhitelisted(focusedCmp)) {
            return true;
        }

        
        if (!focusedCmp || focusedCmp.is(':root')) {
            siblings = me.getRootComponents();
        } else {
            
            parent = parent || focusedCmp.up();
            if (parent) {
                siblings = parent.getRefItems();
            }
        }


        
        if (siblings) {
            idx = focusedCmp ? Ext.Array.indexOf(siblings, focusedCmp) : -1;
            next = Ext.ComponentQuery.query(':' + nextSelector + 'Focus(' + idx + ')', siblings)[0];
            if (next && focusedCmp !== next) {
                next.focus();
                return next;
            }
        }
    },

    onComponentBlur: function(cmp, e) {
        var me = this;

        if (me.focusedCmp === cmp) {
            me.previousFocusedCmp = cmp;
            delete me.focusedCmp;
        }

        if (me.focusFrame) {
            me.focusFrame.hide();
        }
    },

    onComponentFocus: function(cmp, e) {
        var me = this,
            chain = me.focusChain,
            parent;

        if (!cmp.isFocusable()) {
            me.clearComponent(cmp);

            
            
            
            
            if (chain[cmp.id]) {
                return;
            }

            
            parent = cmp.up();
            if (parent) {
                
                
                
                chain[cmp.id] = true;
                parent.focus();
            }

            return;
        }
        
        me.focusChain = {};

        
        
        
        me.focusTask.delay(10, null, null, [cmp, cmp.getFocusEl()]);
    },

    handleComponentFocus: function(cmp, focusEl) {
        var me = this,
            cls,
            ff,
            fw,
            box,
            bt,
            bl,
            bw,
            bh,
            ft,
            fb,
            fl,
            fr;

        if (me.fireEvent('beforecomponentfocus', me, cmp, me.previousFocusedCmp) === false) {
            me.clearComponent(cmp);
            return;
        }

        me.focusedCmp = cmp;

        
        if (me.shouldShowFocusFrame(cmp)) {
            cls = '.' + me.focusFrameCls + '-';
            ff = me.focusFrame;
            box = focusEl.getPageBox();

            
            
            
            bt = box.top;
            bl = box.left;
            bw = box.width;
            bh = box.height;
            ft = ff.child(cls + 'top');
            fb = ff.child(cls + 'bottom');
            fl = ff.child(cls + 'left');
            fr = ff.child(cls + 'right');

            ft.setWidth(bw).setLeftTop(bl, bt);
            fb.setWidth(bw).setLeftTop(bl, bt + bh - 2);
            fl.setHeight(bh - 2).setLeftTop(bl, bt + 2);
            fr.setHeight(bh - 2).setLeftTop(bl + bw - 2, bt + 2);

            ff.show();
        }

        me.fireEvent('componentfocus', me, cmp, me.previousFocusedCmp);
    },

    onComponentHide: function(cmp) {
        var me = this,
            cmpHadFocus = false,
            focusedCmp = me.focusedCmp,
            parent;

        if (focusedCmp) {
            
            
            cmpHadFocus = cmp.hasFocus || (cmp.isContainer && cmp.isAncestor(me.focusedCmp));
        }

        me.clearComponent(cmp);

        
        if (cmpHadFocus && (parent = cmp.up(':focusable'))) {
            parent.focus();
        } else {
            me.focusEl.focus();
        }
    },

    onComponentDestroy: function() {

    },

    removeDOM: function() {
        var me = this;

        
        
        if (me.enabled || me.subscribers.length) {
            return;
        }

        Ext.destroy(
            me.focusFrame
        );
        delete me.focusEl;
        delete me.focusFrame;
    },

    
    removeXTypeFromWhitelist: function(xtype) {
        var me = this;

        if (Ext.isArray(xtype)) {
            Ext.Array.forEach(xtype, me.removeXTypeFromWhitelist, me);
            return;
        }

        Ext.Array.remove(me.whitelist, xtype);
    },

    setupSubscriberKeys: function(container, keys) {
        var me = this,
            el = container.getFocusEl(),
            scope = keys.scope,
            handlers = {
                backspace: me.focusLast,
                enter: me.navigateIn,
                esc: me.navigateOut,
                scope: me
            },

            navSiblings = function(e) {
                if (me.focusedCmp === container) {
                    
                    
                    
                    return me.navigateSiblings(e, me, container);
                } else {
                    return me.navigateSiblings(e);
                }
            };

        Ext.iterate(keys, function(key, cb) {
            handlers[key] = function(e) {
                var ret = navSiblings(e);

                if (Ext.isFunction(cb) && cb.call(scope || container, e, ret) === true) {
                    return true;
                }

                return ret;
            };
        }, me);

        return new Ext.util.KeyNav(el, handlers);
    },

    shouldShowFocusFrame: function(cmp) {
        var me = this,
            opts = me.options || {},
            cmpFocusEl = cmp.getFocusEl(),
            cmpFocusElTag = Ext.getDom(cmpFocusEl).tagName;

        
        
        
        if (!me.focusFrame || !cmp) {
            return false;
        }

        
        if (opts.focusFrame) {
            return true;
        }

        if (me.focusData[cmp.id].focusFrame) {
            return true;
        }

        return false;
    }
});

Ext.define('Ext.Img', {
    extend: 'Ext.Component',
    alias: ['widget.image', 'widget.imagecomponent'],

    autoEl: 'img',

    
    src: '',

    
    alt: '',

    
    imgCls: '',

    getElConfig: function() {
        var me = this,
            config = me.callParent(),
            img;

        
        
        if (me.autoEl == 'img') {
            img = config;
        } else {
            config.cn = [img = {
                tag: 'img',
                id: me.id + '-img'
            }];
        }

        if (me.imgCls) {
            img.cls = (img.cls ? img.cls + ' ' : '') + me.imgCls;
        }

        img.src = me.src || Ext.BLANK_IMAGE_URL;
        if (me.alt) {
            img.alt = me.alt;
        }

        return config;
    },

    onRender: function () {
        var me = this,
            el;

        me.callParent(arguments);

        el = me.el;
        me.imgEl = (me.autoEl == 'img') ? el : el.getById(me.id + '-img');
    },

    onDestroy: function () {
        Ext.destroy(this.imgEl);
        this.imgEl = null;
        this.callParent();
    },

    
    setSrc: function(src) {
        var me = this,
            imgEl = me.imgEl;

        me.src = src;

        if (imgEl) {
            imgEl.dom.src = src || Ext.BLANK_IMAGE_URL;
        }
    }
});

Ext.define('Ext.LoadMask', {

    extend: 'Ext.Component',

    alias: 'widget.loadmask',

    

    mixins: {
        floating: 'Ext.util.Floating',
        bindable: 'Ext.util.Bindable'
    },

    uses: ['Ext.data.StoreManager'],

    

    

    
    
    msg : 'Loading...',
    

    
    msgCls : Ext.baseCSSPrefix + 'mask-loading',

    
    maskCls: Ext.baseCSSPrefix + 'mask',

    
    useMsg: true,

    
    useTargetEl: false,

    baseCls: Ext.baseCSSPrefix + 'mask-msg',

    childEls: [
        'msgEl'
    ],

    renderTpl: '<div id="{id}-msgEl" style="position:relative" class="{[values.$comp.msgCls]}"></div>',

    
    floating: {
        shadow: 'frame'
    },

    
    focusOnToFront: false,

    
    
    bringParentToFront: false,

    
    constructor : function(comp, config) {
        var me = this;

        
        if (!comp.isComponent) {
            comp = Ext.get(comp);
            this.isElement = true;
        }

        me.ownerCt = comp;
        if (!this.isElement) {
            me.bindComponent(comp);
        }
        me.callParent([config]);

        if (me.store) {
            me.bindStore(me.store, true);
        }
    },

    bindComponent: function(comp){
        var me = this,
            listeners = {
                scope: this,
                resize: me.sizeMask,
                added: me.onComponentAdded,
                removed: me.onComponentRemoved
            },
            hierarchyEventSource = Ext.container.Container.hierarchyEventSource;
            
        if (comp.floating) {
            listeners.move = me.sizeMask;
            me.activeOwner = comp;
        } else if (comp.ownerCt) {
            me.onComponentAdded(comp.ownerCt);
        } else {
            
            me.preventBringToFront = true;
        }

        me.mon(comp, listeners);
        
        
        me.mon(hierarchyEventSource, {
            show: me.onContainerShow,
            hide: me.onContainerHide,
            expand: me.onContainerExpand,
            collapse: me.onContainerCollapse,
            scope: me
        });
    },

    onComponentAdded: function(owner){
        var me = this;
        delete me.activeOwner;
        me.floatParent = owner;
        if (!owner.floating) {
            owner = owner.up('[floating]');
        }
        if (owner) {
            me.activeOwner = owner;
            me.mon(owner, 'move', me.sizeMask, me);
        }
        owner = me.floatParent.ownerCt;
        if (me.rendered && me.isVisible() && owner) {
            me.floatOwner = owner;
            me.mon(owner, 'afterlayout', me.sizeMask, me, {single: true});
        }
    },

    onComponentRemoved: function(owner){
        var me = this,
            activeOwner = me.activeOwner,
            floatOwner = me.floatOwner;

        if (activeOwner) {
            me.mun(activeOwner, 'move', me.sizeMask, me);
        }
        if (floatOwner) {
            me.mun(floatOwner, 'afterlayout', me.sizeMask, me);
        }
        delete me.activeOwner;
        delete me.floatOwner;
    },

    afterRender: function() {
        this.callParent(arguments);
        this.container = this.floatParent.getContentTarget();
    },

    onContainerShow: function(container){
        if (this.isActiveContainer(container)) {
            this.onComponentShow();
        }
    },

    onContainerHide: function(container){
        if (this.isActiveContainer(container)) {
            this.onComponentHide();
        }
    },

    onContainerExpand: function(container){
        if (this.isActiveContainer(container)) {
            this.onComponentShow();
        }
    },

    onContainerCollapse: function(container){
        if (this.isActiveContainer(container)) {
            this.onComponentHide();
        }
    },

    isActiveContainer: function(container){
        return this.isDescendantOf(container);
    },

    onComponentHide: function(){
        var me = this;

        if (me.rendered && me.isVisible()) {
            me.hide();
            me.showNext = true;
        }
    },

    onComponentShow: function(){
        if (this.showNext) {
            this.show();
        }
        delete this.showNext;
    },

    
    sizeMask: function() {
        var me = this,
            target;

        if (me.rendered && me.isVisible()) {
            me.center();

            target = me.getMaskTarget();
            me.getMaskEl().show().setSize(target.getSize()).alignTo(target, 'tl-tl');

        }
    },

    
    bindStore : function(store, initial) {
        var me = this;
        me.mixins.bindable.bindStore.apply(me, arguments);
        store = me.store;
        if (store && store.isLoading()) {
            me.onBeforeLoad();
        }
    },

    getStoreListeners: function(){
        return {
            beforeload: this.onBeforeLoad,
            load: this.onLoad,
            exception: this.onLoad,

            
            cachemiss: this.onBeforeLoad,

            
            cachefilled: this.onLoad
        };
    },

    onDisable : function() {
        this.callParent(arguments);
        if (this.loading) {
            this.onLoad();
        }
    },

    getOwner: function(){
        return this.ownerCt || this.floatParent;
    },

    getMaskTarget: function(){
        var owner = this.getOwner();
        return this.useTargetEl ? owner.getTargetEl() : owner.getEl();
    },

    
    onBeforeLoad : function() {
        var me = this,
            owner = me.getOwner(),
            origin;

        if (!me.disabled) {
            me.loading = true;
            
            
            if (owner.componentLayoutCounter) {
                me.maybeShow();
            } else {
                
                origin = owner.afterComponentLayout;
                owner.afterComponentLayout = function() {
                    owner.afterComponentLayout = origin;
                    origin.apply(owner, arguments);
                    me.maybeShow();
                };
            }
        }
    },

    maybeShow: function(){
        var me = this,
            owner = me.getOwner();

        if (!owner.isVisible(true)) {
            me.showNext = true;
        }
        else if (me.loading && owner.rendered) {
            me.show();
        }
    },

    getMaskEl: function(){
        var me = this;
        return me.maskEl || (me.maskEl = me.el.insertSibling({
            cls: me.maskCls,
            style: {
                zIndex: me.el.getStyle('zIndex') - 2
            }
        }, 'before'));
    },

    onShow: function() {
        var me = this,
            msgEl = me.msgEl;

        me.callParent(arguments);
        me.loading = true;

        if (me.useMsg) {
            msgEl.show().update(me.msg);
        } else {
            msgEl.parent().hide();
        }
    },

    hide: function(){
        
        if (this.isElement) {
            this.ownerCt.unmask();
            this.fireEvent('hide', this);
            return;
        }
        delete this.showNext;
        return this.callParent(arguments);
    },

    onHide: function(){
        this.callParent();
        this.getMaskEl().hide();
    },

    show: function(){
        
        if (this.isElement) {
            this.ownerCt.mask(this.useMsg ? this.msg : '', this.msgCls);
            this.fireEvent('show', this);
            return;
        }
        return this.callParent(arguments);
    },

    afterShow: function() {
        this.callParent(arguments);
        this.sizeMask();
    },

    setZIndex: function(index) {
        var me = this,
            owner = me.activeOwner;
            
        if (owner) {
            
            
            
            index = parseInt(owner.el.getStyle('zIndex'), 10) + 1;
        }

        me.getMaskEl().setStyle('zIndex', index - 1);
        return me.mixins.floating.setZIndex.apply(me, arguments);
    },

    
    onLoad : function() {
        this.loading = false;
        this.hide();
    },

    onDestroy: function(){
        var me = this;

        if (me.isElement) {
            me.ownerCt.unmask();
        }

        Ext.destroy(me.maskEl);
        me.callParent();
    }
});


Ext.define('Ext.view.AbstractView', {
    extend: 'Ext.Component',
    requires: [
        'Ext.LoadMask',
        'Ext.data.StoreManager',
        'Ext.CompositeElementLite',
        'Ext.DomQuery',
        'Ext.selection.DataViewModel'
    ],
    mixins: {
        bindable: 'Ext.util.Bindable'
    },

    inheritableStatics: {
        getRecord: function(node) {
            return this.getBoundView(node).getRecord(node);
        },

        getBoundView: function(node) {
            return Ext.getCmp(node.boundView);
        }
    },

    
    

    
    deferInitialRefresh: true,

    

    
    itemCls: Ext.baseCSSPrefix + 'dataview-item',

    

    

    
    
    loadingText: 'Loading...',
    

    
    loadMask: true,

    

    
    loadingUseMsg: true,


    

    
    selectedItemCls: Ext.baseCSSPrefix + 'item-selected',

    
    
    emptyText: "",
    

    
    deferEmptyText: true,

    
    trackOver: false,

    
    blockRefresh: false,

    

    
    preserveScrollOnRefresh: false,

    
    last: false,

    triggerEvent: 'itemclick',
    triggerCtEvent: 'containerclick',

    addCmpEvents: function() {

    },

    
    initComponent : function(){
        var me = this,
            isDef = Ext.isDefined,
            itemTpl = me.itemTpl,
            memberFn = {};

        if (itemTpl) {
            if (Ext.isArray(itemTpl)) {
                
                itemTpl = itemTpl.join('');
            } else if (Ext.isObject(itemTpl)) {
                
                memberFn = Ext.apply(memberFn, itemTpl.initialConfig);
                itemTpl = itemTpl.html;
            }

            if (!me.itemSelector) {
                me.itemSelector = '.' + me.itemCls;
            }

            itemTpl = Ext.String.format('<tpl for="."><div class="{0}">{1}</div></tpl>', me.itemCls, itemTpl);
            me.tpl = new Ext.XTemplate(itemTpl, memberFn);
        }


        me.callParent();
        if(Ext.isString(me.tpl) || Ext.isArray(me.tpl)){
            me.tpl = new Ext.XTemplate(me.tpl);
        }


        me.addEvents(
            
            'beforerefresh',
            
            'refresh',
            
            'viewready',
            
            'itemupdate',
            
            'itemadd',
            
            'itemremove'
        );

        me.addCmpEvents();

        
        me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
        me.bindStore(me.store, true);
        me.all = new Ext.CompositeElementLite();

        
        me.scrollState = {
            top: 0,
            left: 0
        };
        me.on({
            scroll: me.onViewScroll,
            element: 'el',
            scope: me
        });
    },

    onRender: function() {
        var me = this,
            mask = me.loadMask,
            cfg = {
                msg: me.loadingText,
                msgCls: me.loadingCls,
                useMsg: me.loadingUseMsg,
                
                
                store: me.getMaskStore()
            };

        me.callParent(arguments);

        if (mask) {
            
            if (Ext.isObject(mask)) {
                cfg = Ext.apply(cfg, mask);
            }
            
            
            
            
            me.loadMask = new Ext.LoadMask(me, cfg);
            me.loadMask.on({
                scope: me,
                beforeshow: me.onMaskBeforeShow,
                hide: me.onMaskHide
            });
        }
    },
    
    finishRender: function(){
        var me = this;
        me.callParent(arguments);
        
        
        if (!me.up('[collapsed],[hidden]')) {
            me.doFirstRefresh(me.store);
        }
    },

    onBoxReady: function() {
        var me = this;

        me.callParent(arguments);

        
        
        if (!me.firstRefreshDone) {
            me.doFirstRefresh(me.store);
        }
    },
    
    getMaskStore: function(){
        return this.store;    
    },
    
    onMaskBeforeShow: function(){
        var me = this,
            loadingHeight = me.loadingHeight;

        me.getSelectionModel().deselectAll();
        me.all.clear();
        if (loadingHeight && loadingHeight > me.getHeight()) {
            me.hasLoadingHeight = true;
            me.oldMinHeight = me.minHeight;
            me.minHeight = loadingHeight;
            me.updateLayout();
        }
    },

    onMaskHide: function(){
        var me = this;

        if (!me.destroying && me.hasLoadingHeight) {
            me.minHeight = me.oldMinHeight;
            me.updateLayout();
            delete me.hasLoadingHeight;
        }
    },

    beforeRender: function() {
        this.callParent(arguments);
        this.getSelectionModel().beforeViewRender(this);
    },

    afterRender: function() {
        this.callParent(arguments);

        
        
        
        this.getSelectionModel().bindComponent(this);
    },

    
    getSelectionModel: function(){
        var me = this,
            mode = 'SINGLE';

        if (!me.selModel) {
            me.selModel = {};
        }

        if (me.simpleSelect) {
            mode = 'SIMPLE';
        } else if (me.multiSelect) {
            mode = 'MULTI';
        }

        Ext.applyIf(me.selModel, {
            allowDeselect: me.allowDeselect,
            mode: mode
        });

        if (!me.selModel.events) {
            me.selModel = new Ext.selection.DataViewModel(me.selModel);
        }

        if (!me.selModel.hasRelaySetup) {
            me.relayEvents(me.selModel, [
                'selectionchange', 'beforeselect', 'beforedeselect', 'select', 'deselect', 'focuschange'
            ]);
            me.selModel.hasRelaySetup = true;
        }

        
        
        if (me.disableSelection) {
            me.selModel.locked = true;
        }

        return me.selModel;
    },

    
    refresh: function() {
        var me = this,
            targetEl,
            targetParent,
            oldDisplay,
            nextSibling,
            dom,
            records;

        if (!me.rendered || me.isDestroyed) {
            return;
        }

        if (!me.hasListeners.beforerefresh || me.fireEvent('beforerefresh', me) !== false) {
            targetEl = me.getTargetEl();
            records = me.store.getRange();
            dom = targetEl.dom;

            
            
            if (!me.preserveScrollOnRefresh) {
                targetParent = dom.parentNode;
                oldDisplay = dom.style.display;
                dom.style.display = 'none';
                nextSibling = dom.nextSibling;
                targetParent.removeChild(dom);
            }

            if (me.refreshCounter) {
                me.clearViewEl();
            } else {
                me.fixedNodes = targetEl.dom.childNodes.length;
                me.refreshCounter = 1;
            }

            
            
            
            
            me.tpl.append(targetEl, me.collectData(records, 0));

            
            
            if (records.length < 1) {
                if (!me.deferEmptyText || me.hasSkippedEmptyText) {
                    Ext.core.DomHelper.insertHtml('beforeEnd', targetEl.dom, me.emptyText);
                }
                me.all.clear();
            } else {
                me.all.fill(Ext.query(me.getItemSelector(), targetEl.dom));
                me.updateIndexes(0);
            }

            me.selModel.refresh();
            me.hasSkippedEmptyText = true;

            if (!me.preserveScrollOnRefresh) {
                targetParent.insertBefore(dom, nextSibling);
                dom.style.display = oldDisplay;
            }

            
            this.refreshSize();

            me.fireEvent('refresh', me);

            
            
            if (!me.viewReady) {
                
                
                me.viewReady = true;
                me.fireEvent('viewready', me);
            }
        }
    },

    
    refreshSize: function() {
        var sizeModel = this.getSizeModel();
        if (sizeModel.height.shrinkWrap || sizeModel.width.shrinkWrap) {
            this.updateLayout();
        }
    },

    clearViewEl: function(){
        
        
        
        
        
        
        

        var me = this,
            el = me.getTargetEl();

        if (me.fixedNodes) {
            while (el.dom.childNodes[me.fixedNodes]) {
                el.dom.removeChild(el.dom.childNodes[me.fixedNodes]);
            }
        } else {
            el.update('');
        }
        me.refreshCounter++;
    },

    
    onViewScroll: Ext.emptyFn,

    
    saveScrollState: function() {
        if (this.rendered) {
            var dom = this.el.dom,
                state = this.scrollState;

            state.left = dom.scrollLeft;
            state.top = dom.scrollTop;
        }
    },

    
    restoreScrollState: function() {
        if (this.rendered) {
            var dom = this.el.dom, 
                state = this.scrollState;

            dom.scrollLeft = state.left;
            dom.scrollTop = state.top;
        }
    },

    
    prepareData: function(data, index, record) {
        var associatedData, attr;
        if (record) {
            associatedData = record.getAssociatedData();
            for (attr in associatedData) {
                if (associatedData.hasOwnProperty(attr)) {
                    data[attr] = associatedData[attr];
                }
            }
        }
        return data;
    },

    
    collectData : function(records, startIndex){
        var data = [],
            i = 0,
            len = records.length,
            record;

        for (; i < len; i++) {
            record = records[i];
            data[i] = this.prepareData(record.data, startIndex + i, record);
        }
        return data;
    },

    
    bufferRender : function(records, index){
        var me = this,
            div = me.renderBuffer || (me.renderBuffer = document.createElement('div'));

        me.tpl.overwrite(div, me.collectData(records, index));
        return Ext.query(me.getItemSelector(), div);
    },

    
    onUpdate : function(ds, record){
        var me = this,
            index,
            node;

        if (me.viewReady) {
            index = me.store.indexOf(record);
            if (index > -1) {
                node = me.bufferRender([record], index)[0];
                
                if (me.getNode(record)) {
                    me.all.replaceElement(index, node, true);
                    me.updateIndexes(index, index);
                    
                    
                    me.selModel.refresh();
                    if (me.hasListeners.itemupdate) {
                        me.fireEvent('itemupdate', record, index, node);
                    }
                    return node;
                }
            }
        }

    },

    
    onAdd : function(ds, records, index) {
        var me = this,
            nodes;

        if (me.rendered) {
            
            
            if (me.all.getCount() === 0) {
                me.refresh();
                return;
            }

            nodes = me.bufferRender(records, index);
            me.doAdd(nodes, records, index);

            me.selModel.refresh();
            me.updateIndexes(index);

            
            me.refreshSize();

            if (me.hasListeners.itemadd) {
                me.fireEvent('itemadd', records, index, nodes);
            }
        }

    },

    doAdd: function(nodes, records, index) {
        var all = this.all,
            count = all.getCount();

        if (count === 0) {
            this.clearViewEl();
            this.getTargetEl().appendChild(nodes);
        } else if (index < count) {
            if (index === 0) {
                all.item(index).insertSibling(nodes, 'before', true);
            } else {
                all.item(index - 1).insertSibling(nodes, 'after', true);
            }
        } else {
            all.last().insertSibling(nodes, 'after', true);
        }

        Ext.Array.insert(all.elements, index, nodes);
    },

    
    onRemove : function(ds, record, index) {
        var me = this;

        if (me.all.getCount()) {
            if (me.store.getCount() === 0) {
                
                me.refresh();
            } else {
                
                
                me.doRemove(record, index);
                if (me.selModel.refreshOnRemove) {
                    me.selModel.refresh();
                }
                me.updateIndexes(index);
            }

            
            this.refreshSize();

            if (me.hasListeners.itemremove) {
                me.fireEvent('itemremove', record, index);
            }
        }
    },

    doRemove: function(record, index) {
        this.all.removeElement(index, true);
    },

    
    refreshNode : function(index){
        this.onUpdate(this.store, this.store.getAt(index));
    },

    
    updateIndexes : function(startIndex, endIndex) {
        var ns = this.all.elements,
            records = this.store.getRange(),
            i;

        startIndex = startIndex || 0;
        endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));
        for (i = startIndex; i <= endIndex; i++) {
            ns[i].viewIndex = i;
            ns[i].viewRecordId = records[i].internalId;
            if (!ns[i].boundView) {
                ns[i].boundView = this.id;
            }
        }
    },

    
    getStore : function() {
        return this.store;
    },

    
    bindStore : function(store, initial) {
        var me = this;
        me.mixins.bindable.bindStore.apply(me, arguments);

        
        
        if (!initial) {
            me.getSelectionModel().bindStore(me.store);
        }

        
        
        
        if (me.componentLayoutCounter) {
            me.doFirstRefresh(store);
        }
    },

    
    doFirstRefresh: function(store) {
        var me = this;

        
        me.firstRefreshDone = true;

        
        
        
        
        
        if (store && !store.loading) {
            if (me.deferInitialRefresh) {
                me.applyFirstRefresh();
            } else {
                me.refresh();
            }
        }
    },
    
    applyFirstRefresh: function(){
        var me = this;
        if (me.isDestroyed) {
            return;
        }
        
        
        
        
        
        
        
        
        
        if (me.up('[isCollapsingOrExpanding]')) {
            Ext.Function.defer(me.applyFirstRefresh, 100, me);
        } else {
            Ext.Function.defer(function () {
                if (!me.isDestroyed) {
                    me.refresh();
                }
            }, 1);
        }
    },

    onUnbindStore: function(store) {
        this.setMaskBind(null);
    },

    onBindStore: function(store) {
        this.setMaskBind(store);
    },

    setMaskBind: function(store) {
        var mask = this.loadMask;
        if (mask && mask.bindStore) {
            mask.bindStore(store);
        }
    },

    getStoreListeners: function() {
        var me = this;
        return {
            refresh: me.onDataRefresh,
            add: me.onAdd,
            remove: me.onRemove,
            update: me.onUpdate,
            clear: me.refresh
        };
    },

    
    onDataRefresh: function() {
        var me = this,
            
            
            blockedByAncestor = !me.firstRefreshDone && (!me.rendered || me.up('[collapsed],[isCollapsingOrExpanding],[hidden]'));

        
        
        
        
        if (blockedByAncestor) {
            me.deferInitialRefresh = false;
        } else if (me.blockRefresh !== true) {
            me.firstRefreshDone = true;
            me.refresh.apply(me, arguments);
        }

    },

    
    findItemByChild: function(node){
        return Ext.fly(node).findParent(this.getItemSelector(), this.getTargetEl());
    },

    
    findTargetByEvent: function(e) {
        return e.getTarget(this.getItemSelector(), this.getTargetEl());
    },


    
    getSelectedNodes: function(){
        var nodes   = [],
            records = this.selModel.getSelection(),
            ln = records.length,
            i  = 0;

        for (; i < ln; i++) {
            nodes.push(this.getNode(records[i]));
        }

        return nodes;
    },

    
    getRecords: function(nodes) {
        var records = [],
            i = 0,
            len = nodes.length,
            data = this.store.data;

        for (; i < len; i++) {
            records[records.length] = data.getByKey(nodes[i].viewRecordId);
        }

        return records;
    },

    
    getRecord: function(node){
        return this.store.data.getByKey(Ext.getDom(node).viewRecordId);
    },


    
    isSelected : function(node) {
        
        var r = this.getRecord(node);
        return this.selModel.isSelected(r);
    },

    
    select: function(records, keepExisting, suppressEvent) {
        this.selModel.select(records, keepExisting, suppressEvent);
    },

    
    deselect: function(records, suppressEvent) {
        this.selModel.deselect(records, suppressEvent);
    },

    
    getNode : function(nodeInfo) {
        if ((!nodeInfo && nodeInfo !== 0) || !this.rendered) {
            return null;
        }

        if (Ext.isString(nodeInfo)) {
            return document.getElementById(nodeInfo);
        }
        if (Ext.isNumber(nodeInfo)) {
            return this.all.elements[nodeInfo];
        }
        if (nodeInfo.isModel) {
            return this.getNodeByRecord(nodeInfo);
        }
        return nodeInfo; 
    },

    
    getNodeByRecord: function(record) {
        var ns = this.all.elements,
            ln = ns.length,
            i = 0;

        for (; i < ln; i++) {
            if (ns[i].viewRecordId === record.internalId) {
                return ns[i];
            }
        }

        return null;
    },

    
    getNodes: function(start, end) {
        var ns = this.all.elements;

        if (end === undefined) {
            end = ns.length;
        } else {
            end++;
        }
        return this.all.elements.slice(start||0, end);
    },

    
    indexOf: function(node) {
        node = this.getNode(node);
        if (!node && node !== 0) {
            return -1;
        }
        if (Ext.isNumber(node.viewIndex)) {
            return node.viewIndex;
        }
        return this.all.indexOf(node);
    },

    onDestroy : function() {
        var me = this;

        me.all.clear();
        me.callParent();
        me.bindStore(null);
        me.selModel.destroy();
    },

    
    onItemSelect: function(record) {
        var node = this.getNode(record);

        if (node) {
            Ext.fly(node).addCls(this.selectedItemCls);
        }
    },

    
    onItemDeselect: function(record) {
        var node = this.getNode(record);

        if (node) {
            Ext.fly(node).removeCls(this.selectedItemCls);
        }
    },

    getItemSelector: function() {
        return this.itemSelector;
    }
}, function() {
    
    
    
    
    Ext.deprecate('extjs', '4.0', function() {
        Ext.view.AbstractView.override({
            
            
            

            
            getSelectionCount : function(){
                if (Ext.global.console) {
                    Ext.global.console.warn("DataView: getSelectionCount will be removed, please interact with the Ext.selection.DataViewModel");
                }
                return this.selModel.getSelection().length;
            },

            
            getSelectedRecords : function(){
                if (Ext.global.console) {
                    Ext.global.console.warn("DataView: getSelectedRecords will be removed, please interact with the Ext.selection.DataViewModel");
                }
                return this.selModel.getSelection();
            },

            select: function(records, keepExisting, supressEvents) {
                if (Ext.global.console) {
                    Ext.global.console.warn("DataView: select will be removed, please access select through a DataView's SelectionModel, ie: view.getSelectionModel().select()");
                }
                var sm = this.getSelectionModel();
                return sm.select.apply(sm, arguments);
            },

            
            clearSelections: function() {
                if (Ext.global.console) {
                    Ext.global.console.warn("DataView: clearSelections will be removed, please access deselectAll through DataView's SelectionModel, ie: view.getSelectionModel().deselectAll()");
                }
                var sm = this.getSelectionModel();
                return sm.deselectAll();
            }
        });
    });
});


Ext.define('Ext.Shadow', {
    requires: ['Ext.ShadowPool'],

    
    constructor: function(config) {
        var me = this,
            adjusts,
            offset,
            rad;
        
        Ext.apply(me, config);
        if (!Ext.isString(me.mode)) {
            me.mode = me.defaultMode;
        }
        offset = me.offset;
        rad = Math.floor(offset / 2);
        me.opacity = 50;
        switch (me.mode.toLowerCase()) {
            
            case "drop":
                if (Ext.supports.CSS3BoxShadow) {
                    adjusts = {
                        t: offset,
                        l: offset,
                        h: -offset,
                        w: -offset
                    };
                }
                else {
                    adjusts = {
                        t: -rad,
                        l: -rad,
                        h: -rad,
                        w: -rad
                    };
                }
                break;
            case "sides":
                if (Ext.supports.CSS3BoxShadow) {
                    adjusts = {
                        t: offset,
                        l: 0,
                        h: -offset,
                        w: 0
                    };
                }
                else {
                    adjusts = {
                        t: - (1 + rad),
                        l: 1 + rad - 2 * offset,
                        h: -1,
                        w: rad - 1
                    };
                }
                break;
            case "frame":
                if (Ext.supports.CSS3BoxShadow) {
                    adjusts = {
                        t: 0,
                        l: 0,
                        h: 0,
                        w: 0
                    };
                }
                else {
                    adjusts = {
                        t: 1 + rad - 2 * offset,
                        l: 1 + rad - 2 * offset,
                        h: offset - rad - 1,
                        w: offset - rad - 1
                    };
                }
                break;
        }
        me.adjusts = adjusts;
    },

    
    getShadowSize: function() {
        var me = this,
            offset = me.el ? me.offset : 0,
            result = [offset, offset, offset, offset],
            mode = me.mode.toLowerCase();

        
        if (me.el && mode !== 'frame') {
            result[0] = 0;
            if (mode == 'drop') {
                result[3] = 0;
            }
        }
        return result;
    },

    

    
    offset: 4,

    
    defaultMode: "drop",

    
    boxShadowProperty: (function() {
        var property = 'boxShadow',
            style = document.documentElement.style;

        if (!('boxShadow' in style)) {
            if ('WebkitBoxShadow' in style) {
                
                property = 'WebkitBoxShadow';
            }
            else if ('MozBoxShadow' in style) {
                
                property = 'MozBoxShadow';
            }
        }

        return property;
    }()),

    
    show: function(target) {
        var me = this,
            index;
        
        target = Ext.get(target);
        if (!me.el) {
            me.el = Ext.ShadowPool.pull();
            if (me.el.dom.nextSibling != target.dom) {
                me.el.insertBefore(target);
            }
        }
        index = (parseInt(target.getStyle("z-index"), 10) - 1) || 0;
        me.el.setStyle("z-index", me.zIndex || index);
        if (Ext.isIE && !Ext.supports.CSS3BoxShadow) {
            me.el.dom.style.filter = "progid:DXImageTransform.Microsoft.alpha(opacity=" + me.opacity + ") progid:DXImageTransform.Microsoft.Blur(pixelradius=" + (me.offset) + ")";
        }
        me.realign(
            target.getLocalX(),
            target.getLocalY(),
            target.dom.offsetWidth,
            target.dom.offsetHeight
        );
        me.el.dom.style.display = "block";
    },

    
    isVisible: function() {
        return this.el ? true: false;
    },

    
    realign: function(l, t, targetWidth, targetHeight) {
        if (!this.el) {
            return;
        }
        var adjusts = this.adjusts,
            d = this.el.dom,
            targetStyle = d.style,
            shadowWidth,
            shadowHeight,
            sws,
            shs;

        targetStyle.left = (l + adjusts.l) + "px";
        targetStyle.top = (t + adjusts.t) + "px";
        shadowWidth = Math.max(targetWidth + adjusts.w, 0);
        shadowHeight = Math.max(targetHeight + adjusts.h, 0);
        sws = shadowWidth + "px";
        shs = shadowHeight + "px";
        if (targetStyle.width != sws || targetStyle.height != shs) {
            targetStyle.width = sws;
            targetStyle.height = shs;

            if (Ext.supports.CSS3BoxShadow) {
                targetStyle[this.boxShadowProperty] = '0 0 ' + this.offset + 'px #888';
            }
        }
    },

    
    hide: function() {
        var me = this;
        
        if (me.el) {
            me.el.dom.style.display = "none";
            Ext.ShadowPool.push(me.el);
            delete me.el;
        }
    },

    
    setZIndex: function(z) {
        this.zIndex = z;
        if (this.el) {
            this.el.setStyle("z-index", z);
        }
    },
    
    
    setOpacity: function(opacity){
        if (this.el) {
            if (Ext.isIE && !Ext.supports.CSS3BoxShadow) {
                opacity = Math.floor(opacity * 100 / 2) / 100;
            }
            this.opacity = opacity;
            this.el.setOpacity(opacity);
        }
    }
});




Ext.define('Ext.dd.DragDrop', {
    requires: ['Ext.dd.DragDropManager'],

    
    constructor: function(id, sGroup, config) {
        if(id) {
            this.init(id, sGroup, config);
        }
    },

    

    
    id: null,

    
    config: null,

    
    dragElId: null,

    
    handleElId: null,

    
    invalidHandleTypes: null,

    
    invalidHandleIds: null,

    
    invalidHandleClasses: null,

    
    startPageX: 0,

    
    startPageY: 0,

    
    groups: null,

    
    locked: false,

    
    lock: function() {
        this.locked = true;
    },

    
    moveOnly: false,

    
    unlock: function() {
        this.locked = false;
    },

    
    isTarget: true,

    
    padding: null,

    
    _domRef: null,

    
    __ygDragDrop: true,

    
    constrainX: false,

    
    constrainY: false,

    
    minX: 0,

    
    maxX: 0,

    
    minY: 0,

    
    maxY: 0,

    
    maintainOffset: false,

    
    xTicks: null,

    
    yTicks: null,

    
    primaryButtonOnly: true,

    
    available: false,

    
    hasOuterHandles: false,

    
    b4StartDrag: function(x, y) { },

    
    startDrag: function(x, y) {  },

    
    b4Drag: function(e) { },

    
    onDrag: function(e) {  },

    
    onDragEnter: function(e, id) {  },

    
    b4DragOver: function(e) { },

    
    onDragOver: function(e, id) {  },

    
    b4DragOut: function(e) { },

    
    onDragOut: function(e, id) {  },

    
    b4DragDrop: function(e) { },

    
    onDragDrop: function(e, id) {  },

    
    onInvalidDrop: function(e) {  },

    
    b4EndDrag: function(e) { },

    
    endDrag: function(e) {  },

    
    b4MouseDown: function(e) {  },

    
    onMouseDown: function(e) {  },

    
    onMouseUp: function(e) {  },

    
    onAvailable: function () {
    },

    
    defaultPadding: {
        left: 0,
        right: 0,
        top: 0,
        bottom: 0
    },

    
    constrainTo : function(constrainTo, pad, inContent){
        if(Ext.isNumber(pad)){
            pad = {left: pad, right:pad, top:pad, bottom:pad};
        }
        pad = pad || this.defaultPadding;
        var b = Ext.get(this.getEl()).getBox(),
            ce = Ext.get(constrainTo),
            s = ce.getScroll(),
            c,
            cd = ce.dom,
            xy,
            topSpace,
            leftSpace;
        if(cd == document.body){
            c = { x: s.left, y: s.top, width: Ext.Element.getViewWidth(), height: Ext.Element.getViewHeight()};
        }else{
            xy = ce.getXY();
            c = {x : xy[0], y: xy[1], width: cd.clientWidth, height: cd.clientHeight};
        }

        topSpace = b.y - c.y;
        leftSpace = b.x - c.x;

        this.resetConstraints();
        this.setXConstraint(leftSpace - (pad.left||0), 
                c.width - leftSpace - b.width - (pad.right||0), 
        this.xTickSize
        );
        this.setYConstraint(topSpace - (pad.top||0), 
                c.height - topSpace - b.height - (pad.bottom||0), 
        this.yTickSize
        );
    },

    
    getEl: function() {
        if (!this._domRef) {
            this._domRef = Ext.getDom(this.id);
        }

        return this._domRef;
    },

    
    getDragEl: function() {
        return Ext.getDom(this.dragElId);
    },

    
    init: function(id, sGroup, config) {
        this.initTarget(id, sGroup, config);
        Ext.EventManager.on(this.id, "mousedown", this.handleMouseDown, this);
        
    },

    
    initTarget: function(id, sGroup, config) {
        
        this.config = config || {};

        
        this.DDMInstance = Ext.dd.DragDropManager;
        
        this.groups = {};

        
        
        if (typeof id !== "string") {
            id = Ext.id(id);
        }

        
        this.id = id;

        
        this.addToGroup((sGroup) ? sGroup : "default");

        
        
        this.handleElId = id;

        
        this.setDragElId(id);

        
        this.invalidHandleTypes = { A: "A" };
        this.invalidHandleIds = {};
        this.invalidHandleClasses = [];

        this.applyConfig();

        this.handleOnAvailable();
    },

    
    applyConfig: function() {

        
        
        this.padding           = this.config.padding || [0, 0, 0, 0];
        this.isTarget          = (this.config.isTarget !== false);
        this.maintainOffset    = (this.config.maintainOffset);
        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);

    },

    
    handleOnAvailable: function() {
        this.available = true;
        this.resetConstraints();
        this.onAvailable();
    },

    
    setPadding: function(iTop, iRight, iBot, iLeft) {
        
        if (!iRight && 0 !== iRight) {
            this.padding = [iTop, iTop, iTop, iTop];
        } else if (!iBot && 0 !== iBot) {
            this.padding = [iTop, iRight, iTop, iRight];
        } else {
            this.padding = [iTop, iRight, iBot, iLeft];
        }
    },

    
    setInitPosition: function(diffX, diffY) {
        var el = this.getEl(),
            dx, dy, p;

        if (!this.DDMInstance.verifyEl(el)) {
            return;
        }

        dx = diffX || 0;
        dy = diffY || 0;

        p = Ext.Element.getXY( el );

        this.initPageX = p[0] - dx;
        this.initPageY = p[1] - dy;

        this.lastPageX = p[0];
        this.lastPageY = p[1];

        this.setStartPosition(p);
    },

    
    setStartPosition: function(pos) {
        var p = pos || Ext.Element.getXY( this.getEl() );
        this.deltaSetXY = null;

        this.startPageX = p[0];
        this.startPageY = p[1];
    },

    
    addToGroup: function(sGroup) {
        this.groups[sGroup] = true;
        this.DDMInstance.regDragDrop(this, sGroup);
    },

    
    removeFromGroup: function(sGroup) {
        if (this.groups[sGroup]) {
            delete this.groups[sGroup];
        }

        this.DDMInstance.removeDDFromGroup(this, sGroup);
    },

    
    setDragElId: function(id) {
        this.dragElId = id;
    },

    
    setHandleElId: function(id) {
        if (typeof id !== "string") {
            id = Ext.id(id);
        }
        this.handleElId = id;
        this.DDMInstance.regHandle(this.id, id);
    },

    
    setOuterHandleElId: function(id) {
        if (typeof id !== "string") {
            id = Ext.id(id);
        }
        Ext.EventManager.on(id, "mousedown", this.handleMouseDown, this);
        this.setHandleElId(id);

        this.hasOuterHandles = true;
    },

    
    unreg: function() {
        Ext.EventManager.un(this.id, "mousedown", this.handleMouseDown, this);
        this._domRef = null;
        this.DDMInstance._remove(this);
    },

    destroy : function(){
        this.unreg();
    },

    
    isLocked: function() {
        return (this.DDMInstance.isLocked() || this.locked);
    },

    
    handleMouseDown: function(e, oDD){
        if (this.primaryButtonOnly && e.button != 0) {
            return;
        }

        if (this.isLocked()) {
            return;
        }

        this.DDMInstance.refreshCache(this.groups);

        if (this.hasOuterHandles || this.DDMInstance.isOverTarget(e.getPoint(), this) )  {
            if (this.clickValidator(e)) {
                
                this.setStartPosition();
                this.b4MouseDown(e);
                this.onMouseDown(e);

                this.DDMInstance.handleMouseDown(e, this);

                this.DDMInstance.stopEvent(e);
            }
        }
    },

    clickValidator: function(e) {
        var target = e.getTarget();
        return ( this.isValidHandleChild(target) &&
                    (this.id == this.handleElId ||
                        this.DDMInstance.handleWasClicked(target, this.id)) );
    },

    
    addInvalidHandleType: function(tagName) {
        var type = tagName.toUpperCase();
        this.invalidHandleTypes[type] = type;
    },

    
    addInvalidHandleId: function(id) {
        if (typeof id !== "string") {
            id = Ext.id(id);
        }
        this.invalidHandleIds[id] = id;
    },

    
    addInvalidHandleClass: function(cssClass) {
        this.invalidHandleClasses.push(cssClass);
    },

    
    removeInvalidHandleType: function(tagName) {
        var type = tagName.toUpperCase();
        
        delete this.invalidHandleTypes[type];
    },

    
    removeInvalidHandleId: function(id) {
        if (typeof id !== "string") {
            id = Ext.id(id);
        }
        delete this.invalidHandleIds[id];
    },

    
    removeInvalidHandleClass: function(cssClass) {
        for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
            if (this.invalidHandleClasses[i] == cssClass) {
                delete this.invalidHandleClasses[i];
            }
        }
    },

    
    isValidHandleChild: function(node) {

        var valid = true,
            nodeName,
            i, len;
        
        try {
            nodeName = node.nodeName.toUpperCase();
        } catch(e) {
            nodeName = node.nodeName;
        }
        valid = valid && !this.invalidHandleTypes[nodeName];
        valid = valid && !this.invalidHandleIds[node.id];

        for (i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
            valid = !Ext.fly(node).hasCls(this.invalidHandleClasses[i]);
        }


        return valid;

    },

    
    setXTicks: function(iStartX, iTickSize) {
        this.xTicks = [];
        this.xTickSize = iTickSize;

        var tickMap = {},
            i;

        for (i = this.initPageX; i >= this.minX; i = i - iTickSize) {
            if (!tickMap[i]) {
                this.xTicks[this.xTicks.length] = i;
                tickMap[i] = true;
            }
        }

        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
            if (!tickMap[i]) {
                this.xTicks[this.xTicks.length] = i;
                tickMap[i] = true;
            }
        }

        Ext.Array.sort(this.xTicks, this.DDMInstance.numericSort);
    },

    
    setYTicks: function(iStartY, iTickSize) {
        this.yTicks = [];
        this.yTickSize = iTickSize;

        var tickMap = {},
            i;

        for (i = this.initPageY; i >= this.minY; i = i - iTickSize) {
            if (!tickMap[i]) {
                this.yTicks[this.yTicks.length] = i;
                tickMap[i] = true;
            }
        }

        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
            if (!tickMap[i]) {
                this.yTicks[this.yTicks.length] = i;
                tickMap[i] = true;
            }
        }

        Ext.Array.sort(this.yTicks, this.DDMInstance.numericSort);
    },

    
    setXConstraint: function(iLeft, iRight, iTickSize) {
        this.leftConstraint = iLeft;
        this.rightConstraint = iRight;

        this.minX = this.initPageX - iLeft;
        this.maxX = this.initPageX + iRight;
        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }

        this.constrainX = true;
    },

    
    clearConstraints: function() {
        this.constrainX = false;
        this.constrainY = false;
        this.clearTicks();
    },

    
    clearTicks: function() {
        this.xTicks = null;
        this.yTicks = null;
        this.xTickSize = 0;
        this.yTickSize = 0;
    },

    
    setYConstraint: function(iUp, iDown, iTickSize) {
        this.topConstraint = iUp;
        this.bottomConstraint = iDown;

        this.minY = this.initPageY - iUp;
        this.maxY = this.initPageY + iDown;
        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }

        this.constrainY = true;

    },

    
    resetConstraints: function() {
        
        if (this.initPageX || this.initPageX === 0) {
            
            var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0,
                dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;

            this.setInitPosition(dx, dy);

        
        } else {
            this.setInitPosition();
        }

        if (this.constrainX) {
            this.setXConstraint( this.leftConstraint,
                                 this.rightConstraint,
                                 this.xTickSize        );
        }

        if (this.constrainY) {
            this.setYConstraint( this.topConstraint,
                                 this.bottomConstraint,
                                 this.yTickSize         );
        }
    },

    
    getTick: function(val, tickArray) {
        if (!tickArray) {
            
            
            return val;
        } else if (tickArray[0] >= val) {
            
            
            return tickArray[0];
        } else {
            var i, len, next, diff1, diff2;
            for (i=0, len=tickArray.length; i<len; ++i) {
                next = i + 1;
                if (tickArray[next] && tickArray[next] >= val) {
                    diff1 = val - tickArray[i];
                    diff2 = tickArray[next] - val;
                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
                }
            }

            
            
            return tickArray[tickArray.length - 1];
        }
    },

    
    toString: function() {
        return ("DragDrop " + this.id);
    }

});





Ext.define('Ext.dd.DD', {
    extend: 'Ext.dd.DragDrop',
    requires: ['Ext.dd.DragDropManager'],

    
    constructor: function(id, sGroup, config) {
        if (id) {
            this.init(id, sGroup, config);
        }
    },

    
    scroll: true,

    
    autoOffset: function(iPageX, iPageY) {
        var x = iPageX - this.startPageX,
            y = iPageY - this.startPageY;
        this.setDelta(x, y);
    },

    
    setDelta: function(iDeltaX, iDeltaY) {
        this.deltaX = iDeltaX;
        this.deltaY = iDeltaY;
    },

    
    setDragElPos: function(iPageX, iPageY) {
        
        

        var el = this.getDragEl();
        this.alignElWithMouse(el, iPageX, iPageY);
    },

    
    alignElWithMouse: function(el, iPageX, iPageY) {
        var oCoord = this.getTargetCoord(iPageX, iPageY),
            fly = el.dom ? el : Ext.fly(el, '_dd'),
            elSize = fly.getSize(),
            EL = Ext.Element,
            vpSize,
            aCoord,
            newLeft,
            newTop;

        if (!this.deltaSetXY) {
            vpSize = this.cachedViewportSize = { width: EL.getDocumentWidth(), height: EL.getDocumentHeight() };
            aCoord = [
                Math.max(0, Math.min(oCoord.x, vpSize.width - elSize.width)),
                Math.max(0, Math.min(oCoord.y, vpSize.height - elSize.height))
            ];
            fly.setXY(aCoord);
            newLeft = fly.getLocalX();
            newTop  = fly.getLocalY();
            this.deltaSetXY = [newLeft - oCoord.x, newTop - oCoord.y];
        } else {
            vpSize = this.cachedViewportSize;
            fly.setLeftTop(
                Math.max(0, Math.min(oCoord.x + this.deltaSetXY[0], vpSize.width - elSize.width)),
                Math.max(0, Math.min(oCoord.y + this.deltaSetXY[1], vpSize.height - elSize.height))
            );
        }

        this.cachePosition(oCoord.x, oCoord.y);
        this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
        return oCoord;
    },

    
    cachePosition: function(iPageX, iPageY) {
        if (iPageX) {
            this.lastPageX = iPageX;
            this.lastPageY = iPageY;
        } else {
            var aCoord = Ext.Element.getXY(this.getEl());
            this.lastPageX = aCoord[0];
            this.lastPageY = aCoord[1];
        }
    },

    
    autoScroll: function(x, y, h, w) {

        if (this.scroll) {
            
            var clientH = Ext.Element.getViewHeight(),
                
                clientW = Ext.Element.getViewWidth(),
                
                st = this.DDMInstance.getScrollTop(),
                
                sl = this.DDMInstance.getScrollLeft(),
                
                bot = h + y,
                
                right = w + x,
                
                
                
                toBot = (clientH + st - y - this.deltaY),
                
                toRight = (clientW + sl - x - this.deltaX),
                
                
                thresh = 40,
                
                
                
                scrAmt = (document.all) ? 80 : 30;

            
            
            if ( bot > clientH && toBot < thresh ) {
                window.scrollTo(sl, st + scrAmt);
            }

            
            
            if ( y < st && st > 0 && y - st < thresh ) {
                window.scrollTo(sl, st - scrAmt);
            }

            
            
            if ( right > clientW && toRight < thresh ) {
                window.scrollTo(sl + scrAmt, st);
            }

            
            
            if ( x < sl && sl > 0 && x - sl < thresh ) {
                window.scrollTo(sl - scrAmt, st);
            }
        }
    },

    
    getTargetCoord: function(iPageX, iPageY) {
        var x = iPageX - this.deltaX,
            y = iPageY - this.deltaY;

        if (this.constrainX) {
            if (x < this.minX) {
                x = this.minX;
            }
            if (x > this.maxX) {
                x = this.maxX;
            }
        }

        if (this.constrainY) {
            if (y < this.minY) {
                y = this.minY;
            }
            if (y > this.maxY) {
                y = this.maxY;
            }
        }

        x = this.getTick(x, this.xTicks);
        y = this.getTick(y, this.yTicks);


        return {x: x, y: y};
    },

    
    applyConfig: function() {
        this.callParent();
        this.scroll = (this.config.scroll !== false);
    },

    
    b4MouseDown: function(e) {
        
        this.autoOffset(e.getPageX(), e.getPageY());
    },

    
    b4Drag: function(e) {
        this.setDragElPos(e.getPageX(), e.getPageY());
    },

    toString: function() {
        return ("DD " + this.id);
    }

    
    
    
    

});




Ext.define('Ext.dd.DDProxy', {
    extend: 'Ext.dd.DD',

    statics: {
        
        dragElId: "ygddfdiv"
    },

    
    constructor: function(id, sGroup, config) {
        if (id) {
            this.init(id, sGroup, config);
            this.initFrame();
        }
    },

    
    resizeFrame: true,

    
    centerFrame: false,

    
    createFrame: function() {
        var self = this,
            body = document.body,
            div,
            s;

        if (!body || !body.firstChild) {
            setTimeout( function() { self.createFrame(); }, 50 );
            return;
        }

        div = this.getDragEl();

        if (!div) {
            div    = document.createElement("div");
            div.id = this.dragElId;
            s  = div.style;

            s.position   = "absolute";
            s.visibility = "hidden";
            s.cursor     = "move";
            s.border     = "2px solid #aaa";
            s.zIndex     = 999;

            
            
            
            body.insertBefore(div, body.firstChild);
        }
    },

    
    initFrame: function() {
        this.createFrame();
    },

    applyConfig: function() {
        this.callParent();

        this.resizeFrame = (this.config.resizeFrame !== false);
        this.centerFrame = (this.config.centerFrame);
        this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId);
    },

    
    showFrame: function(iPageX, iPageY) {
        var el = this.getEl(),
            dragEl = this.getDragEl(),
            s = dragEl.style;

        this._resizeProxy();

        if (this.centerFrame) {
            this.setDelta( Math.round(parseInt(s.width,  10)/2),
                           Math.round(parseInt(s.height, 10)/2) );
        }

        this.setDragElPos(iPageX, iPageY);

        Ext.fly(dragEl).show();
    },

    
    _resizeProxy: function() {
        if (this.resizeFrame) {
            var el = this.getEl();
            Ext.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
        }
    },

    
    b4MouseDown: function(e) {
        var x = e.getPageX(),
            y = e.getPageY();
        this.autoOffset(x, y);
        this.setDragElPos(x, y);
    },

    
    b4StartDrag: function(x, y) {
        
        this.showFrame(x, y);
    },

    
    b4EndDrag: function(e) {
        Ext.fly(this.getDragEl()).hide();
    },

    
    
    
    endDrag: function(e) {

        var lel = this.getEl(),
            del = this.getDragEl();

        
        del.style.visibility = "";

        this.beforeMove();
        
        
        lel.style.visibility = "hidden";
        Ext.dd.DDM.moveToEl(lel, del);
        del.style.visibility = "hidden";
        lel.style.visibility = "";

        this.afterDrag();
    },

    beforeMove : function(){

    },

    afterDrag : function(){

    },

    toString: function() {
        return ("DDProxy " + this.id);
    }

});





Ext.define('Ext.dd.DDTarget', {
    extend: 'Ext.dd.DragDrop',

    
    constructor: function(id, sGroup, config) {
        if (id) {
            this.initTarget(id, sGroup, config);
        }
    },

    
    getDragEl: Ext.emptyFn,
    
    isValidHandleChild: Ext.emptyFn,
    
    startDrag: Ext.emptyFn,
    
    endDrag: Ext.emptyFn,
    
    onDrag: Ext.emptyFn,
    
    onDragDrop: Ext.emptyFn,
    
    onDragEnter: Ext.emptyFn,
    
    onDragOut: Ext.emptyFn,
    
    onDragOver: Ext.emptyFn,
    
    onInvalidDrop: Ext.emptyFn,
    
    onMouseDown: Ext.emptyFn,
    
    onMouseUp: Ext.emptyFn,
    
    setXConstraint: Ext.emptyFn,
    
    setYConstraint: Ext.emptyFn,
    
    resetConstraints: Ext.emptyFn,
    
    clearConstraints: Ext.emptyFn,
    
    clearTicks: Ext.emptyFn,
    
    setInitPosition: Ext.emptyFn,
    
    setDragElId: Ext.emptyFn,
    
    setHandleElId: Ext.emptyFn,
    
    setOuterHandleElId: Ext.emptyFn,
    
    addInvalidHandleClass: Ext.emptyFn,
    
    addInvalidHandleId: Ext.emptyFn,
    
    addInvalidHandleType: Ext.emptyFn,
    
    removeInvalidHandleClass: Ext.emptyFn,
    
    removeInvalidHandleId: Ext.emptyFn,
    
    removeInvalidHandleType: Ext.emptyFn,

    toString: function() {
        return ("DDTarget " + this.id);
    }
});

Ext.define('Ext.dd.DropTarget', {
    extend: 'Ext.dd.DDTarget',
    requires: ['Ext.dd.ScrollManager'],

    
    constructor : function(el, config){
        this.el = Ext.get(el);

        Ext.apply(this, config);

        if(this.containerScroll){
            Ext.dd.ScrollManager.register(this.el);
        }

        this.callParent([this.el.dom, this.ddGroup || this.group,
              {isTarget: true}]);
    },

    
    
    
    dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',
    
    dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',

    
    isTarget : true,

    
    isNotifyTarget : true,

    
    notifyEnter : function(dd, e, data){
        if(this.overClass){
            this.el.addCls(this.overClass);
        }
        return this.dropAllowed;
    },

    
    notifyOver : function(dd, e, data){
        return this.dropAllowed;
    },

    
    notifyOut : function(dd, e, data){
        if(this.overClass){
            this.el.removeCls(this.overClass);
        }
    },

    
    notifyDrop : function(dd, e, data){
        return false;
    },

    destroy : function(){
        this.callParent();
        if(this.containerScroll){
            Ext.dd.ScrollManager.unregister(this.el);
        }
    }
});


Ext.define('Ext.dd.DropZone', {
    extend: 'Ext.dd.DropTarget',
    requires: ['Ext.dd.Registry'],

    
    getTargetFromEvent : function(e){
        return Ext.dd.Registry.getTargetFromEvent(e);
    },

    
    onNodeEnter : function(n, dd, e, data){
        
    },

    
    onNodeOver : function(n, dd, e, data){
        return this.dropAllowed;
    },

    
    onNodeOut : function(n, dd, e, data){
        
    },

    
    onNodeDrop : function(n, dd, e, data){
        return false;
    },

    
    onContainerOver : function(dd, e, data){
        return this.dropNotAllowed;
    },

    
    onContainerDrop : function(dd, e, data){
        return false;
    },

    
    notifyEnter : function(dd, e, data){
        return this.dropNotAllowed;
    },

    
    notifyOver : function(dd, e, data){
        var n = this.getTargetFromEvent(e);
        if(!n) { 
            if(this.lastOverNode){
                this.onNodeOut(this.lastOverNode, dd, e, data);
                this.lastOverNode = null;
            }
            return this.onContainerOver(dd, e, data);
        }
        if(this.lastOverNode != n){
            if(this.lastOverNode){
                this.onNodeOut(this.lastOverNode, dd, e, data);
            }
            this.onNodeEnter(n, dd, e, data);
            this.lastOverNode = n;
        }
        return this.onNodeOver(n, dd, e, data);
    },

    
    notifyOut : function(dd, e, data){
        if(this.lastOverNode){
            this.onNodeOut(this.lastOverNode, dd, e, data);
            this.lastOverNode = null;
        }
    },

    
    notifyDrop : function(dd, e, data){
        if(this.lastOverNode){
            this.onNodeOut(this.lastOverNode, dd, e, data);
            this.lastOverNode = null;
        }
        var n = this.getTargetFromEvent(e);
        return n ?
            this.onNodeDrop(n, dd, e, data) :
            this.onContainerDrop(dd, e, data);
    },

    
    triggerCacheRefresh : function() {
        Ext.dd.DDM.refreshCache(this.groups);
    }
});

Ext.define('Ext.dd.StatusProxy', {
    extend: 'Ext.Component',
    animRepair: false,

    childEls: [
        'ghost'
    ],

    renderTpl: [
        '<div class="' + Ext.baseCSSPrefix + 'dd-drop-icon"></div>' +
        '<div id="{id}-ghost" class="' + Ext.baseCSSPrefix + 'dd-drag-ghost"></div>'
    ],

    
    constructor: function(config) {
        var me = this;

        config = config || {};

        Ext.apply(me, {
            hideMode: 'visibility',
            hidden: true,
            floating: true,
            id: me.id || Ext.id(),
            cls: Ext.baseCSSPrefix + 'dd-drag-proxy ' + this.dropNotAllowed,
            shadow: config.shadow || false,
            renderTo: Ext.getDetachedBody()
        });
        me.callParent(arguments);
        this.dropStatus = this.dropNotAllowed;
    },

    
    dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',

    
    dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',

    
    setStatus : function(cssClass){
        cssClass = cssClass || this.dropNotAllowed;
        if (this.dropStatus != cssClass) {
            this.el.replaceCls(this.dropStatus, cssClass);
            this.dropStatus = cssClass;
        }
    },

    
    reset : function(clearGhost){
        var me = this,
            clsPrefix = Ext.baseCSSPrefix + 'dd-drag-proxy ';

        me.el.replaceCls(clsPrefix + me.dropAllowed, clsPrefix + me.dropNotAllowed);
        me.dropStatus = me.dropNotAllowed;
        if (clearGhost) {
            me.ghost.update('');
        }
    },

    
    update : function(html){
        if (typeof html == "string") {
            this.ghost.update(html);
        } else {
            this.ghost.update("");
            html.style.margin = "0";
            this.ghost.dom.appendChild(html);
        }
        var el = this.ghost.dom.firstChild;
        if (el) {
            Ext.fly(el).setStyle('float', 'none');
        }
    },

    
    getGhost : function(){
        return this.ghost;
    },

    
    hide : function(clear) {
        this.callParent();
        if (clear) {
            this.reset(true);
        }
    },

    
    stop : function(){
        if (this.anim && this.anim.isAnimated && this.anim.isAnimated()) {
            this.anim.stop();
        }
    },

    
    sync : function(){
        this.el.sync();
    },

    
    repair : function(xy, callback, scope) {
        var me = this;

        me.callback = callback;
        me.scope = scope;
        if (xy && me.animRepair !== false) {
            me.el.addCls(Ext.baseCSSPrefix + 'dd-drag-repair');
            me.el.hideUnders(true);
            me.anim = me.el.animate({
                duration: me.repairDuration || 500,
                easing: 'ease-out',
                to: {
                    x: xy[0],
                    y: xy[1]
                },
                stopAnimation: true,
                callback: me.afterRepair,
                scope: me
            });
        } else {
            me.afterRepair();
        }
    },

    
    afterRepair : function() {
        var me = this;
    
        me.hide(true);
        me.el.removeCls(Ext.baseCSSPrefix + 'dd-drag-repair');
        if (typeof me.callback == "function") {
            me.callback.call(me.scope || me);
        }
        delete me.callback;
        delete me.scope;
    }
});


Ext.define('Ext.dd.DragSource', {
    extend: 'Ext.dd.DDProxy',
    requires: [
        'Ext.dd.StatusProxy',
        'Ext.dd.DragDropManager'
    ],

    

    
    dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',
    
    dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',

    
    animRepair: true,

    
    repairHighlightColor: 'c3daf9',

    
    constructor: function(el, config) {
        this.el = Ext.get(el);
        if(!this.dragData){
            this.dragData = {};
        }

        Ext.apply(this, config);

        if(!this.proxy){
            this.proxy = new Ext.dd.StatusProxy({
                id: this.el.id + '-drag-status-proxy',
                animRepair: this.animRepair
            });
        }
        this.callParent([this.el.dom, this.ddGroup || this.group,
              {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true}]);

        this.dragging = false;
    },

    
    getDragData : function(e){
        return this.dragData;
    },

    
    onDragEnter : function(e, id){
        var target = Ext.dd.DragDropManager.getDDById(id),
            status;
        this.cachedTarget = target;
        if (this.beforeDragEnter(target, e, id) !== false) {
            if (target.isNotifyTarget) {
                status = target.notifyEnter(this, e, this.dragData);
                this.proxy.setStatus(status);
            } else {
                this.proxy.setStatus(this.dropAllowed);
            }

            if (this.afterDragEnter) {
                
                this.afterDragEnter(target, e, id);
            }
        }
    },

    
    beforeDragEnter: function(target, e, id) {
        return true;
    },

    
    onDragOver: function(e, id) {
        var target = this.cachedTarget || Ext.dd.DragDropManager.getDDById(id),
            status;
        if (this.beforeDragOver(target, e, id) !== false) {
            if(target.isNotifyTarget){
                status = target.notifyOver(this, e, this.dragData);
                this.proxy.setStatus(status);
            }

            if (this.afterDragOver) {
                
                this.afterDragOver(target, e, id);
            }
        }
    },

    
    beforeDragOver: function(target, e, id) {
        return true;
    },

    
    onDragOut: function(e, id) {
        var target = this.cachedTarget || Ext.dd.DragDropManager.getDDById(id);
        if (this.beforeDragOut(target, e, id) !== false) {
            if (target.isNotifyTarget) {
                target.notifyOut(this, e, this.dragData);
            }
            this.proxy.reset();
            if (this.afterDragOut) {
                
                this.afterDragOut(target, e, id);
            }
        }
        this.cachedTarget = null;
    },

    
    beforeDragOut: function(target, e, id){
        return true;
    },

    
    onDragDrop: function(e, id){
        var target = this.cachedTarget || Ext.dd.DragDropManager.getDDById(id);
        if (this.beforeDragDrop(target, e, id) !== false) {
            if (target.isNotifyTarget) {
                if (target.notifyDrop(this, e, this.dragData) !== false) { 
                    this.onValidDrop(target, e, id);
                } else {
                    this.onInvalidDrop(target, e, id);
                }
            } else {
                this.onValidDrop(target, e, id);
            }

            if (this.afterDragDrop) {
                
                this.afterDragDrop(target, e, id);
            }
        }
        delete this.cachedTarget;
    },

    
    beforeDragDrop: function(target, e, id){
        return true;
    },

    
    onValidDrop: function(target, e, id){
        this.hideProxy();
        if(this.afterValidDrop){
            
            this.afterValidDrop(target, e, id);
        }
    },

    
    getRepairXY: function(e, data){
        return this.el.getXY();
    },

    
    onInvalidDrop: function(target, e, id) {
        
        
        
        if (!e) {
            e = target;
            target = null;
            id = e.getTarget().id;
        }
        this.beforeInvalidDrop(target, e, id);
        if (this.cachedTarget) {
            if(this.cachedTarget.isNotifyTarget){
                this.cachedTarget.notifyOut(this, e, this.dragData);
            }
            this.cacheTarget = null;
        }
        this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);

        if (this.afterInvalidDrop) {
            
            this.afterInvalidDrop(e, id);
        }
    },

    
    afterRepair: function() {
        var me = this;
        if (Ext.enableFx) {
            me.el.highlight(me.repairHighlightColor);
        }
        me.dragging = false;
    },

    
    beforeInvalidDrop: function(target, e, id) {
        return true;
    },

    
    handleMouseDown: function(e) {
        if (this.dragging) {
            return;
        }
        var data = this.getDragData(e);
        if (data && this.onBeforeDrag(data, e) !== false) {
            this.dragData = data;
            this.proxy.stop();
            this.callParent(arguments);
        }
    },

    
    onBeforeDrag: function(data, e){
        return true;
    },

    
    onStartDrag: Ext.emptyFn,

    alignElWithMouse: function() {
        this.proxy.ensureAttachedToBody(true);
        return this.callParent(arguments);
    },

    
    startDrag: function(x, y) {
        this.proxy.reset();
        this.proxy.hidden = false;
        this.dragging = true;
        this.proxy.update("");
        this.onInitDrag(x, y);
        this.proxy.show();
    },

    
    onInitDrag: function(x, y) {
        var clone = this.el.dom.cloneNode(true);
        clone.id = Ext.id(); 
        this.proxy.update(clone);
        this.onStartDrag(x, y);
        return true;
    },

    
    getProxy: function() {
        return this.proxy;
    },

    
    hideProxy: function() {
        this.proxy.hide();
        this.proxy.reset(true);
        this.dragging = false;
    },

    
    triggerCacheRefresh: function() {
        Ext.dd.DDM.refreshCache(this.groups);
    },

    
    b4EndDrag: function(e) {
    },

    
    endDrag : function(e){
        this.onEndDrag(this.dragData, e);
    },

    
    onEndDrag : function(data, e){
    },

    
    autoOffset : function(x, y) {
        this.setDelta(-12, -20);
    },

    destroy: function(){
        this.callParent();
        Ext.destroy(this.proxy);
    }
});


Ext.define('Ext.draw.SpriteDD', {
    extend: 'Ext.dd.DragSource',

    constructor : function(sprite, cfg){
        var me = this,
            el = sprite.el;
        me.sprite = sprite;
        me.el = el;
        me.dragData = {el: el, sprite: sprite};
        me.callParent([el, cfg]);
        me.sprite.setStyle('cursor', 'move');
    },

    showFrame: Ext.emptyFn,
    createFrame : Ext.emptyFn,

    getDragEl : function(e){
        return this.el;
    },
    
    getRegion: function() {
        var me = this,
            el = me.el,
            pos, x1, x2, y1, y2, t, r, b, l, bbox, sprite;
        
        sprite = me.sprite;
        bbox = sprite.getBBox();
        
        try {
            pos = Ext.Element.getXY(el);
        } catch (e) { }

        if (!pos) {
            return null;
        }

        x1 = pos[0];
        x2 = x1 + bbox.width;
        y1 = pos[1];
        y2 = y1 + bbox.height;
        
        return new Ext.util.Region(y1, x2, y2, x1);
    },

    
     
    startDrag: function(x, y) {
        var me = this,
            attr = me.sprite.attr;
        me.prev = me.sprite.surface.transformToViewBox(x, y);
    },

    onDrag: function(e) {
        var xy = e.getXY(),
            me = this,
            sprite = me.sprite,
            attr = sprite.attr, dx, dy;
        xy = me.sprite.surface.transformToViewBox(xy[0], xy[1]);
        dx = xy[0] - me.prev[0];
        dy = xy[1] - me.prev[1];
        sprite.setAttributes({
            translate: {
                x: attr.translation.x + dx,
                y: attr.translation.y + dy
            }
        }, true);
        me.prev = xy;
    },

    setDragElPos: function () {
        
        return false;
    }
});

Ext.define('Ext.draw.Sprite', {

    

    mixins: {
        observable: 'Ext.util.Observable',
        animate: 'Ext.util.Animate'
    },

    requires: ['Ext.draw.SpriteDD'],

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    

    dirty: false,
    dirtyHidden: false,
    dirtyTransform: false,
    dirtyPath: true,
    dirtyFont: true,
    zIndexDirty: true,

    
    isSprite: true,
    zIndex: 0,
    fontProperties: [
        'font',
        'font-size',
        'font-weight',
        'font-style',
        'font-family',
        'text-anchor',
        'text'
    ],
    pathProperties: [
        'x',
        'y',
        'd',
        'path',
        'height',
        'width',
        'radius',
        'r',
        'rx',
        'ry',
        'cx',
        'cy'
    ],
    constructor: function(config) {
        var me = this;
        config = Ext.merge({}, config || {});
        me.id = Ext.id(null, 'ext-sprite-');
        me.transformations = [];
        Ext.copyTo(this, config, 'surface,group,type,draggable');
        
        me.bbox = {};
        me.attr = {
            zIndex: 0,
            translation: {
                x: null,
                y: null
            },
            rotation: {
                degrees: null,
                x: null,
                y: null
            },
            scaling: {
                x: null,
                y: null,
                cx: null,
                cy: null
            }
        };
        
        delete config.surface;
        delete config.group;
        delete config.type;
        delete config.draggable;
        me.setAttributes(config);
        me.addEvents(
            
            'beforedestroy',
            
            'destroy',
            
            'render',
            
            'mousedown',
            
            'mouseup',
            
            'mouseover',
            
            'mouseout',
            
            'mousemove',
            
            'click'
        );
        me.mixins.observable.constructor.apply(this, arguments);
    },

    

    initDraggable: function() {
        var me = this;
        me.draggable = true;
        
        if (!me.el) {
            me.surface.createSpriteElement(me);
        }
        me.dd = new Ext.draw.SpriteDD(me, Ext.isBoolean(me.draggable) ? null : me.draggable);
        me.on('beforedestroy', me.dd.destroy, me.dd);
    },

    
    setAttributes: function(attrs, redraw) {
        var me = this,
            fontProps = me.fontProperties,
            fontPropsLength = fontProps.length,
            pathProps = me.pathProperties,
            pathPropsLength = pathProps.length,
            hasSurface = !!me.surface,
            custom = hasSurface && me.surface.customAttributes || {},
            spriteAttrs = me.attr,
            dirtyBBox = false,
            attr, i, newTranslation, translation, newRotate, rotation, newScaling, scaling;

        attrs = Ext.apply({}, attrs);
        for (attr in custom) {
            if (attrs.hasOwnProperty(attr) && typeof custom[attr] == "function") {
                Ext.apply(attrs, custom[attr].apply(me, [].concat(attrs[attr])));
            }
        }

        
        if (!!attrs.hidden !== !!spriteAttrs.hidden) {
            me.dirtyHidden = true;
        }

        
        for (i = 0; i < pathPropsLength; i++) {
            attr = pathProps[i];
            if (attr in attrs && attrs[attr] !== spriteAttrs[attr]) {
                me.dirtyPath = true;
                dirtyBBox = true;
                break;
            }
        }

        
        if ('zIndex' in attrs) {
            me.zIndexDirty = true;
        }

        
        if ('text' in attrs) {
            me.dirtyFont = true;
            dirtyBBox = true;
        }

        for (i = 0; i < fontPropsLength; i++) {
            attr = fontProps[i];
            if (attr in attrs && attrs[attr] !== spriteAttrs[attr]) {
                me.dirtyFont = true;
                dirtyBBox = true;
                break;
            }
        }

        newTranslation = attrs.translation || attrs.translate;
        delete attrs.translate;
        delete attrs.translation;
        translation = spriteAttrs.translation;
        if (newTranslation) {
            if (('x' in newTranslation && newTranslation.x !== translation.x) ||
                ('y' in newTranslation && newTranslation.y !== translation.y)) {
                me.dirtyTransform = true;
                translation.x = newTranslation.x;
                translation.y = newTranslation.y;
            }
        }

        newRotate = attrs.rotation || attrs.rotate;
        rotation = spriteAttrs.rotation;
        delete attrs.rotate;
        delete attrs.rotation;
        if (newRotate) {
            if (('x' in newRotate && newRotate.x !== rotation.x) ||
                ('y' in newRotate && newRotate.y !== rotation.y) ||
                ('degrees' in newRotate && newRotate.degrees !== rotation.degrees)) {
                me.dirtyTransform = true;
                rotation.x = newRotate.x;
                rotation.y = newRotate.y;
                rotation.degrees = newRotate.degrees;
            }
        }

        newScaling = attrs.scaling || attrs.scale;
        scaling = spriteAttrs.scaling;
        delete attrs.scale;
        delete attrs.scaling;
        if (newScaling) {
            if (('x' in newScaling && newScaling.x !== scaling.x) ||
                ('y' in newScaling && newScaling.y !== scaling.y) ||
                ('cx' in newScaling && newScaling.cx !== scaling.cx) ||
                ('cy' in newScaling && newScaling.cy !== scaling.cy)) {
                me.dirtyTransform = true;
                scaling.x = newScaling.x;
                scaling.y = newScaling.y;
                scaling.cx = newScaling.cx;
                scaling.cy = newScaling.cy;
            }
        }

        
        if (!me.dirtyTransform && dirtyBBox) {
            if (spriteAttrs.scaling.x === null ||
                spriteAttrs.scaling.y === null ||
                spriteAttrs.rotation.y === null ||
                spriteAttrs.rotation.y === null) {
                me.dirtyTransform = true;
            }
        }

        Ext.apply(spriteAttrs, attrs);
        me.dirty = true;

        if (redraw === true && hasSurface) {
            me.redraw();
        }
        return this;
    },

    
    getBBox: function() {
        return this.surface.getBBox(this);
    },

    setText: function(text) {
        return this.surface.setText(this, text);
    },

    
    hide: function(redraw) {
        this.setAttributes({
            hidden: true
        }, redraw);
        return this;
    },

    
    show: function(redraw) {
        this.setAttributes({
            hidden: false
        }, redraw);
        return this;
    },

    
    remove: function() {
        if (this.surface) {
            this.surface.remove(this);
            return true;
        }
        return false;
    },

    onRemove: function() {
        this.surface.onRemove(this);
    },

    
    destroy: function() {
        var me = this;
        if (me.fireEvent('beforedestroy', me) !== false) {
            me.remove();
            me.surface.onDestroy(me);
            me.clearListeners();
            me.fireEvent('destroy');
        }
    },

    
    redraw: function() {
        this.surface.renderItem(this);
        return this;
    },

    
    setStyle: function() {
        this.el.setStyle.apply(this.el, arguments);
        return this;
    },

    
    addCls: function(obj) {
        this.surface.addCls(this, obj);
        return this;
    },

    
    removeCls: function(obj) {
        this.surface.removeCls(this, obj);
        return this;
    }
});


Ext.define('Ext.draw.engine.Svg', {

    

    extend: 'Ext.draw.Surface',

    requires: ['Ext.draw.Draw', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],

    

    engine: 'Svg',

    trimRe: /^\s+|\s+$/g,
    spacesRe: /\s+/,
    xlink: "http:/" + "/www.w3.org/1999/xlink",

    translateAttrs: {
        radius: "r",
        radiusX: "rx",
        radiusY: "ry",
        path: "d",
        lineWidth: "stroke-width",
        fillOpacity: "fill-opacity",
        strokeOpacity: "stroke-opacity",
        strokeLinejoin: "stroke-linejoin"
    },

    parsers: {},

    minDefaults: {
        circle: {
            cx: 0,
            cy: 0,
            r: 0,
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        ellipse: {
            cx: 0,
            cy: 0,
            rx: 0,
            ry: 0,
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        rect: {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            rx: 0,
            ry: 0,
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        text: {
            x: 0,
            y: 0,
            "text-anchor": "start",
            "font-family": null,
            "font-size": null,
            "font-weight": null,
            "font-style": null,
            fill: "#000",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        path: {
            d: "M0,0",
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        image: {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            preserveAspectRatio: "none",
            opacity: null
        }
    },

    createSvgElement: function(type, attrs) {
        var el = this.domRef.createElementNS("http:/" + "/www.w3.org/2000/svg", type),
            key;
        if (attrs) {
            for (key in attrs) {
                el.setAttribute(key, String(attrs[key]));
            }
        }
        return el;
    },

    createSpriteElement: function(sprite) {
        
        var el = this.createSvgElement(sprite.type);
        el.id = sprite.id;
        if (el.style) {
            el.style.webkitTapHighlightColor = "rgba(0,0,0,0)";
        }
        sprite.el = Ext.get(el);
        this.applyZIndex(sprite); 
        sprite.matrix = new Ext.draw.Matrix();
        sprite.bbox = {
            plain: 0,
            transform: 0
        };
        this.applyAttrs(sprite);
        this.applyTransformations(sprite);
        sprite.fireEvent("render", sprite);
        return el;
    },
    
    getBBoxText: function (sprite) {
        var bbox = {},
            bb, height, width, i, ln, el;

        if (sprite && sprite.el) {
            el = sprite.el.dom;
            try {
                bbox = el.getBBox();
                return bbox;
            } catch(e) {
                
            }
            bbox = {x: bbox.x, y: Infinity, width: 0, height: 0};
            ln = el.getNumberOfChars();
            for (i = 0; i < ln; i++) {
                bb = el.getExtentOfChar(i);
                bbox.y = Math.min(bb.y, bbox.y);
                height = bb.y + bb.height - bbox.y;
                bbox.height = Math.max(bbox.height, height);
                width = bb.x + bb.width - bbox.x;
                bbox.width = Math.max(bbox.width, width);
            }
            return bbox;
        }
    },

    hide: function() {
        Ext.get(this.el).hide();
    },

    show: function() {
        Ext.get(this.el).show();
    },

    hidePrim: function(sprite) {
        this.addCls(sprite, Ext.baseCSSPrefix + 'hide-visibility');
    },

    showPrim: function(sprite) {
        this.removeCls(sprite, Ext.baseCSSPrefix + 'hide-visibility');
    },

    getDefs: function() {
        return this._defs || (this._defs = this.createSvgElement("defs"));
    },

    transform: function(sprite, matrixOnly) {
        var me = this,
            matrix = new Ext.draw.Matrix(),
            transforms = sprite.transformations,
            transformsLength = transforms.length,
            i = 0,
            transform, type;
            
        for (; i < transformsLength; i++) {
            transform = transforms[i];
            type = transform.type;
            if (type == "translate") {
                matrix.translate(transform.x, transform.y);
            }
            else if (type == "rotate") {
                matrix.rotate(transform.degrees, transform.x, transform.y);
            }
            else if (type == "scale") {
                matrix.scale(transform.x, transform.y, transform.centerX, transform.centerY);
            }
        }
        sprite.matrix = matrix;
        if (!matrixOnly) {
            sprite.el.set({transform: matrix.toSvg()});
        }
    },

    setSize: function(width, height) {
        var me = this,
            el = me.el;
        
        width = +width || me.width;
        height = +height || me.height;
        me.width = width;
        me.height = height;

        el.setSize(width, height);
        el.set({
            width: width,
            height: height
        });
        me.callParent([width, height]);
    },

    
    getRegion: function() {
        
        
        var svgXY = this.el.getXY(),
            rectXY = this.bgRect.getXY(),
            max = Math.max,
            x = max(svgXY[0], rectXY[0]),
            y = max(svgXY[1], rectXY[1]);
        return {
            left: x,
            top: y,
            right: x + this.width,
            bottom: y + this.height
        };
    },

    onRemove: function(sprite) {
        if (sprite.el) {
            sprite.el.destroy();
            delete sprite.el;
        }
        this.callParent(arguments);
    },
    
    setViewBox: function(x, y, width, height) {
        if (isFinite(x) && isFinite(y) && isFinite(width) && isFinite(height)) {
            this.callParent(arguments);
            this.el.dom.setAttribute("viewBox", [x, y, width, height].join(" "));
        }
    },

    render: function (container) {
        var me = this,
            width,
            height,
            el,
            defs,
            bgRect,
            webkitRect;
        if (!me.el) {
            width = me.width || 0;
            height = me.height || 0;
            el = me.createSvgElement('svg', {
                xmlns: "http:/" + "/www.w3.org/2000/svg",
                version: 1.1,
                width: width,
                height: height
            });
            defs = me.getDefs();

            
            
            
            
            bgRect = me.createSvgElement("rect", {
                width: "100%",
                height: "100%",
                fill: "#000",
                stroke: "none",
                opacity: 0
            });
            
            if (Ext.isSafari3) {
                
                webkitRect = me.createSvgElement("rect", {
                    x: -10,
                    y: -10,
                    width: "110%",
                    height: "110%",
                    fill: "none",
                    stroke: "#000"
                });
            }
            el.appendChild(defs);
            if (Ext.isSafari3) {
                el.appendChild(webkitRect);
            }
            el.appendChild(bgRect);
            container.appendChild(el);
            me.el = Ext.get(el);
            me.bgRect = Ext.get(bgRect);
            if (Ext.isSafari3) {
                me.webkitRect = Ext.get(webkitRect);
                me.webkitRect.hide();
            }
            me.el.on({
                scope: me,
                mouseup: me.onMouseUp,
                mousedown: me.onMouseDown,
                mouseover: me.onMouseOver,
                mouseout: me.onMouseOut,
                mousemove: me.onMouseMove,
                mouseenter: me.onMouseEnter,
                mouseleave: me.onMouseLeave,
                click: me.onClick,
                dblclick: me.onDblClick
            });
        }
        me.renderAll();
    },

    
    onMouseEnter: function(e) {
        if (this.el.parent().getRegion().contains(e.getPoint())) {
            this.fireEvent('mouseenter', e);
        }
    },

    
    onMouseLeave: function(e) {
        if (!this.el.parent().getRegion().contains(e.getPoint())) {
            this.fireEvent('mouseleave', e);
        }
    },
    
    processEvent: function(name, e) {
        var target = e.getTarget(),
            surface = this.surface,
            sprite;

        this.fireEvent(name, e);
        
        if (target.nodeName == "tspan" && target.parentNode) {
            target = target.parentNode;
        }
        sprite = this.items.get(target.id);
        if (sprite) {
            sprite.fireEvent(name, sprite, e);
        }
    },

    
    tuneText: function (sprite, attrs) {
        var el = sprite.el.dom,
            tspans = [],
            height, tspan, text, i, ln, texts, factor, x;

        if (attrs.hasOwnProperty("text")) {
            
            
            

            
            text = sprite.tspans && Ext.Array.map(sprite.tspans, function(t) { return t.textContent; }).join('');

            if (!sprite.tspans || attrs.text != text) {
                tspans = this.setText(sprite, attrs.text);
                sprite.tspans = tspans;
            
            } else {
                tspans = sprite.tspans || [];
            }
        }
        
        if (tspans.length) {
            height = this.getBBoxText(sprite).height;
            x = sprite.el.dom.getAttribute("x");
            for (i = 0, ln = tspans.length; i < ln; i++) {
                
                
                factor = (Ext.isFF3_0 || Ext.isFF3_5) ? 2 : 4;
                tspans[i].setAttribute("x", x);
                tspans[i].setAttribute("dy", i ? height * 1.2 : height / factor);
            }
            sprite.dirty = true;
        }
    },

    setText: function(sprite, textString) {
         var me = this,
             el = sprite.el.dom,
             tspans = [],
             height, tspan, text, i, ln, texts;
        
        while (el.firstChild) {
            el.removeChild(el.firstChild);
        }
        
        texts = String(textString).split("\n");
        for (i = 0, ln = texts.length; i < ln; i++) {
            text = texts[i];
            if (text) {
                tspan = me.createSvgElement("tspan");
                tspan.appendChild(document.createTextNode(Ext.htmlDecode(text)));
                el.appendChild(tspan);
                tspans[i] = tspan;
            }
        }
        return tspans;
    },

    renderAll: function() {
        this.items.each(this.renderItem, this);
    },

    renderItem: function (sprite) {
        if (!this.el) {
            return;
        }
        if (!sprite.el) {
            this.createSpriteElement(sprite);
        }
        if (sprite.zIndexDirty) {
            this.applyZIndex(sprite);
        }
        if (sprite.dirty) {
            this.applyAttrs(sprite);
            if (sprite.dirtyTransform) {
                this.applyTransformations(sprite);
            }
        }
    },

    redraw: function(sprite) {
        sprite.dirty = sprite.zIndexDirty = true;
        this.renderItem(sprite);
    },

    applyAttrs: function (sprite) {
        var me = this,
            el = sprite.el,
            group = sprite.group,
            sattr = sprite.attr,
            parsers = me.parsers,
            
            
            
            gradientsMap = me.gradientsMap || {},
            safariFix = Ext.isSafari && !Ext.isStrict,
            groups, i, ln, attrs, font, key, style, name, rect;

        if (group) {
            groups = [].concat(group);
            ln = groups.length;
            for (i = 0; i < ln; i++) {
                group = groups[i];
                me.getGroup(group).add(sprite);
            }
            delete sprite.group;
        }
        attrs = me.scrubAttrs(sprite) || {};

        
            sprite.bbox.plain = 0;
            sprite.bbox.transform = 0;
            if (sprite.type == "circle" || sprite.type == "ellipse") {
                attrs.cx = attrs.cx || attrs.x;
                attrs.cy = attrs.cy || attrs.y;
            }
            else if (sprite.type == "rect") {
                attrs.rx = attrs.ry = attrs.r;
            }
            else if (sprite.type == "path" && attrs.d) {
                attrs.d = Ext.draw.Draw.pathToString(Ext.draw.Draw.pathToAbsolute(attrs.d));
            }
            sprite.dirtyPath = false;
        
        
        
        

        if (attrs['clip-rect']) {
            me.setClip(sprite, attrs);
            delete attrs['clip-rect'];
        }
        if (sprite.type == 'text' && attrs.font && sprite.dirtyFont) {
            el.set({ style: "font: " + attrs.font});
        }
        if (sprite.type == "image") {
            el.dom.setAttributeNS(me.xlink, "href", attrs.src);
        }
        Ext.applyIf(attrs, me.minDefaults[sprite.type]);

        if (sprite.dirtyHidden) {
            (sattr.hidden) ? me.hidePrim(sprite) : me.showPrim(sprite);
            sprite.dirtyHidden = false;
        }
        for (key in attrs) {
            if (attrs.hasOwnProperty(key) && attrs[key] != null) {
                
                
                
                
                
                if (safariFix && ('color|stroke|fill'.indexOf(key) > -1) && (attrs[key] in gradientsMap)) {
                    attrs[key] = gradientsMap[attrs[key]];
                }
                
                if (key == 'hidden' && sprite.type == 'text') {
                    continue;
                }
                if (key in parsers) {
                    el.dom.setAttribute(key, parsers[key](attrs[key], sprite, me));
                } else {
                    el.dom.setAttribute(key, attrs[key]);
                }
            }
        }
        
        if (sprite.type == 'text') {
            me.tuneText(sprite, attrs);
        }
        sprite.dirtyFont = false;

        
        style = sattr.style;
        if (style) {
            el.setStyle(style);
        }

        sprite.dirty = false;

        if (Ext.isSafari3) {
            
            me.webkitRect.show();
            setTimeout(function () {
                me.webkitRect.hide();
            });
        }
    },

    setClip: function(sprite, params) {
        var me = this,
            rect = params["clip-rect"],
            clipEl, clipPath;
        if (rect) {
            if (sprite.clip) {
                sprite.clip.parentNode.parentNode.removeChild(sprite.clip.parentNode);
            }
            clipEl = me.createSvgElement('clipPath');
            clipPath = me.createSvgElement('rect');
            clipEl.id = Ext.id(null, 'ext-clip-');
            clipPath.setAttribute("x", rect.x);
            clipPath.setAttribute("y", rect.y);
            clipPath.setAttribute("width", rect.width);
            clipPath.setAttribute("height", rect.height);
            clipEl.appendChild(clipPath);
            me.getDefs().appendChild(clipEl);
            sprite.el.dom.setAttribute("clip-path", "url(#" + clipEl.id + ")");
            sprite.clip = clipPath;
        } 
        
        
        
        
        
        
    },

    
    applyZIndex: function(sprite) {
        var me = this,
            items = me.items,
            idx = items.indexOf(sprite),
            el = sprite.el,
            prevEl;
        if (me.el.dom.childNodes[idx + 2] !== el.dom) { 
            if (idx > 0) {
                
                do {
                    prevEl = items.getAt(--idx).el;
                } while (!prevEl && idx > 0);
            }
            el.insertAfter(prevEl || me.bgRect);
        }
        sprite.zIndexDirty = false;
    },

    createItem: function (config) {
        var sprite = new Ext.draw.Sprite(config);
        sprite.surface = this;
        return sprite;
    },

    addGradient: function(gradient) {
        gradient = Ext.draw.Draw.parseGradient(gradient);
        var me = this,
            ln = gradient.stops.length,
            vector = gradient.vector,
            
            
            
            usePlain = Ext.isSafari && !Ext.isStrict,
            gradientEl, stop, stopEl, i, gradientsMap;
            
        gradientsMap = me.gradientsMap || {};
        
        if (!usePlain) {
            if (gradient.type == "linear") {
                gradientEl = me.createSvgElement("linearGradient");
                gradientEl.setAttribute("x1", vector[0]);
                gradientEl.setAttribute("y1", vector[1]);
                gradientEl.setAttribute("x2", vector[2]);
                gradientEl.setAttribute("y2", vector[3]);
            }
            else {
                gradientEl = me.createSvgElement("radialGradient");
                gradientEl.setAttribute("cx", gradient.centerX);
                gradientEl.setAttribute("cy", gradient.centerY);
                gradientEl.setAttribute("r", gradient.radius);
                if (Ext.isNumber(gradient.focalX) && Ext.isNumber(gradient.focalY)) {
                    gradientEl.setAttribute("fx", gradient.focalX);
                    gradientEl.setAttribute("fy", gradient.focalY);
                }
            }
            gradientEl.id = gradient.id;
            me.getDefs().appendChild(gradientEl);
            for (i = 0; i < ln; i++) {
                stop = gradient.stops[i];
                stopEl = me.createSvgElement("stop");
                stopEl.setAttribute("offset", stop.offset + "%");
                stopEl.setAttribute("stop-color", stop.color);
                stopEl.setAttribute("stop-opacity",stop.opacity);
                gradientEl.appendChild(stopEl);
            }
        } else {
            gradientsMap['url(#' + gradient.id + ')'] = gradient.stops[0].color;
        }
        me.gradientsMap = gradientsMap;
    },

    
    hasCls: function(sprite, className) {
        return className && (' ' + (sprite.el.dom.getAttribute('class') || '') + ' ').indexOf(' ' + className + ' ') != -1;
    },

    addCls: function(sprite, className) {
        var el = sprite.el,
            i,
            len,
            v,
            cls = [],
            curCls =  el.getAttribute('class') || '';
        
        if (!Ext.isArray(className)) {
            if (typeof className == 'string' && !this.hasCls(sprite, className)) {
                el.set({ 'class': curCls + ' ' + className });
            }
        }
        else {
            for (i = 0, len = className.length; i < len; i++) {
                v = className[i];
                if (typeof v == 'string' && (' ' + curCls + ' ').indexOf(' ' + v + ' ') == -1) {
                    cls.push(v);
                }
            }
            if (cls.length) {
                el.set({ 'class': ' ' + cls.join(' ') });
            }
        }
    },

    removeCls: function(sprite, className) {
        var me = this,
            el = sprite.el,
            curCls =  el.getAttribute('class') || '',
            i, idx, len, cls, elClasses;
        if (!Ext.isArray(className)){
            className = [className];
        }
        if (curCls) {
            elClasses = curCls.replace(me.trimRe, ' ').split(me.spacesRe);
            for (i = 0, len = className.length; i < len; i++) {
                cls = className[i];
                if (typeof cls == 'string') {
                    cls = cls.replace(me.trimRe, '');
                    idx = Ext.Array.indexOf(elClasses, cls);
                    if (idx != -1) {
                        Ext.Array.erase(elClasses, idx, 1);
                    }
                }
            }
            el.set({ 'class': elClasses.join(' ') });
        }
    },

    destroy: function() {
        var me = this;
        
        me.callParent();
        if (me.el) {
            me.el.remove();
        }
        if (me._defs) {
            Ext.get(me._defs).destroy();
        }
        if (me.bgRect) {
            Ext.get(me.bgRect).destroy();
        }
        if (me.webkitRect) {
            Ext.get(me.webkitRect).destroy();
        }
        delete me.el;
    }
});


Ext.define('Ext.draw.engine.Vml', {

    

    extend: 'Ext.draw.Surface',

    requires: ['Ext.draw.Draw', 'Ext.draw.Color', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],

    

    engine: 'Vml',

    map: {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
    bitesRe: /([clmz]),?([^clmz]*)/gi,
    valRe: /-?[^,\s\-]+/g,
    fillUrlRe: /^url\(\s*['"]?([^\)]+?)['"]?\s*\)$/i,
    pathlike: /^(path|rect)$/,
    NonVmlPathRe: /[ahqstv]/ig, // Non-VML Pathing ops
    partialPathRe: /[clmz]/g,
    fontFamilyRe: /^['"]+|['"]+$/g,
    baseVmlCls: Ext.baseCSSPrefix + 'vml-base',
    vmlGroupCls: Ext.baseCSSPrefix + 'vml-group',
    spriteCls: Ext.baseCSSPrefix + 'vml-sprite',
    measureSpanCls: Ext.baseCSSPrefix + 'vml-measure-span',
    zoom: 21600,
    coordsize: 1000,
    coordorigin: '0 0',
    zIndexShift: 0,
    // VML uses CSS z-index and therefore doesn't need sprites to be kept in zIndex order
    orderSpritesByZIndex: false,

    
    
    path2vml: function (path) {
        var me = this,
            nonVML = me.NonVmlPathRe,
            map = me.map,
            val = me.valRe,
            zoom = me.zoom,
            bites = me.bitesRe,
            command = Ext.Function.bind(Ext.draw.Draw.pathToAbsolute, Ext.draw.Draw),
            res, pa, p, r, i, ii, j, jj;
        if (String(path).match(nonVML)) {
            command = Ext.Function.bind(Ext.draw.Draw.path2curve, Ext.draw.Draw);
        } else if (!String(path).match(me.partialPathRe)) {
            res = String(path).replace(bites, function (all, command, args) {
                var vals = [],
                    isMove = command.toLowerCase() == "m",
                    res = map[command];
                args.replace(val, function (value) {
                    if (isMove && vals.length === 2) {
                        res += vals + map[command == "m" ? "l" : "L"];
                        vals = [];
                    }
                    vals.push(Math.round(value * zoom));
                });
                return res + vals;
            });
            return res;
        }
        pa = command(path);
        res = [];
        for (i = 0, ii = pa.length; i < ii; i++) {
            p = pa[i];
            r = pa[i][0].toLowerCase();
            if (r == "z") {
                r = "x";
            }
            for (j = 1, jj = p.length; j < jj; j++) {
                r += Math.round(p[j] * me.zoom) + (j != jj - 1 ? "," : "");
            }
            res.push(r);
        }
        return res.join(" ");
    },

    
    translateAttrs: {
        radius: "r",
        radiusX: "rx",
        radiusY: "ry",
        lineWidth: "stroke-width",
        fillOpacity: "fill-opacity",
        strokeOpacity: "stroke-opacity",
        strokeLinejoin: "stroke-linejoin"
    },

    
    minDefaults: {
        circle: {
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        ellipse: {
            cx: 0,
            cy: 0,
            rx: 0,
            ry: 0,
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        rect: {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            rx: 0,
            ry: 0,
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        text: {
            x: 0,
            y: 0,
            "text-anchor": "start",
            font: '10px "Arial"',
            fill: "#000",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        path: {
            d: "M0,0",
            fill: "none",
            stroke: null,
            "stroke-width": null,
            opacity: null,
            "fill-opacity": null,
            "stroke-opacity": null
        },
        image: {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            preserveAspectRatio: "none",
            opacity: null
        }
    },

    
    onMouseEnter: function (e) {
        this.fireEvent("mouseenter", e);
    },

    
    onMouseLeave: function (e) {
        this.fireEvent("mouseleave", e);
    },

    
    processEvent: function (name, e) {
        var target = e.getTarget(),
            surface = this.surface,
            sprite;
        this.fireEvent(name, e);
        sprite = this.items.get(target.id);
        if (sprite) {
            sprite.fireEvent(name, sprite, e);
        }
    },

    
    createSpriteElement: function (sprite) {
        var me = this,
            attr = sprite.attr,
            type = sprite.type,
            zoom = me.zoom,
            vml = sprite.vml || (sprite.vml = {}),
            round = Math.round,
            el = (type === 'image') ? me.createNode('image') : me.createNode('shape'),
            path, skew, textPath;

        el.coordsize = zoom + ' ' + zoom;
        el.coordorigin = attr.coordorigin || "0 0";
        Ext.get(el).addCls(me.spriteCls);
        if (type == "text") {
            vml.path = path = me.createNode("path");
            path.textpathok = true;
            vml.textpath = textPath = me.createNode("textpath");
            textPath.on = true;
            el.appendChild(textPath);
            el.appendChild(path);
        }
        el.id = sprite.id;
        sprite.el = Ext.get(el);
        sprite.el.setStyle('zIndex', -me.zIndexShift);
        me.el.appendChild(el);
        if (type !== 'image') {
            skew = me.createNode("skew");
            skew.on = true;
            el.appendChild(skew);
            sprite.skew = skew;
        }
        sprite.matrix = new Ext.draw.Matrix();
        sprite.bbox = {
            plain: null,
            transform: null
        };

        this.applyAttrs(sprite);
        this.applyTransformations(sprite);        
        sprite.fireEvent("render", sprite);
        return sprite.el;
    },

    getBBoxText: function (sprite) {
        var vml = sprite.vml;
        return {
            x: vml.X + (vml.bbx || 0) - vml.W / 2,
            y: vml.Y - vml.H / 2,
            width: vml.W,
            height: vml.H
        };
    },

    applyAttrs: function (sprite) {
        var me = this,
            vml = sprite.vml,
            group = sprite.group,
            spriteAttr = sprite.attr,
            el = sprite.el,
            dom = el.dom,
            style, name, groups, i, ln, scrubbedAttrs, font, key,
            cx, cy, rx, ry;

        if (group) {
            groups = [].concat(group);
            ln = groups.length;
            for (i = 0; i < ln; i++) {
                group = groups[i];
                me.getGroup(group).add(sprite);
            }
            delete sprite.group;
        }
        scrubbedAttrs = me.scrubAttrs(sprite) || {};

        if (sprite.zIndexDirty) {
            me.setZIndex(sprite);
        }

        
        Ext.applyIf(scrubbedAttrs, me.minDefaults[sprite.type]);

        if (sprite.type == 'image') {
            Ext.apply(sprite.attr, {
                x: scrubbedAttrs.x,
                y: scrubbedAttrs.y,
                width: scrubbedAttrs.width,
                height: scrubbedAttrs.height
            });
            el.setStyle({
                width: scrubbedAttrs.width + 'px',
                height: scrubbedAttrs.height + 'px'
            });
            dom.src = scrubbedAttrs.src;
        }

        if (dom.href) {
            dom.href = scrubbedAttrs.href;
        }
        if (dom.title) {
            dom.title = scrubbedAttrs.title;
        }
        if (dom.target) {
            dom.target = scrubbedAttrs.target;
        }
        if (dom.cursor) {
            dom.cursor = scrubbedAttrs.cursor;
        }

        
        if (sprite.dirtyHidden) {
            (scrubbedAttrs.hidden) ? me.hidePrim(sprite) : me.showPrim(sprite);
            sprite.dirtyHidden = false;
        }

        
        if (sprite.dirtyPath) {
            if (sprite.type == "circle" || sprite.type == "ellipse") {
                cx = scrubbedAttrs.x;
                cy = scrubbedAttrs.y;
                rx = scrubbedAttrs.rx || scrubbedAttrs.r || 0;
                ry = scrubbedAttrs.ry || scrubbedAttrs.r || 0;
                dom.path = Ext.String.format("ar{0},{1},{2},{3},{4},{1},{4},{1}",
                    Math.round((cx - rx) * me.zoom),
                    Math.round((cy - ry) * me.zoom),
                    Math.round((cx + rx) * me.zoom),
                    Math.round((cy + ry) * me.zoom),
                    Math.round(cx * me.zoom));
                sprite.dirtyPath = false;
            }
            else if (sprite.type !== "text" && sprite.type !== 'image') {
                sprite.attr.path = scrubbedAttrs.path = me.setPaths(sprite, scrubbedAttrs) || scrubbedAttrs.path;
                dom.path = me.path2vml(scrubbedAttrs.path);
                sprite.dirtyPath = false;
            }
        }

        
        if ("clip-rect" in scrubbedAttrs) {
            me.setClip(sprite, scrubbedAttrs);
        }

        
        if (sprite.type == "text") {
            me.setTextAttributes(sprite, scrubbedAttrs);
        }

        
        if (scrubbedAttrs.opacity || scrubbedAttrs['stroke-opacity'] || scrubbedAttrs.fill) {
            me.setFill(sprite, scrubbedAttrs);
        }

        
        if (scrubbedAttrs.stroke || scrubbedAttrs['stroke-opacity'] || scrubbedAttrs.fill) {
            me.setStroke(sprite, scrubbedAttrs);
        }

        
        style = spriteAttr.style;
        if (style) {
            el.setStyle(style);
        }

        sprite.dirty = false;
    },

    setZIndex: function (sprite) {
        var me = this,
            zIndex = sprite.attr.zIndex,
            shift = me.zIndexShift,
            items, iLen, item, i;

        if (zIndex < shift) {
            
            
            items = me.items.items;
            iLen = items.length;

            for (i = 0; i < iLen; i++) {
                if ((zIndex = items[i].attr.zIndex) && zIndex < shift) { 
                    shift = zIndex;
                }
            }

            me.zIndexShift = shift;
            for (i = 0; i < iLen; i++) {
                item = items[i];
                if (item.el) {
                    item.el.setStyle('zIndex', item.attr.zIndex - shift);
                }
                item.zIndexDirty = false;
            }
        } else if (sprite.el) {
            sprite.el.setStyle('zIndex', zIndex - shift);
            sprite.zIndexDirty = false;
        }
    },

    
    setPaths: function (sprite, params) {
        var spriteAttr = sprite.attr, thickness = sprite.attr['stroke-width'] || 1;
        
        sprite.bbox.plain = null;
        sprite.bbox.transform = null;
        if (sprite.type == 'circle') {
            spriteAttr.rx = spriteAttr.ry = params.r;
            return Ext.draw.Draw.ellipsePath(sprite);
        }
        else if (sprite.type == 'ellipse') {
            spriteAttr.rx = params.rx;
            spriteAttr.ry = params.ry;
            return Ext.draw.Draw.ellipsePath(sprite);
        }
        else if (sprite.type == 'rect') {
            spriteAttr.rx = spriteAttr.ry = params.r;
            return Ext.draw.Draw.rectPath(sprite);
        }
        else if (sprite.type == 'path' && spriteAttr.path) {
            return Ext.draw.Draw.pathToAbsolute(spriteAttr.path);
        }
        return false;
    },

    setFill: function (sprite, params) {
        var me = this,
            el = sprite.el.dom,
            fillEl = el.fill,
            newfill = false,
            opacity, gradient, fillUrl, rotation, angle;

        if (!fillEl) {
            
            fillEl = el.fill = me.createNode("fill");
            newfill = true;
        }
        if (Ext.isArray(params.fill)) {
            params.fill = params.fill[0];
        }
        if (params.fill == "none") {
            fillEl.on = false;
        }
        else {
            if (typeof params.opacity == "number") {
                fillEl.opacity = params.opacity;
            }
            if (typeof params["fill-opacity"] == "number") {
                fillEl.opacity = params["fill-opacity"];
            }
            fillEl.on = true;
            if (typeof params.fill == "string") {
                fillUrl = params.fill.match(me.fillUrlRe);
                if (fillUrl) {
                    fillUrl = fillUrl[1];
                    
                    if (fillUrl.charAt(0) == "#") {
                        gradient = me.gradientsColl.getByKey(fillUrl.substring(1));
                    }
                    if (gradient) {
                        
                        rotation = params.rotation;
                        angle = -(gradient.angle + 270 + (rotation ? rotation.degrees : 0)) % 360;
                        
                        if (angle === 0) {
                            angle = 180;
                        }
                        fillEl.angle = angle;
                        fillEl.type = "gradient";
                        fillEl.method = "sigma";
                        if (fillEl.colors) {
                            fillEl.colors.value = gradient.colors;
                        } else {
                            fillEl.colors = gradient.colors;
                        }
                    }
                    
                    else {
                        fillEl.src = fillUrl;
                        fillEl.type = "tile";
                    }
                }
                else {
                    fillEl.color = Ext.draw.Color.toHex(params.fill);
                    fillEl.src = "";
                    fillEl.type = "solid";
                }
            }
        }
        if (newfill) {
            el.appendChild(fillEl);
        }
    },

    setStroke: function (sprite, params) {
        var me = this,
            el = sprite.el.dom,
            strokeEl = sprite.strokeEl,
            newStroke = false,
            width, opacity;

        if (!strokeEl) {
            strokeEl = sprite.strokeEl = me.createNode("stroke");
            newStroke = true;
        }
        if (Ext.isArray(params.stroke)) {
            params.stroke = params.stroke[0];
        }
        if (!params.stroke || params.stroke == "none" || params.stroke == 0 || params["stroke-width"] == 0) {
            strokeEl.on = false;
        }
        else {
            strokeEl.on = true;
            if (params.stroke && !params.stroke.match(me.fillUrlRe)) {
                
                strokeEl.color = Ext.draw.Color.toHex(params.stroke);
            }
            strokeEl.dashstyle = params["stroke-dasharray"] ? "dash" : "solid";
            strokeEl.joinstyle = params["stroke-linejoin"];
            strokeEl.endcap = params["stroke-linecap"] || "round";
            strokeEl.miterlimit = params["stroke-miterlimit"] || 8;
            width = parseFloat(params["stroke-width"] || 1) * 0.75;
            opacity = params["stroke-opacity"] || 1;
            
            if (Ext.isNumber(width) && width < 1) {
                strokeEl.weight = 1;
                strokeEl.opacity = opacity * width;
            }
            else {
                strokeEl.weight = width;
                strokeEl.opacity = opacity;
            }
        }
        if (newStroke) {
            el.appendChild(strokeEl);
        }
    },

    setClip: function (sprite, params) {
        var me = this,
            el = sprite.el,
            clipEl = sprite.clipEl,
            rect = String(params["clip-rect"]).split(me.separatorRe);
        if (!clipEl) {
            clipEl = sprite.clipEl = me.el.insertFirst(Ext.getDoc().dom.createElement("div"));
            clipEl.addCls(Ext.baseCSSPrefix + 'vml-sprite');
        }
        if (rect.length == 4) {
            rect[2] = +rect[2] + (+rect[0]);
            rect[3] = +rect[3] + (+rect[1]);
            clipEl.setStyle("clip", Ext.String.format("rect({1}px {2}px {3}px {0}px)", rect[0], rect[1], rect[2], rect[3]));
            clipEl.setSize(me.el.width, me.el.height);
        }
        else {
            clipEl.setStyle("clip", "");
        }
    },

    setTextAttributes: function (sprite, params) {
        var me = this,
            vml = sprite.vml,
            textStyle = vml.textpath.style,
            spanCacheStyle = me.span.style,
            zoom = me.zoom,
            round = Math.round,
            fontObj = {
                fontSize: "font-size",
                fontWeight: "font-weight",
                fontStyle: "font-style"
            },
            fontProp,
            paramProp;
        if (sprite.dirtyFont) {
            if (params.font) {
                textStyle.font = spanCacheStyle.font = params.font;
            }
            if (params["font-family"]) {
                textStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(me.fontFamilyRe, "") + '"';
                spanCacheStyle.fontFamily = params["font-family"];
            }

            for (fontProp in fontObj) {
                paramProp = params[fontObj[fontProp]];
                if (paramProp) {
                    textStyle[fontProp] = spanCacheStyle[fontProp] = paramProp;
                }
            }

            me.setText(sprite, params.text);

            if (vml.textpath.string) {
                me.span.innerHTML = String(vml.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br/>");
            }
            vml.W = me.span.offsetWidth;
            vml.H = me.span.offsetHeight + 2; 

            
            if (params["text-anchor"] == "middle") {
                textStyle["v-text-align"] = "center";
            }
            else if (params["text-anchor"] == "end") {
                textStyle["v-text-align"] = "right";
                vml.bbx = -Math.round(vml.W / 2);
            }
            else {
                textStyle["v-text-align"] = "left";
                vml.bbx = Math.round(vml.W / 2);
            }
        }
        vml.X = params.x;
        vml.Y = params.y;
        vml.path.v = Ext.String.format("m{0},{1}l{2},{1}", Math.round(vml.X * zoom), Math.round(vml.Y * zoom), Math.round(vml.X * zoom) + 1);
        
        sprite.bbox.plain = null;
        sprite.bbox.transform = null;
        sprite.dirtyFont = false;
    },

    setText: function (sprite, text) {
        sprite.vml.textpath.string = Ext.htmlDecode(text);
    },

    hide: function () {
        this.el.hide();
    },

    show: function () {
        this.el.show();
    },

    hidePrim: function (sprite) {
        sprite.el.addCls(Ext.baseCSSPrefix + 'hide-visibility');
    },

    showPrim: function (sprite) {
        sprite.el.removeCls(Ext.baseCSSPrefix + 'hide-visibility');
    },

    setSize: function (width, height) {
        var me = this;
        width = width || me.width;
        height = height || me.height;
        me.width = width;
        me.height = height;

        if (me.el) {
            
            if (width != undefined) {
                me.el.setWidth(width);
            }
            if (height != undefined) {
                me.el.setHeight(height);
            }
        }

        me.callParent(arguments);
    },

    
    applyViewBox: function () {
        var me = this,
            viewBox = me.viewBox,
            width = me.width,
            height = me.height,
            items,
            iLen,
            i;
        
        me.callParent();

        if (viewBox && (width || height)) {
            items = me.items.items;
            iLen = items.length;

            for (i = 0; i < iLen; i++) {
                me.applyTransformations(items[i]);
            }
        }
    },

    onAdd: function (item) {
        this.callParent(arguments);
        if (this.el) {
            this.renderItem(item);
        }
    },

    onRemove: function (sprite) {
        if (sprite.el) {
            sprite.el.remove();
            delete sprite.el;
        }
        this.callParent(arguments);
    },

    render: function (container) {
        var me = this,
            doc = Ext.getDoc().dom,
            el;
        
        if (!me.createNode) {
            try {
                if (!doc.namespaces.rvml) {
                    doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
                }
                me.createNode = function (tagName) {
                    return doc.createElement("<rvml:" + tagName + ' class="rvml">');
                };
            } catch (e) {
                me.createNode = function (tagName) {
                    return doc.createElement("<" + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
                };
            }
        }

        if (!me.el) {
            el = doc.createElement("div");
            me.el = Ext.get(el);
            me.el.addCls(me.baseVmlCls);

            
            me.span = doc.createElement("span");
            Ext.get(me.span).addCls(me.measureSpanCls);
            el.appendChild(me.span);
            me.el.setSize(me.width || 0, me.height || 0);
            container.appendChild(el);
            me.el.on({
                scope: me,
                mouseup: me.onMouseUp,
                mousedown: me.onMouseDown,
                mouseover: me.onMouseOver,
                mouseout: me.onMouseOut,
                mousemove: me.onMouseMove,
                mouseenter: me.onMouseEnter,
                mouseleave: me.onMouseLeave,
                click: me.onClick,
                dblclick: me.onDblClick
            });
        }
        me.renderAll();
    },

    renderAll: function () {
        this.items.each(this.renderItem, this);
    },

    redraw: function (sprite) {
        sprite.dirty = true;
        this.renderItem(sprite);
    },

    renderItem: function (sprite) {
        
        if (!this.el) {
            return;
        }

        
        if (!sprite.el) {
            this.createSpriteElement(sprite);
        }

        if (sprite.dirty) {
            this.applyAttrs(sprite);
            if (sprite.dirtyTransform) {
                this.applyTransformations(sprite);
            }
        }
    },

    rotationCompensation: function (deg, dx, dy) {
        var matrix = new Ext.draw.Matrix();
        matrix.rotate(-deg, 0.5, 0.5);
        return {
            x: matrix.x(dx, dy),
            y: matrix.y(dx, dy)
        };
    },

    transform: function (sprite, matrixOnly) {
        var me = this,
            bbox = me.getBBox(sprite, true),
            cx = bbox.x + bbox.width * 0.5,
            cy = bbox.y + bbox.height * 0.5,
            matrix = new Ext.draw.Matrix(),
            transforms = sprite.transformations,
            transformsLength = transforms.length,
            i = 0,
            deltaDegrees = 0,
            deltaScaleX = 1,
            deltaScaleY = 1,
            flip = "",
            el = sprite.el,
            dom = el.dom,
            domStyle = dom.style,
            zoom = me.zoom,
            skew = sprite.skew,
            shift = me.viewBoxShift,
            deltaX, deltaY, transform, type, compensate, y, fill, newAngle, zoomScaleX, zoomScaleY, newOrigin, offset;


        for (; i < transformsLength; i++) {
            transform = transforms[i];
            type = transform.type;
            if (type == "translate") {
                matrix.translate(transform.x, transform.y);
            }
            else if (type == "rotate") {
                matrix.rotate(transform.degrees, transform.x, transform.y);
                deltaDegrees += transform.degrees;
            }
            else if (type == "scale") {
                matrix.scale(transform.x, transform.y, transform.centerX, transform.centerY);
                deltaScaleX *= transform.x;
                deltaScaleY *= transform.y;
            }
        }

        sprite.matrix = matrix.clone();

        if (matrixOnly) {
            return;
        }

        if (shift) {
            matrix.prepend(shift.scale, 0, 0, shift.scale, shift.dx * shift.scale, shift.dy * shift.scale);
        }

        
        if (sprite.type != "image" && skew) {
            skew.origin = "0,0";
            
            skew.matrix = matrix.toString();
            
            
            
            offset = matrix.offset();
            if (offset[0] > 32767) {
                offset[0] = 32767;
            } else if (offset[0] < -32768) {
                offset[0] = -32768;
            }
            if (offset[1] > 32767) {
                offset[1] = 32767;
            } else if (offset[1] < -32768) {
                offset[1] = -32768;
            }
            skew.offset = offset;
        }
        else {
            domStyle.filter = matrix.toFilter();
            domStyle.left = Math.min(
                matrix.x(bbox.x, bbox.y),
                matrix.x(bbox.x + bbox.width, bbox.y),
                matrix.x(bbox.x, bbox.y + bbox.height),
                matrix.x(bbox.x + bbox.width, bbox.y + bbox.height)) + 'px';
            domStyle.top = Math.min(
                matrix.y(bbox.x, bbox.y),
                matrix.y(bbox.x + bbox.width, bbox.y),
                matrix.y(bbox.x, bbox.y + bbox.height),
                matrix.y(bbox.x + bbox.width, bbox.y + bbox.height)) + 'px';
        }
    },

    createItem: function (config) {
        return Ext.create('Ext.draw.Sprite', config);
    },

    getRegion: function () {
        return this.el.getRegion();
    },

    addCls: function (sprite, className) {
        if (sprite && sprite.el) {
            sprite.el.addCls(className);
        }
    },

    removeCls: function (sprite, className) {
        if (sprite && sprite.el) {
            sprite.el.removeCls(className);
        }
    },

    
    addGradient: function (gradient) {
        var gradients = this.gradientsColl || (this.gradientsColl = Ext.create('Ext.util.MixedCollection')),
            colors = [],
            stops = Ext.create('Ext.util.MixedCollection'),
            keys,
            items,
            iLen,
            key,
            item,
            i;

        
        stops.addAll(gradient.stops);
        stops.sortByKey("ASC", function (a, b) {
            a = parseInt(a, 10);
            b = parseInt(b, 10);
            return a > b ? 1 : (a < b ? -1 : 0);
        });

        keys = stops.keys;
        items = stops.items;
        iLen = keys.length;

        for (i = 0; i < iLen; i++) {
            key = keys[i];
            item = items[i];
            colors.push(key + '% ' + item.color);
        }

        gradients.add(gradient.id, {
            colors: colors.join(","),
            angle: gradient.angle
        });
    },

    destroy: function () {
        var me = this;

        me.callParent(arguments);
        if (me.el) {
            me.el.remove();
        }
        delete me.el;
    }
});


Ext.define('Ext.dd.DragZone', {
    extend: 'Ext.dd.DragSource',

    
    constructor : function(el, config){
        this.callParent([el, config]);
        if (this.containerScroll) {
            Ext.dd.ScrollManager.register(this.el);
        }
    },

    

    

    
    getDragData : function(e){
        return Ext.dd.Registry.getHandleFromEvent(e);
    },

    
    onInitDrag : function(x, y){
        this.proxy.update(this.dragData.ddel.cloneNode(true));
        this.onStartDrag(x, y);
        return true;
    },

    
    afterRepair : function(){
        var me = this;
        if (Ext.enableFx) {
            Ext.fly(me.dragData.ddel).highlight(me.repairHighlightColor);
        }
        me.dragging = false;
    },

    
    getRepairXY : function(e){
        return Ext.fly(this.dragData.ddel).getXY();
    },

    destroy : function(){
        this.callParent();
        if (this.containerScroll) {
            Ext.dd.ScrollManager.unregister(this.el);
        }
    }
});


Ext.define('Ext.flash.Component', {
    extend: 'Ext.Component',
    alternateClassName: 'Ext.FlashComponent',
    alias: 'widget.flash',

    
    flashVersion : '9.0.115',

    
    backgroundColor: '#ffffff',

    
    wmode: 'opaque',

    

    

    

    

    
    swfWidth: '100%',

    
    swfHeight: '100%',

    
    expressInstall: false,

    

    
    renderTpl: ['<div id="{swfId}"></div>'],

    initComponent: function() {

        this.callParent();
        this.addEvents(
            
            'success',

            
            'failure'
        );
    },
    
    beforeRender: function(){
        this.callParent();
        
        Ext.applyIf(this.renderData, {
            swfId: this.getSwfId()
        });
    },

    afterRender: function() {
        var me = this,
            flashParams = Ext.apply({}, me.flashParams), 
            flashVars = Ext.apply({}, me.flashVars);

        me.callParent();

        flashParams = Ext.apply({
            allowScriptAccess: 'always',
            bgcolor: me.backgroundColor,
            wmode: me.wmode
        }, flashParams);

        flashVars = Ext.apply({
            allowedDomain: document.location.hostname
        }, flashVars);

        new swfobject.embedSWF(
            me.url,
            me.getSwfId(),
            me.swfWidth,
            me.swfHeight,
            me.flashVersion,
            me.expressInstall ? me.statics.EXPRESS_INSTALL_URL : undefined,
            flashVars,
            flashParams,
            me.flashAttributes,
            Ext.bind(me.swfCallback, me)
        );
    },

    
    swfCallback: function(e) {
        var me = this;
        if (e.success) {
            me.swf = Ext.get(e.ref);
            me.onSuccess();
            me.fireEvent('success', me);
        } else {
            me.onFailure();
            me.fireEvent('failure', me);
        }
    },

    
    getSwfId: function() {
        return this.swfId || (this.swfId = "extswf" + this.getAutoId());
    },

    onSuccess: function() {
        
        
        this.swf.setStyle('visibility', 'inherit');
    },

    onFailure: Ext.emptyFn,

    beforeDestroy: function() {
        var me = this,
            swf = me.swf;
        if (swf) {
            swfobject.removeSWF(me.getSwfId());
            Ext.destroy(swf);
            delete me.swf;
        }
        me.callParent();
    },

    statics: {
        
        EXPRESS_INSTALL_URL: 'http:/' + '/swfobject.googlecode.com/svn/trunk/swfobject/expressInstall.swf'
    }
});


Ext.define('Ext.form.CheckboxManager', {
    extend: 'Ext.util.MixedCollection',
    singleton: true,

    getByName: function(name) {
        return this.filterBy(function(item) {
            return item.name == name;
        });
    },

    getWithValue: function(name, value) {
        return this.filterBy(function(item) {
            return item.name == name && item.inputValue == value;
        });
    },

    getChecked: function(name) {
        return this.filterBy(function(item) {
            return item.name == name && item.checked;
        });
    }
});


Ext.define('Ext.form.Label', {
    extend:'Ext.Component',
    alias: 'widget.label',
    requires: ['Ext.util.Format'],

    autoEl: 'label',

    
    
    
    
    maskOnDisable: false,

    getElConfig: function(){
        var me = this;

        me.html = me.text ? Ext.util.Format.htmlEncode(me.text) : (me.html || '');
        return Ext.apply(me.callParent(), {
            htmlFor: me.forId || ''
        });
    },

    
    setText : function(text, encode){
        var me = this;
        
        encode = encode !== false;
        if(encode) {
            me.text = text;
            delete me.html;
        } else {
            me.html = text;
            delete me.text;
        }
        
        if(me.rendered){
            me.el.dom.innerHTML = encode !== false ? Ext.util.Format.htmlEncode(text) : text;
            me.updateLayout();
        }
        return me;
    }
});



Ext.define("Ext.form.Labelable", {
    requires: ['Ext.XTemplate'],

    autoEl: {
        tag: 'table',
        cellpadding: 0
    },

    childEls: [
        
        'labelCell',

        
        'labelEl',

        
        'bodyEl',

        
        'sideErrorCell',

        
        'errorEl',

        'inputRow',

        'bottomPlaceHolder'
    ],

    
    labelableRenderTpl: [

        
        '<tr id="{id}-inputRow" <tpl if="inFormLayout">id="{id}"</tpl>>',

            
            '<tpl if="labelOnLeft">',
                '<td id="{id}-labelCell" style="{labelCellStyle}" {labelCellAttrs}>',
                    '{beforeLabelTpl}',
                    '<label id="{id}-labelEl" {labelAttrTpl}<tpl if="inputId"> for="{inputId}"</tpl> class="{labelCls}"',
                        '<tpl if="labelStyle"> style="{labelStyle}"</tpl>>',
                        '{beforeLabelTextTpl}',
                        '<tpl if="fieldLabel">{fieldLabel}{labelSeparator}</tpl>',
                        '{afterLabelTextTpl}',
                    '</label>',
                    '{afterLabelTpl}',
                '</td>',
            '</tpl>',

            
            '<td class="{baseBodyCls} {fieldBodyCls}" id="{id}-bodyEl" colspan="{bodyColspan}" role="presentation">',
                '{beforeBodyEl}',

                
                '<tpl if="labelAlign==\'top\'">',
                    '{beforeLabelTpl}',
                    '<div id="{id}-labelCell" style="{labelCellStyle}">',
                        '<label id="{id}-labelEl" {labelAttrTpl}<tpl if="inputId"> for="{inputId}"</tpl> class="{labelCls}"',
                            '<tpl if="labelStyle"> style="{labelStyle}"</tpl>>',
                            '{beforeLabelTextTpl}',
                            '<tpl if="fieldLabel">{fieldLabel}{labelSeparator}</tpl>',
                            '{afterLabelTextTpl}',
                        '</label>',
                    '</div>',
                    '{afterLabelTpl}',
                '</tpl>',

                '{beforeSubTpl}',
                '{[values.$comp.getSubTplMarkup()]}',
                '{afterSubTpl}',

            
            '<tpl if="msgTarget===\'side\'">',
                '{afterBodyEl}',
                '</td>',
                '<td id="{id}-sideErrorCell" vAlign="{[values.labelAlign===\'top\' && !values.hideLabel ? \'bottom\' : \'middle\']}" style="{[values.autoFitErrors ? \'display:none\' : \'\']}" width="{errorIconWidth}">',
                    '<div id="{id}-errorEl" class="{errorMsgCls}" style="display:none;width:{errorIconWidth}px"></div>',
                '</td>',
            '<tpl elseif="msgTarget==\'under\'">',
                '<div id="{id}-errorEl" class="{errorMsgClass}" colspan="2" style="display:none"></div>',
                '{afterBodyEl}',
                '</td>',
            '</tpl>',

        '</tr>',
        {
            disableFormats: true
        }
    ],

    
    activeErrorsTpl: [
        '<tpl if="errors && errors.length">',
            '<ul><tpl for="errors"><li>{.}</li></tpl></ul>',
        '</tpl>'
    ],

    
    isFieldLabelable: true,

    
    formItemCls: Ext.baseCSSPrefix + 'form-item',

    
    labelCls: Ext.baseCSSPrefix + 'form-item-label',

    

    
    errorMsgCls: Ext.baseCSSPrefix + 'form-error-msg',

    
    baseBodyCls: Ext.baseCSSPrefix + 'form-item-body',

    
    fieldBodyCls: '',

    
    clearCls: Ext.baseCSSPrefix + 'clear',

    
    invalidCls : Ext.baseCSSPrefix + 'form-invalid',

    
    fieldLabel: undefined,

    
    labelAlign : 'left',

    
    labelWidth: 100,

    
    labelPad : 5,

    
    
    labelSeparator : ':',
    

    

    
    hideLabel: false,

    
    hideEmptyLabel: true,

    
    preventMark: false,

    
    autoFitErrors: true,

    
    msgTarget: 'qtip',

    

    
    noWrap: true,

    labelableInsertions: [

        
        'beforeBodyEl',

        
        'afterBodyEl',

        
        'beforeLabelTpl',

        
        'afterLabelTpl',

        
        'beforeSubTpl',

        
        'afterSubTpl',

        
        'beforeLabelTextTpl',

        
        'afterLabelTextTpl',

        
        'labelAttrTpl'
    ],

    
    labelableRenderProps: [ 'allowBlank', 'id', 'labelAlign', 'fieldBodyCls', 'baseBodyCls',
                            'clearCls', 'labelSeparator', 'msgTarget' ],

    
    initLabelable: function() {
        var me = this,
            padding = me.padding;

        
        
        
        if (padding) {
            me.padding = undefined;
            me.extraMargins = Ext.Element.parseBox(padding);
        }

        me.addCls(me.formItemCls);
        
        
        me.lastActiveError = '';

        me.addEvents(
            
            'errorchange'
        );
    },

    
    trimLabelSeparator: function() {
        var me = this,
            separator = me.labelSeparator,
            label = me.fieldLabel || '',
            lastChar = label.substr(label.length - 1);

        
        return lastChar === separator ? label.slice(0, -1) : label;
    },

    
    getFieldLabel: function() {
        return this.trimLabelSeparator();
    },
    
    
    setFieldLabel: function(label){
        label = label || '';
        
        var me = this,
            separator = me.labelSeparator,
            labelEl = me.labelEl;
        
        me.fieldLabel = label;
        if (me.rendered) {
            if (Ext.isEmpty(label) && me.hideEmptyLabel) {
                labelEl.parent().setDisplayed('none');
            } else {
                if (separator) {
                    label = me.trimLabelSeparator() + separator;
                }
                labelEl.update(label);
                labelEl.parent().setDisplayed('');
            }
            me.updateLayout();
        }
    },

    getInsertionRenderData: function (data, names) {
        var i = names.length,
            name, value;

        while (i--) {
            name = names[i];
            value = this[name];

            if (value) {
                if (typeof value != 'string') {
                    if (!value.isTemplate) {
                        value = Ext.XTemplate.getTpl(this, name);
                    }
                    value = value.apply(data);
                }
            }

            data[name] = value || '';
        }

        return data;
    },

    
    getLabelableRenderData: function() {
        var me = this,
            data,
            tempEl,
            topLabel = me.labelAlign === 'top';

        if (!Ext.form.Labelable.errorIconWidth) {
            Ext.form.Labelable.errorIconWidth = (tempEl = Ext.resetElement.createChild({style: 'position:absolute', cls: Ext.baseCSSPrefix + 'form-invalid-icon'})).getWidth();
            tempEl.remove();
        }

        data = Ext.copyTo({
            inFormLayout   : me.ownerLayout && me.ownerLayout.type === 'form',
            inputId        : me.getInputId(),
            labelOnLeft    : !topLabel,
            hideLabel      : !me.hasVisibleLabel(),
            fieldLabel     : me.getFieldLabel(),
            labelCellStyle : me.getLabelCellStyle(),
            labelCellAttrs : me.getLabelCellAttrs(),
            labelCls       : me.getLabelCls(),
            labelStyle     : me.getLabelStyle(),
            bodyColspan    : me.getBodyColspan(),
            externalError  : !me.autoFitErrors,
            errorMsgCls    : me.getErrorMsgCls(),
            errorIconWidth : Ext.form.Labelable.errorIconWidth
        },
        me, me.labelableRenderProps, true);

        me.getInsertionRenderData(data, me.labelableInsertions);

        return data;
    },
    
    beforeLabelableRender: function() {
        var me = this;
        if (me.ownerLayout) {
            me.addCls(Ext.baseCSSPrefix + me.ownerLayout.type + '-form-item');
        }
    },

    onLabelableRender: function() {
        var me = this,
            margins,
            side,
            style = {};

        if (me.extraMargins) {
            margins = me.el.getMargin();
            for (side in margins) {
                if (margins.hasOwnProperty(side)) {
                    style['margin-' + side] = (margins[side] + me.extraMargins[side]) + 'px';
                }
            }
            me.el.setStyle(style);
        }
    },
    
    
    hasVisibleLabel: function(){
        if (this.hideLabel) {
            return false;
        }
        return !(this.hideEmptyLabel && !this.getFieldLabel());
    },
    
    
    getBodyColspan: function() {
        var me = this,
            result;

        if (me.msgTarget === 'side' && (!me.autoFitErrors || me.hasActiveError())) {
            result = 1;
        } else {
            result = 2;
        }
        if (me.labelAlign !== 'top' && !me.hasVisibleLabel()) {
            result++;
        }
        return result;
    },
    
    getLabelCls: function() {
        var labelCls = this.labelCls,
            labelClsExtra = this.labelClsExtra;

        if (this.labelAlign === 'top') {
            labelCls += '-top';
        }
        return labelClsExtra ? labelCls + ' ' + labelClsExtra : labelCls;
    },

    getLabelCellStyle: function() {
        var me = this,
            hideLabelCell = me.hideLabel || (!me.fieldLabel && me.hideEmptyLabel);

        return hideLabelCell ? 'display:none;' : '';
    },
    
    getErrorMsgCls: function() {
        var me = this,
            hideLabelCell = (me.hideLabel || (!me.fieldLabel && me.hideEmptyLabel));
        
        return me.errorMsgCls + (!hideLabelCell && me.labelAlign === 'top' ? ' ' + Ext.baseCSSPrefix + 'lbl-top-err-icon' : '');
    },

    getLabelCellAttrs: function() {
        var me = this,
            labelAlign = me.labelAlign,
            result = '';

        if (labelAlign !== 'top') {
            result = 'valign="top" halign="' + labelAlign + '" width="' + (me.labelWidth + me.labelPad) + '"';
        }
        return result + ' class="' + Ext.baseCSSPrefix + 'field-label-cell"';
    },
    
    
    getLabelStyle: function(){
        var me = this,
            labelPad = me.labelPad,
            labelStyle = '';

        
        
        if (me.labelAlign !== 'top') {
            if (me.labelWidth) {
                labelStyle = 'width:' + me.labelWidth + 'px;';
            }
            labelStyle += 'margin-right:' + labelPad + 'px;';
        }
        
        return labelStyle + (me.labelStyle || '');
    },

    
    getSubTplMarkup: function() {
        return '';
    },

    
    getInputId: function() {
        return '';
    },

    
    getActiveError : function() {
        return this.activeError || '';
    },

    
    hasActiveError: function() {
        return !!this.getActiveError();
    },

    
    setActiveError: function(msg) {
        this.setActiveErrors(msg);
    },

    
    getActiveErrors: function() {
        return this.activeErrors || [];
    },

    
    setActiveErrors: function(errors) {
        errors = Ext.Array.from(errors);
        this.activeError = errors[0];
        this.activeErrors = errors;
        this.activeError = this.getTpl('activeErrorsTpl').apply({errors: errors});
        this.renderActiveError();
    },

    
    unsetActiveError: function() {
        delete this.activeError;
        delete this.activeErrors;
        this.renderActiveError();
    },

    
    renderActiveError: function() {
        var me = this,
            activeError = me.getActiveError(),
            hasError = !!activeError;

        if (activeError !== me.lastActiveError) {
            me.fireEvent('errorchange', me, activeError);
            me.lastActiveError = activeError;
        }

        if (me.rendered && !me.isDestroyed && !me.preventMark) {
            
            me.el[hasError ? 'addCls' : 'removeCls'](me.invalidCls);

            
            me.getActionEl().dom.setAttribute('aria-invalid', hasError);

            
            if (me.errorEl) {
                me.errorEl.dom.innerHTML = activeError;
            }
        }
    },

    
    setFieldDefaults: function(defaults) {
        var me = this,
            val, key;

        for (key in defaults) {
            if (defaults.hasOwnProperty(key)) {
                val = defaults[key];

                if (!me.hasOwnProperty(key)) {
                    me[key] = val;
                }
            }
        }
    }
});


Ext.define('Ext.form.RadioManager', {
    extend: 'Ext.util.MixedCollection',
    singleton: true,

    getByName: function(name, formId) {
        return this.filterBy(function(item) {
            return item.name == name && item.getFormId() == formId;
        });
    },

    getWithValue: function(name, value, formId) {
        return this.filterBy(function(item) {
            return item.name == name && item.inputValue == value && item.getFormId() == formId;
        });
    },

    getChecked: function(name, formId) {
        return this.findBy(function(item) {
            return item.name == name && item.checked && item.getFormId() == formId;
        });
    }
});


Ext.define('Ext.form.action.DirectSubmit', {
    extend:'Ext.form.action.Submit',
    requires: ['Ext.direct.Manager'],
    alternateClassName: 'Ext.form.Action.DirectSubmit',
    alias: 'formaction.directsubmit',

    type: 'directsubmit',

    doSubmit: function() {
        var me = this,
            callback = Ext.Function.bind(me.onComplete, me),
            formEl = me.buildForm();
        me.form.api.submit(formEl, callback, me);
        Ext.removeNode(formEl);
    },

    
    
    
    processResponse: function(result) {
        return (this.result = result);
    },
    
    onComplete: function(data, response){
        if (data) {
            this.onSuccess(data);
        } else {
            this.onFailure(null);
        }
    }
});


Ext.define('Ext.form.action.Load', {
    extend:'Ext.form.action.Action',
    requires: ['Ext.data.Connection'],
    alternateClassName: 'Ext.form.Action.Load',
    alias: 'formaction.load',

    type: 'load',

    
    run: function() {
        Ext.Ajax.request(Ext.apply(
            this.createCallback(),
            {
                method: this.getMethod(),
                url: this.getUrl(),
                headers: this.headers,
                params: this.getParams()
            }
        ));
    },

    
    onSuccess: function(response){
        var result = this.processResponse(response),
            form = this.form;
        if (result === true || !result.success || !result.data) {
            this.failureType = Ext.form.action.Action.LOAD_FAILURE;
            form.afterAction(this, false);
            return;
        }
        form.clearInvalid();
        form.setValues(result.data);
        form.afterAction(this, true);
    },

    
    handleResponse: function(response) {
        var reader = this.form.reader,
            rs, data;
        if (reader) {
            rs = reader.read(response);
            data = rs.records && rs.records[0] ? rs.records[0].data : null;
            return {
                success : rs.success,
                data : data
            };
        }
        return Ext.decode(response.responseText);
    }
});



Ext.define('Ext.form.action.DirectLoad', {
    extend:'Ext.form.action.Load',
    requires: ['Ext.direct.Manager'],
    alternateClassName: 'Ext.form.Action.DirectLoad',
    alias: 'formaction.directload',

    type: 'directload',

    run: function() {
        var me = this,
            form = me.form,
            fn = form.api.load,
            method = fn.directCfg.method,
            args = method.getArgs(me.getParams(), form.paramOrder, form.paramsAsHash);
            
        args.push(me.onComplete, me);
        fn.apply(window, args);
    },

    
    
    
    processResponse: function(result) {
        return (this.result = result);
    },

    onComplete: function(data, response) {
        if (data) {
            this.onSuccess(data);
        } else {
            this.onFailure(null);
        }
    }
});




Ext.define('Ext.form.action.StandardSubmit', {
    extend:'Ext.form.action.Submit',
    alias: 'formaction.standardsubmit',

    

    
    doSubmit: function() {
        var form = this.buildForm();
        form.submit();
        Ext.removeNode(form);
    }

});


Ext.define('Ext.grid.ColumnComponentLayout', {
    extend: 'Ext.layout.component.Auto',
    alias: 'layout.columncomponent',

    type: 'columncomponent',

    setWidthInDom: true,

    getContentHeight : function(ownerContext) {
        
        return this.owner.isGroupHeader ? ownerContext.getProp('contentHeight') : this.callParent(arguments);
    },

    calculateOwnerHeightFromContentHeight: function (ownerContext, contentHeight) {
        var result = this.callParent(arguments);
        if (this.owner.isGroupHeader) {
            result += this.owner.titleEl.dom.offsetHeight;
        }
        return result;
    },
    
    getContentWidth : function(ownerContext) {
        
        return this.owner.isGroupHeader ? ownerContext.getProp('contentWidth') : this.callParent(arguments);
    },

    calculateOwnerWidthFromContentWidth: function (ownerContext, contentWidth) {
        return contentWidth + ownerContext.getPaddingInfo().width;
    }
});

Ext.define('Ext.grid.feature.AbstractSummary', {
    
    

    extend: 'Ext.grid.feature.Feature',
    
    alias: 'feature.abstractsummary',

    

   
    showSummaryRow: true,

    
    nestedIdRe: /\{\{id\}([\w\-]*)\}/g,

    
    init: function() {
        var me = this;

        
        me.grid.optimizedColumnMove = false;

        me.view.mon(me.view.store, {
            update: me.onStoreUpdate,
            scope: me
        });
    },

    
    onStoreUpdate: function() {
        var v = this.view;
        if (this.showSummaryRow) {
            v.saveScrollState();
            v.refresh();
            v.restoreScrollState();
        }
    },

    
    toggleSummaryRow: function(visible){
        this.showSummaryRow = !!visible;
    },

    
    getSummaryFragments: function(){
        var fragments = {};
        if (this.showSummaryRow) {
            Ext.apply(fragments, {
                printSummaryRow: Ext.bind(this.printSummaryRow, this)
            });
        }
        return fragments;
    },

    
    printSummaryRow: function(index){
        var inner = this.view.getTableChunker().metaRowTpl.join(''),
            prefix = Ext.baseCSSPrefix;

        inner = inner.replace(prefix + 'grid-row', prefix + 'grid-row-summary');
        inner = inner.replace('{{id}}', '{gridSummaryValue}');
        inner = inner.replace(this.nestedIdRe, '{id$1}');  
        inner = inner.replace('{[this.embedRowCls()]}', '{rowCls}');
        inner = inner.replace('{[this.embedRowAttr()]}', '{rowAttr}');
        inner = new Ext.XTemplate(inner, {
            firstOrLastCls: Ext.view.TableChunker.firstOrLastCls
        });

        return inner.applyTemplate({
            columns: this.getPrintData(index)
        });
    },

    
    getColumnValue: function(column, summaryData){
        var comp     = Ext.getCmp(column.id),
            value    = summaryData[column.id],
            renderer = comp.summaryRenderer;
            
        if (!value && value !== 0) {
            value = '\u00a0';
        }

        if (renderer) {
            value = renderer.call(
                comp.scope || this,
                value,
                summaryData,
                column.dataIndex
            );
        }
        return value;
    },

    
    getSummary: function(store, type, field, group){
        if (type) {
            if (Ext.isFunction(type)) {
                return store.aggregate(type, null, group);
            }

            switch (type) {
                case 'count':
                    return store.count(group);
                case 'min':
                    return store.min(field, group);
                case 'max':
                    return store.max(field, group);
                case 'sum':
                    return store.sum(field, group);
                case 'average':
                    return store.average(field, group);
                default:
                    return group ? {} : '';
                    
            }
        }
    }

});


Ext.define('Ext.grid.feature.Chunking', {
    extend: 'Ext.grid.feature.Feature',
    alias: 'feature.chunking',

    chunkSize: 20,
    rowHeight: Ext.isIE ? 27 : 26,
    visibleChunk: 0,
    hasFeatureEvent: false,
    attachEvents: function() {
        this.view.el.on('scroll', this.onBodyScroll, this, {buffer: 300});
    },

    onBodyScroll: function(e, t) {
        var view = this.view,
            top  = t.scrollTop,
            nextChunk = Math.floor(top / this.rowHeight / this.chunkSize);
        if (nextChunk !== this.visibleChunk) {

            this.visibleChunk = nextChunk;
            view.refresh();
            view.el.dom.scrollTop = top;
            
            view.el.dom.scrollTop = top;
        }
    },

    collectData: function(records, preppedRecords, startIndex, fullWidth, o) {
        
        
        var me = this,
            recordCount = o.rows.length,
            start = 0,
            i = 0,
            visibleChunk = me.visibleChunk,
            rows,
            chunkLength,
            origRows = o.rows;

        delete o.rows;
        o.chunks = [];
        for (; start < recordCount; start += me.chunkSize, i++) {
            if (start + me.chunkSize > recordCount) {
                chunkLength = recordCount - start;
            } else {
                chunkLength = me.chunkSize;
            }
            
            if (i >= visibleChunk - 1 && i <= visibleChunk + 1) {
                rows = origRows.slice(start, start + me.chunkSize);
            } else {
                rows = [];
            }
            o.chunks.push({
                rows: rows,
                fullWidth: fullWidth,
                chunkHeight: chunkLength * me.rowHeight
            });
        }

        return o;
    },

    getTableFragments: function() {
        return {
            openTableWrap: function() {
                return '<tpl for="chunks"><div class="' + Ext.baseCSSPrefix + 'grid-chunk" style="height: {chunkHeight}px;">';
            },
            closeTableWrap: function() {
                return '</div></tpl>';
            }
        };
    }
});


Ext.define('Ext.grid.feature.GroupingSummary', {

    

    extend: 'Ext.grid.feature.Grouping',

    alias: 'feature.groupingsummary',

    mixins: {
        summary: 'Ext.grid.feature.AbstractSummary'
    },

    

    init: function() {
        this.mixins.summary.init.call(this);
    },

   
   getFeatureTpl: function() {
        var tpl = this.callParent(arguments);

        if (this.showSummaryRow) {
            
            tpl = tpl.replace('</tpl>', '');
            tpl += '{[this.printSummaryRow(xindex)]}</tpl>';
        }
        return tpl;
    },

    
    getFragmentTpl: function() {
        var me = this,
            fragments = me.callParent();

        Ext.apply(fragments, me.getSummaryFragments());
        if (me.showSummaryRow) {
            
            me.summaryGroups = me.view.store.getGroups();
            me.summaryData = me.generateSummaryData();
        }
        return fragments;
    },

    
    getPrintData: function(index){
        var me = this,
            columns = me.view.headerCt.getColumnsForTpl(),
            i = 0,
            length = columns.length,
            data = [],
            name = me.summaryGroups[index - 1].name,
            active = me.summaryData[name],
            column;

        for (; i < length; ++i) {
            column = columns[i];
            column.gridSummaryValue = this.getColumnValue(column, active);
            data.push(column);
        }
        return data;
    },

    
    generateSummaryData: function(){
        var me = this,
            data = {},
            remoteData = {},
            store = me.view.store,
            groupField = this.getGroupField(),
            reader = store.proxy.reader,
            groups = me.summaryGroups,
            columns = me.view.headerCt.getColumnsForTpl(),
            remote,
            i,
            length,
            fieldData,
            root,
            key,
            comp,
            summaryRows,
            s,
            sLen,
            convertedSummaryRow;

        for (i = 0, length = groups.length; i < length; ++i) {
            data[groups[i].name] = {};
        }

        
        if (me.remoteRoot && reader.rawData) {
            
            root = reader.root;
            reader.root = me.remoteRoot;
            reader.buildExtractors(true);
            summaryRows = reader.getRoot(reader.rawData);
            sLen      = summaryRows.length;

            
            if (!reader.convertRecordData) {
                reader.buildExtractors();
            }

            for (s = 0; s < sLen; s++) {
                convertedSummaryRow = {};

                
                reader.convertRecordData(convertedSummaryRow, summaryRows[s]);
                remoteData[convertedSummaryRow[groupField]] = convertedSummaryRow;
            }

            
            reader.root = root;
            reader.buildExtractors(true);
        }

        for (i = 0, length = columns.length; i < length; ++i) {
            comp = Ext.getCmp(columns[i].id);
            fieldData = me.getSummary(store, comp.summaryType, comp.dataIndex, true);

            for (key in fieldData) {
                if (fieldData.hasOwnProperty(key)) {
                    data[key][comp.id] = fieldData[key];
                }
            }

            for (key in remoteData) {
                if (remoteData.hasOwnProperty(key)) {
                    remote = remoteData[key][comp.dataIndex];
                    if (remote !== undefined && data[key] !== undefined) {
                        data[key][comp.id] = remote;
                    }
                }
            }
        }
        return data;
    }
});


Ext.define('Ext.grid.feature.Summary', {
    
    
    
    extend: 'Ext.grid.feature.AbstractSummary',
    
    alias: 'feature.summary',
    
    
    
    
    getFragmentTpl: function() {
        
        this.summaryData = this.generateSummaryData(); 
        return this.getSummaryFragments();
    },
    
    
    getTableFragments: function(){
        if (this.showSummaryRow) {
            return {
                closeRows: this.closeRows
            };
        }
    },
    
    
    closeRows: function() {
        return '</tpl>{[this.printSummaryRow()]}';
    },
    
    
    getPrintData: function(index){
        var me = this,
            columns = me.view.headerCt.getColumnsForTpl(),
            i = 0,
            length = columns.length,
            data = [],
            active = me.summaryData,
            column;
            
        for (; i < length; ++i) {
            column = columns[i];
            column.gridSummaryValue = this.getColumnValue(column, active);
            data.push(column);
        }
        return data;
    },
    
    
    generateSummaryData: function(){
        var me = this,
            data = {},
            store = me.view.store,
            columns = me.view.headerCt.getColumnsForTpl(),
            i = 0,
            length = columns.length,
            fieldData,
            key,
            comp;
            
        for (i = 0, length = columns.length; i < length; ++i) {
            comp = Ext.getCmp(columns[i].id);
            data[comp.id] = me.getSummary(store, comp.summaryType, comp.dataIndex, false);
        }
        return data;
    }
});

Ext.define('Ext.grid.header.DragZone', {
    extend: 'Ext.dd.DragZone',
    colHeaderCls: Ext.baseCSSPrefix + 'column-header',
    maxProxyWidth: 120,

    constructor: function(headerCt) {
        this.headerCt = headerCt;
        this.ddGroup =  this.getDDGroup();
        this.callParent([headerCt.el]);
        this.proxy.el.addCls(Ext.baseCSSPrefix + 'grid-col-dd');
    },

    getDDGroup: function() {
        return 'header-dd-zone-' + this.headerCt.up('[scrollerOwner]').id;
    },

    getDragData: function(e) {
        var header = e.getTarget('.'+this.colHeaderCls),
            headerCmp,
            ddel;

        if (header) {
            headerCmp = Ext.getCmp(header.id);
            if (!this.headerCt.dragging && headerCmp.draggable && !(headerCmp.isOnLeftEdge(e) || headerCmp.isOnRightEdge(e))) {
                ddel = document.createElement('div');
                ddel.innerHTML = Ext.getCmp(header.id).text;
                return {
                    ddel: ddel,
                    header: headerCmp
                };
            }
        }
        return false;
    },

    onBeforeDrag: function() {
        return !(this.headerCt.dragging || this.disabled);
    },

    onInitDrag: function() {
        this.headerCt.dragging = true;
        this.callParent(arguments);
    },

    onDragDrop: function() {
        this.headerCt.dragging = false;
        this.callParent(arguments);
    },

    afterRepair: function() {
        this.callParent();
        this.headerCt.dragging = false;
    },

    getRepairXY: function() {
        return this.dragData.header.el.getXY();
    },
    
    disable: function() {
        this.disabled = true;
    },
    
    enable: function() {
        this.disabled = false;
    }
});


Ext.define('Ext.grid.header.DropZone', {
    extend: 'Ext.dd.DropZone',
    colHeaderCls: Ext.baseCSSPrefix + 'column-header',
    proxyOffsets: [-4, -9],

    constructor: function(headerCt){
        this.headerCt = headerCt;
        this.ddGroup = this.getDDGroup();
        this.callParent([headerCt.el]);
    },

    getDDGroup: function() {
        return 'header-dd-zone-' + this.headerCt.up('[scrollerOwner]').id;
    },

    getTargetFromEvent : function(e){
        return e.getTarget('.' + this.colHeaderCls);
    },

    getTopIndicator: function() {
        if (!this.topIndicator) {
            this.topIndicator = Ext.DomHelper.append(Ext.getBody(), {
                cls: "col-move-top",
                html: "&#160;"
            }, true);
        }
        return this.topIndicator;
    },

    getBottomIndicator: function() {
        if (!this.bottomIndicator) {
            this.bottomIndicator = Ext.DomHelper.append(Ext.getBody(), {
                cls: "col-move-bottom",
                html: "&#160;"
            }, true);
        }
        return this.bottomIndicator;
    },

    getLocation: function(e, t) {
        var x      = e.getXY()[0],
            region = Ext.fly(t).getRegion(),
            pos, header;

        if ((region.right - x) <= (region.right - region.left) / 2) {
            pos = "after";
        } else {
            pos = "before";
        }
        return {
            pos: pos,
            header: Ext.getCmp(t.id),
            node: t
        };
    },

    positionIndicator: function(draggedHeader, node, e){
        var location = this.getLocation(e, node),
            header = location.header,
            pos    = location.pos,
            nextHd = draggedHeader.nextSibling('gridcolumn:not([hidden])'),
            prevHd = draggedHeader.previousSibling('gridcolumn:not([hidden])'),
            topIndicator, bottomIndicator, topAnchor, bottomAnchor,
            topXY, bottomXY, headerCtEl, minX, maxX,
            allDropZones, ln, i, dropZone;

        
        if (!header.draggable && header.getIndex() === 0) {
            return false;
        }

        this.lastLocation = location;

        if ((draggedHeader !== header) &&
            ((pos === "before" && nextHd !== header) ||
            (pos === "after" && prevHd !== header)) &&
            !header.isDescendantOf(draggedHeader)) {

            
            
            
            allDropZones = Ext.dd.DragDropManager.getRelated(this);
            ln = allDropZones.length;
            i  = 0;

            for (; i < ln; i++) {
                dropZone = allDropZones[i];
                if (dropZone !== this && dropZone.invalidateDrop) {
                    dropZone.invalidateDrop();
                }
            }


            this.valid = true;
            topIndicator = this.getTopIndicator();
            bottomIndicator = this.getBottomIndicator();
            if (pos === 'before') {
                topAnchor = 'tl';
                bottomAnchor = 'bl';
            } else {
                topAnchor = 'tr';
                bottomAnchor = 'br';
            }
            topXY = header.el.getAnchorXY(topAnchor);
            bottomXY = header.el.getAnchorXY(bottomAnchor);

            
            headerCtEl = this.headerCt.el;
            minX = headerCtEl.getLeft();
            maxX = headerCtEl.getRight();

            topXY[0] = Ext.Number.constrain(topXY[0], minX, maxX);
            bottomXY[0] = Ext.Number.constrain(bottomXY[0], minX, maxX);

            
            
            topXY[0] -= 4;
            topXY[1] -= 9;
            bottomXY[0] -= 4;

            
            topIndicator.setXY(topXY);
            bottomIndicator.setXY(bottomXY);
            topIndicator.show();
            bottomIndicator.show();
        
        } else {
            this.invalidateDrop();
        }
    },

    invalidateDrop: function() {
        this.valid = false;
        this.hideIndicators();
    },

    onNodeOver: function(node, dragZone, e, data) {
        var me = this,
            header = me.headerCt,
            doPosition = true,
            from = data.header,
            to;
            
        if (data.header.el.dom === node) {
            doPosition = false;
        } else {
            to = me.getLocation(e, node).header;
            doPosition = (from.ownerCt === to.ownerCt) || (!from.ownerCt.sealed && !to.ownerCt.sealed);
        }
        
        if (doPosition) {
            me.positionIndicator(data.header, node, e);
        } else {
            me.valid = false;
        }
        return me.valid ? me.dropAllowed : me.dropNotAllowed;
    },

    hideIndicators: function() {
        this.getTopIndicator().hide();
        this.getBottomIndicator().hide();
    },

    onNodeOut: function() {
        this.hideIndicators();
    },

    onNodeDrop: function(node, dragZone, e, data) {
        if (this.valid) {
            var dragHeader   = data.header,
                lastLocation = this.lastLocation,
                targetHeader = lastLocation.header,
                fromCt       = dragHeader.ownerCt,
                fromHeader   = dragHeader.up('headercontainer:not(gridcolumn)'),
                localFromIdx = fromCt.items.indexOf(dragHeader), 
                toCt         = targetHeader.ownerCt,
                toHeader     = targetHeader.up('headercontainer:not(gridcolumn)'),
                localToIdx   = toCt.items.indexOf(targetHeader),
                headerCt     = this.headerCt,
                fromIdx      = headerCt.getHeaderIndex(dragHeader),
                colsToMove   = dragHeader.isGroupHeader ? dragHeader.query(':not([isGroupHeader])').length : 1,
                toIdx        = headerCt.getHeaderIndex(targetHeader),
                groupCt,
                scrollerOwner;

            
            if (lastLocation.pos === 'after') {
                localToIdx++;
                toIdx += targetHeader.isGroupHeader ? targetHeader.query(':not([isGroupHeader])').length : 1;
            }

            
            
            
            if (fromHeader !== toHeader && fromHeader.lockableInjected && toHeader.lockableInjected && toHeader.lockedCt) {
                scrollerOwner = fromCt.up('[scrollerOwner]');
                scrollerOwner.lock(dragHeader, localToIdx);

                
                this.onNodeDrop(node, dragZone, e, data);
            } else if (fromHeader !== toHeader && fromHeader.lockableInjected && toHeader.lockableInjected && fromHeader.lockedCt) {
                scrollerOwner = fromCt.up('[scrollerOwner]');
                scrollerOwner.unlock(dragHeader, localToIdx);

                
                this.onNodeDrop(node, dragZone, e, data);
            }
            
            
            else {
                this.invalidateDrop();

                
                
                if ((fromCt === toCt) && (localToIdx > localFromIdx)) {

                    
                    localToIdx -= 1;
                }

                
                Ext.suspendLayouts();

                
                if (fromCt !== toCt) {
                    fromCt.remove(dragHeader, false);

                    
                    if (fromCt.isGroupHeader) {
                        if (!fromCt.items.getCount()) {
                            groupCt = fromCt.ownerCt;
                            groupCt.remove(fromCt, false);
                            fromCt.el.dom.parentNode.removeChild(fromCt.el.dom);
                        }
                    }
                }

                
                if (fromCt === toCt) {
                    toCt.move(localFromIdx, localToIdx);
                } else {
                    toCt.insert(localToIdx, dragHeader);
                }

                
                
                
                if (toCt.isGroupHeader) {
                    
                    if (toCt !== fromCt) {
                        dragHeader.savedFlex = dragHeader.flex;
                        delete dragHeader.flex;
                        dragHeader.width = dragHeader.getWidth();
                    }
                } else {
                    if (dragHeader.savedFlex) {
                        dragHeader.flex = dragHeader.savedFlex;
                        delete dragHeader.width;
                    }
                }

                
                headerCt.purgeCache();
                Ext.resumeLayouts(true);
                headerCt.onHeaderMoved(dragHeader, colsToMove, fromIdx, toIdx);

                
                if (!fromCt.items.getCount()) {
                    fromCt.destroy();
                }
            }
        }
    }
});


Ext.define('Ext.grid.plugin.HeaderReorderer', {
    extend: 'Ext.AbstractPlugin',
    requires: ['Ext.grid.header.DragZone', 'Ext.grid.header.DropZone'],
    alias: 'plugin.gridheaderreorderer',

    init: function(headerCt) {
        this.headerCt = headerCt;
        headerCt.on({
            render: this.onHeaderCtRender,
            single: true,
            scope: this
        });
    },

    
    destroy: function() {
        Ext.destroy(this.dragZone, this.dropZone);
    },

    onHeaderCtRender: function() {
        var me = this;
        
        me.dragZone = new Ext.grid.header.DragZone(me.headerCt);
        me.dropZone = new Ext.grid.header.DropZone(me.headerCt);
        if (me.disabled) {
            me.dragZone.disable();
        }
    },
    
    enable: function() {
        this.disabled = false;
        if (this.dragZone) {
            this.dragZone.enable();
        }
    },
    
    disable: function() {
        this.disabled = true;
        if (this.dragZone) {
            this.dragZone.disable();
        }
    }
});


Ext.define('Ext.grid.property.Property', {
    extend: 'Ext.data.Model',

    alternateClassName: 'Ext.PropGridProperty',

    fields: [{
        name: 'name',
        type: 'string'
    }, {
        name: 'value'
    }],
    idProperty: 'name'
});

Ext.define('Ext.grid.property.Store', {

    extend: 'Ext.data.Store',

    alternateClassName: 'Ext.grid.PropertyStore',

    sortOnLoad: false,

    uses: ['Ext.data.reader.Reader', 'Ext.data.proxy.Proxy', 'Ext.data.ResultSet', 'Ext.grid.property.Property'],

    
    constructor : function(grid, source){
        var me = this;
        
        me.grid = grid;
        me.source = source;
        me.callParent([{
            data: source,
            model: Ext.grid.property.Property,
            proxy: me.getProxy()
        }]);
    },

    
    getProxy: function() {
        if (!this.proxy) {
            Ext.grid.property.Store.prototype.proxy = new Ext.data.proxy.Memory({
                model: Ext.grid.property.Property,
                reader: this.getReader()
            });
        }
        return this.proxy;
    },

    
    getReader: function() {
        if (!this.reader) {
            Ext.grid.property.Store.prototype.reader = new Ext.data.reader.Reader({
                model: Ext.grid.property.Property,

                buildExtractors: Ext.emptyFn,

                read: function(dataObject) {
                    return this.readRecords(dataObject);
                },

                readRecords: function(dataObject) {
                    var val,
                        propName,
                        result = {
                            records: [],
                            success: true
                        };

                    for (propName in dataObject) {
                        if (dataObject.hasOwnProperty(propName)) {
                            val = dataObject[propName];
                            if (this.isEditableValue(val)) {
                                result.records.push(new Ext.grid.property.Property({
                                    name: propName,
                                    value: val
                                }, propName));
                            }
                        }
                    }
                    result.total = result.count = result.records.length;
                    return new Ext.data.ResultSet(result);
                },

                
                isEditableValue: function(val){
                    return Ext.isPrimitive(val) || Ext.isDate(val);
                }
            });
        }
        return this.reader;
    },

    
    setSource : function(dataObject) {
        var me = this;

        me.source = dataObject;
        me.suspendEvents();
        me.removeAll();
        me.proxy.data = dataObject;
        me.load();
        me.resumeEvents();
        me.fireEvent('datachanged', me);
        me.fireEvent('refresh', me);
    },

    
    getProperty : function(row) {
       return Ext.isNumber(row) ? this.getAt(row) : this.getById(row);
    },

    
    setValue : function(prop, value, create){
        var me = this,
            rec = me.getRec(prop);
            
        if (rec) {
            rec.set('value', value);
            me.source[prop] = value;
        } else if (create) {
            
            me.source[prop] = value;
            rec = new Ext.grid.property.Property({name: prop, value: value}, prop);
            me.add(rec);
        }
    },

    
    remove : function(prop) {
        var rec = this.getRec(prop);
        if (rec) {
            this.callParent([rec]);
            delete this.source[prop];
        }
    },

    
    getRec : function(prop) {
        return this.getById(prop);
    },

    
    getSource : function() {
        return this.source;
    }
});

Ext.define('Ext.layout.component.Body', {

    

    alias: ['layout.body'],

    extend: 'Ext.layout.component.Auto',

    

    type: 'body',

    beginLayout: function (ownerContext) {
        this.callParent(arguments);

        ownerContext.bodyContext = ownerContext.getEl('body');
    },

    
    
    
    
    
    

    calculateOwnerHeightFromContentHeight: function (ownerContext, contentHeight) {
        var height = this.callParent(arguments);

        if (ownerContext.targetContext != ownerContext) {
            height += ownerContext.getPaddingInfo().height;
        }

        return height;
    },

    calculateOwnerWidthFromContentWidth: function (ownerContext, contentWidth) {
        var width = this.callParent(arguments);

        if (ownerContext.targetContext != ownerContext) {
            width += ownerContext.getPaddingInfo().width;
        }

        return width;
    },

    measureContentWidth: function (ownerContext) {
        return ownerContext.bodyContext.setWidth(ownerContext.bodyContext.el.dom.offsetWidth, false);
    },

    measureContentHeight: function (ownerContext) {
        return ownerContext.bodyContext.setHeight(ownerContext.bodyContext.el.dom.offsetHeight, false);
    },

    publishInnerHeight: function (ownerContext, height) {
        var innerHeight = height - ownerContext.getFrameInfo().height,
            targetContext = ownerContext.targetContext;

        if (targetContext != ownerContext) {
            innerHeight -= ownerContext.getPaddingInfo().height;
        }

        
        return ownerContext.bodyContext.setHeight(innerHeight, !ownerContext.heightModel.natural);
    },

    publishInnerWidth: function (ownerContext, width) {
        var innerWidth = width - ownerContext.getFrameInfo().width,
            targetContext = ownerContext.targetContext;

        if (targetContext != ownerContext) {
            innerWidth -= ownerContext.getPaddingInfo().width;
        }

        ownerContext.bodyContext.setWidth(innerWidth, !ownerContext.widthModel.natural);
    }
});


Ext.define('Ext.layout.component.BoundList', {
    extend: 'Ext.layout.component.Auto',
    alias: 'layout.boundlist',

    type: 'component',
    
    beginLayout: function(ownerContext) {
        var me = this,
            owner = me.owner,
            toolbar = owner.pagingToolbar;

        me.callParent(arguments);
        
        if (owner.floating) {
            ownerContext.savedXY = owner.el.getXY();
            
            owner.el.setXY([-9999, -9999]);
        }
        
        if (toolbar) {
            ownerContext.toolbarContext = ownerContext.context.getCmp(toolbar);
        }
        ownerContext.listContext = ownerContext.getEl('listEl');
    },
    
    beginLayoutCycle: function(ownerContext){
        var owner = this.owner;
        
        this.callParent(arguments);
        if (ownerContext.heightModel.auto) {
            
            
            
            owner.el.setHeight('auto');
            owner.listEl.setHeight('auto');
        }
    },

    getLayoutItems: function() {
        var toolbar = this.owner.pagingToolbar;
        return toolbar ? [toolbar] : [];
    },
    
    isValidParent: function() {
        
        
        return true;
    },

    finishedLayout: function(ownerContext) {
        var xy = ownerContext.savedXY;
        
        this.callParent(arguments);
        if (xy) {
            this.owner.el.setXY(xy);
        }
    },
    
    measureContentWidth: function(ownerContext) {
        return this.owner.listEl.getWidth();
    },
    
    measureContentHeight: function(ownerContext) {
        return this.owner.listEl.getHeight();
    },
    
    publishInnerHeight: function(ownerContext, height) {
        var toolbar = ownerContext.toolbarContext,
            toolbarHeight = 0;
            
        if (toolbar) {
            toolbarHeight = toolbar.getProp('height');
        }
        
        if (toolbarHeight === undefined) {
            this.done = false;
        } else {
            ownerContext.listContext.setHeight(height - ownerContext.getFrameInfo().height - toolbarHeight);
        }
    },
    
    calculateOwnerHeightFromContentHeight: function(ownerContext){
        var height = this.callParent(arguments),
            toolbar = ownerContext.toolbarContext;
            
        if (toolbar) {
            height += toolbar.getProp('height');
        }
        return height;
    }
});

Ext.define('Ext.layout.component.Button', {

    

    alias: ['layout.button'],

    extend: 'Ext.layout.component.Auto',

    

    type: 'button',

    cellClsRE: /-btn-(tl|br)\b/,
    htmlRE: /<.*>/,

    constructor: function () {
        this.callParent(arguments);

        this.hackWidth = Ext.isIE && (!Ext.isStrict || Ext.isIE6 || Ext.isIE7 || Ext.isIE8);
        this.heightIncludesPadding = Ext.isIE6 && Ext.isStrict;
    },

    

    beginLayout: function (ownerContext) {
        this.callParent(arguments);

        this.cacheTargetInfo(ownerContext);
    },

    beginLayoutCycle: function(ownerContext) {
        var me = this,
            empty = '',
            owner = me.owner,
            btnEl = owner.btnEl,
            btnInnerEl = owner.btnInnerEl,
            text = owner.text,
            htmlAutoHeight;

        me.callParent(arguments);

        btnInnerEl.setStyle('overflow', empty);

        
        if (!ownerContext.widthModel.natural) {
            owner.el.setStyle('width', empty);
        }

        
        
        htmlAutoHeight = ownerContext.heightModel.shrinkWrap && text && me.htmlRE.test(text);

        btnEl.setStyle('width', empty);
        btnEl.setStyle('height', htmlAutoHeight ? 'auto' : empty);
        btnInnerEl.setStyle('width', empty);
        btnInnerEl.setStyle('height', htmlAutoHeight ? 'auto' : empty);
        btnInnerEl.setStyle('line-height', htmlAutoHeight ? 'normal' : empty);
        btnInnerEl.setStyle('padding-top', empty);
        owner.btnIconEl.setStyle('width', empty);
    },

    calculateOwnerHeightFromContentHeight: function (ownerContext, contentHeight) {
        return contentHeight;
    },

    calculateOwnerWidthFromContentWidth: function (ownerContext, contentWidth) {
        return contentWidth;
    },

    measureContentWidth: function (ownerContext) {
        var me = this,
            owner = me.owner,
            btnEl = owner.btnEl,
            btnInnerEl = owner.btnInnerEl,
            text = owner.text,
            btnFrameWidth, metrics, sizeIconEl, width, btnElContext, btnInnerElContext;

        
        
        
        
        if (owner.text && me.hackWidth && btnEl) {
            btnFrameWidth = me.btnFrameWidth;

            
            
            
            if (text.indexOf('>') === -1) {
                text = text.replace(/</g, '&lt;');
            }

            metrics = Ext.util.TextMetrics.measure(btnInnerEl, text);

            width = metrics.width + btnFrameWidth + me.adjWidth;

            btnElContext = ownerContext.getEl('btnEl');
            btnInnerElContext = ownerContext.getEl('btnInnerEl');
            sizeIconEl = (owner.icon || owner.iconCls) && 
                    (owner.iconAlign == "top" || owner.iconAlign == "bottom");

            
            
            
            ownerContext.setWidth(width); 

            btnElContext.setWidth(metrics.width + btnFrameWidth);
            btnInnerElContext.setWidth(metrics.width + btnFrameWidth);

            if (sizeIconEl) {
                owner.btnIconEl.setWidth(metrics.width + btnFrameWidth);
            }
        } else {
            width = ownerContext.el.getWidth();
        }

        return width;
    },

    measureContentHeight: function (ownerContext) {
        var me = this,
            owner = me.owner,
            btnInnerEl = owner.btnInnerEl,
            btnItem = ownerContext.getEl('btnEl'),
            btnInnerItem = ownerContext.getEl('btnInnerEl'),
            minTextHeight = me.minTextHeight,
            adjHeight = me.adjHeight,
            text = owner.getText(),
            height,
            textHeight,
            topPadding;

        if (owner.vertical) {
            height = Ext.util.TextMetrics.measure(btnInnerEl, owner.text).width;
            height += me.btnFrameHeight + adjHeight;

            
            ownerContext.setHeight(height, true, true);
        }
        else {
            
            if (text && me.htmlRE.test(text)) {
                textHeight = btnInnerEl.getHeight();

                
                if (textHeight < minTextHeight) {
                    topPadding = Math.floor((minTextHeight - textHeight) / 2);

                    
                    
                    btnInnerItem.setHeight(minTextHeight - (me.heightIncludesPadding ? topPadding : 0));
                    btnInnerItem.setProp('padding-top', topPadding);

                    textHeight = minTextHeight;
                }

                
                height = textHeight + adjHeight;
            }
            else {
                height = ownerContext.el.getHeight();
            }
        }

        
        btnItem.setHeight(height - adjHeight);

        return height;
    },

    publishInnerHeight: function(ownerContext, height) {
        var me = this,
            owner = me.owner,
            isNum = Ext.isNumber,
            btnItem = ownerContext.getEl('btnEl'),
            btnInnerEl = owner.btnInnerEl,
            btnInnerItem = ownerContext.getEl('btnInnerEl'),
            btnHeight = isNum(height) ? height - me.adjHeight : height,
            btnFrameHeight = me.btnFrameHeight,
            text = owner.getText(),
            textHeight,
            paddingTop;

        btnItem.setHeight(btnHeight);
        btnInnerItem.setHeight(btnHeight);

        
        if (!owner.vertical && btnHeight >= 0) {
            btnInnerItem.setProp('line-height', btnHeight - btnFrameHeight + 'px');
        }

        
        
        
        
        
        if (text && me.htmlRE.test(text)) {
            btnInnerItem.setProp('line-height', 'normal');
            btnInnerEl.setStyle('line-height', 'normal');
            textHeight = Ext.util.TextMetrics.measure(btnInnerEl, text).height;
            paddingTop = Math.floor(Math.max(btnHeight - btnFrameHeight - textHeight, 0) / 2);
            btnInnerItem.setProp('padding-top', me.btnFrameTop + paddingTop);
            btnInnerItem.setHeight(btnHeight - (me.heightIncludesPadding ? paddingTop : 0));
        }
    },

    publishInnerWidth: function(ownerContext, width) {
        var me = this,
            isNum = Ext.isNumber,
            btnItem = ownerContext.getEl('btnEl'),
            btnInnerItem = ownerContext.getEl('btnInnerEl'),
            btnWidth = isNum(width) ? width - me.adjWidth : width;

        btnItem.setWidth(btnWidth);
        btnInnerItem.setWidth(btnWidth);
    },
    
    clearTargetCache: function(){
        delete this.adjWidth;    
    },

    cacheTargetInfo: function(ownerContext) {
        var me = this,
            owner = me.owner,
            scale = owner.scale,
            padding, frameSize, btnWrapPadding, btnInnerEl, innerFrameSize;

        
        if (!('adjWidth' in me) || me.lastScale !== scale) {
            
            if (me.lastScale) {
                owner.btnInnerEl.setStyle('line-height', '');
            }

            me.lastScale = scale;

            padding = ownerContext.getPaddingInfo();
            frameSize = ownerContext.getFrameInfo();
            btnWrapPadding = ownerContext.getEl('btnWrap').getPaddingInfo();
            btnInnerEl = ownerContext.getEl('btnInnerEl');
            innerFrameSize = btnInnerEl.getPaddingInfo();

            Ext.apply(me, {
                
                adjWidth       : btnWrapPadding.width + frameSize.width + padding.width,
                adjHeight      : btnWrapPadding.height + frameSize.height + padding.height,
                btnFrameWidth  : innerFrameSize.width,
                btnFrameHeight : innerFrameSize.height,
                btnFrameTop    : innerFrameSize.top,

                
                minTextHeight  : parseInt(btnInnerEl.getStyle('line-height'), 10)
            });
        }

        me.callParent(arguments);
    },
    
    finishedLayout: function(){
        var owner = this.owner;
        this.callParent(arguments);
        
        
        if (Ext.isWebKit) {
            owner.el.dom.offsetWidth;
        }
    }
});


Ext.define('Ext.layout.component.Dock', {

    

    extend: 'Ext.layout.component.Component',

    alias: 'layout.dock',

    alternateClassName: 'Ext.layout.component.AbstractDock',

    

    type: 'dock',

    initializedBorders: -1,

    horizontalCollapsePolicy: { width: true, x: true },

    verticalCollapsePolicy: { height: true, y: true },

    finishRender: function () {
        var me = this,
            target, items;

        me.callParent();

        target = me.getRenderTarget();
        items = me.getDockedItems();

        me.finishRenderItems(target, items);
    },

    isItemBoxParent: function (itemContext) {
        return true;
    },

    isItemShrinkWrap: function (item) {
        return true;
    },

    dockOpposites: {
        top: 'bottom',
        right: 'left',
        bottom: 'top',
        left: 'right'
    },

    handleItemBorders: function() {
        var me = this,
            owner = me.owner,
            borders, docked,
            oldBorders = me.borders,
            opposites = me.dockOpposites,
            currentGeneration = owner.dockedItems.generation,
            i, ln, item, dock, side, borderItem,
            collapsed = me.collapsed;

        if (me.initializedBorders == currentGeneration || (owner.border && !owner.manageBodyBorders)) {
            return;
        }

        me.initializedBorders = currentGeneration;

        
        me.collapsed = false;
        docked = me.getLayoutItems();
        me.collapsed = collapsed;

        borders = { top: [], right: [], bottom: [], left: [] };

        for (i = 0, ln = docked.length; i < ln; i++) {
            item = docked[i];
            dock = item.dock;

            if (item.ignoreBorderManagement) {
                continue;
            }

            if (!borders[dock].satisfied) {
                borders[dock].push(item);
                borders[dock].satisfied = true;
            }

            if (!borders.top.satisfied && opposites[dock] !== 'top') {
                borders.top.push(item);
            }
            if (!borders.right.satisfied && opposites[dock] !== 'right') {
                borders.right.push(item);
            }
            if (!borders.bottom.satisfied && opposites[dock] !== 'bottom') {
                borders.bottom.push(item);
            }
            if (!borders.left.satisfied && opposites[dock] !== 'left') {
                borders.left.push(item);
            }
        }

        if (oldBorders) {
            for (side in oldBorders) {
                if (oldBorders.hasOwnProperty(side)) {
                    ln = oldBorders[side].length;
                    if (!owner.manageBodyBorders) {
                        for (i = 0; i < ln; i++) {
                            borderItem = oldBorders[side][i];
                            if (!borderItem.isDestroyed) {
                                borderItem.removeCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);
                            }
                        }
                        if (!oldBorders[side].satisfied && !owner.bodyBorder) {
                            owner.removeBodyCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);
                        }
                    }
                    else if (oldBorders[side].satisfied) {
                        owner.setBodyStyle('border-' + side + '-width', '');
                    }
                }
            }
        }

        for (side in borders) {
            if (borders.hasOwnProperty(side)) {
                ln = borders[side].length;
                if (!owner.manageBodyBorders) {
                    for (i = 0; i < ln; i++) {
                        borders[side][i].addCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);
                    }
                    if ((!borders[side].satisfied && !owner.bodyBorder) || owner.bodyBorder === false) {
                        owner.addBodyCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);
                    }
                }
                else if (borders[side].satisfied) {
                    owner.setBodyStyle('border-' + side + '-width', '1px');
                }
            }
        }

        me.borders = borders;
    },

    beforeLayoutCycle: function (ownerContext) {
        var me = this,
            owner = me.owner,
            shrinkWrap = me.sizeModels.shrinkWrap,
            collapsedHorz, collapsedVert;

        if (owner.collapsed) {
            if (owner.collapsedVertical()) {
                collapsedVert = true;
                ownerContext.measureDimensions = 1;
            } else {
                collapsedHorz = true;
                ownerContext.measureDimensions = 2;
            }
        }

        ownerContext.collapsedVert = collapsedVert;
        ownerContext.collapsedHorz = collapsedHorz;

        
        
        
        
        if (collapsedVert) {
            ownerContext.heightModel = shrinkWrap;
        } else if (collapsedHorz) {
            ownerContext.widthModel = shrinkWrap;
        }
    },

    beginLayout: function(ownerContext) {
        var me = this,
            owner = me.owner,
            docked = me.getLayoutItems(),
            layoutContext = ownerContext.context,
            dockedItemCount = docked.length,
            dockedItems, i, item, itemContext, offsets,
            collapsed;

        me.callParent(arguments);

        me.handleItemBorders();

        
        
        collapsed = owner.getCollapsed();
        if (collapsed !== me.lastCollapsedState && Ext.isDefined(me.lastCollapsedState)) {
            
            if (me.owner.collapsed) {
                ownerContext.isCollapsingOrExpanding = 1;
                
                owner.addClsWithUI(owner.collapsedCls);
            } else {
                ownerContext.isCollapsingOrExpanding = 2;
                
                owner.removeClsWithUI(owner.collapsedCls);
                ownerContext.lastCollapsedState = me.lastCollapsedState;
            }
        }
        me.lastCollapsedState = collapsed;

        ownerContext.dockedItems = dockedItems = [];

        for (i = 0; i < dockedItemCount; i++) {
            item = docked[i];
            if (item.rendered) {
                itemContext = layoutContext.getCmp(item);
                itemContext.dockedAt = { x: 0, y: 0 };
                itemContext.offsets = offsets = Ext.Element.parseBox(item.offsets || {});
                offsets.width = offsets.left + offsets.right;
                offsets.height = offsets.top + offsets.bottom;
                dockedItems.push(itemContext);
            }
        }

        ownerContext.bodyContext = ownerContext.getEl('body');
    },

    beginLayoutCycle: function(ownerContext) {
        var me = this,
            docked = ownerContext.dockedItems,
            len = docked.length,
            owner = me.owner,
            frameBody = owner.frameBody,
            lastHeightModel = me.lastHeightModel,
            i, item, dock;

        me.callParent(arguments);

        if (lastHeightModel && lastHeightModel.shrinkWrap &&
                    !ownerContext.heightModel.shrinkWrap && !me.owner.manageHeight) {
            owner.body.dom.style.marginBottom = '';
        }

        if (ownerContext.widthModel.auto) {
            if (ownerContext.widthModel.shrinkWrap) {
                owner.el.setWidth(null);
            }
            owner.body.setWidth(null);
            if (frameBody) {
                frameBody.setWidth(null);
            }
        }
        if (ownerContext.heightModel.auto) {
            owner.body.setHeight(null);
            
            if (frameBody) {
                frameBody.setHeight(null);
            }
        }

        
        
        if (ownerContext.collapsedVert) {
            ownerContext.setContentHeight(0);
        } else if (ownerContext.collapsedHorz) {
            ownerContext.setContentWidth(0);
        }

        
        
        for (i = 0; i < len; i++) {
            item = docked[i].target;
            dock = item.dock;

            if (dock == 'right') {
                item.el.setLeft(0);
            } else if (dock != 'left') {
                continue;
            }

            
        }
    },

    calculate: function (ownerContext) {
        var me = this,
            measure = me.measureAutoDimensions(ownerContext, ownerContext.measureDimensions),
            state = ownerContext.state,
            horzDone = state.horzDone,
            vertDone = state.vertDone,
            bodyContext = ownerContext.bodyContext,
            horz, vert, forward, backward;

        
        ownerContext.borderInfo  || ownerContext.getBorderInfo();
        ownerContext.paddingInfo || ownerContext.getPaddingInfo();
        ownerContext.framingInfo || ownerContext.getFraming();
        bodyContext.borderInfo   || bodyContext.getBorderInfo();
        bodyContext.paddingInfo  || bodyContext.getPaddingInfo();

        
        
        horz = !horzDone &&
               me.createAxis(ownerContext, measure.contentWidth, ownerContext.widthModel,
                             'left', 'right', 'x', 'width', 'Width', ownerContext.collapsedHorz);
        vert = !vertDone &&
               me.createAxis(ownerContext, measure.contentHeight, ownerContext.heightModel,
                             'top', 'bottom', 'y', 'height', 'Height', ownerContext.collapsedVert);

        
        
        
        
        
        
        
        
        for (forward = 0, backward = ownerContext.dockedItems.length; backward--; ++forward) {
            if (horz) {
                me.dockChild(ownerContext, horz, backward, forward);
            }
            if (vert) {
                me.dockChild(ownerContext, vert, backward, forward);
            }
        }

        if (horz && me.finishAxis(ownerContext, horz)) {
            state.horzDone = horzDone = horz;
        }

        if (vert && me.finishAxis(ownerContext, vert)) {
            state.vertDone = vertDone = vert;
        }

        
        
        if (horzDone && vertDone && me.finishConstraints(ownerContext, horzDone, vertDone)) {
            
            
            
            me.finishPositions(ownerContext, horzDone, vertDone);
        } else {
            me.done = false;
        }
    },

    
    createAxis: function (ownerContext, contentSize, sizeModel, dockBegin, dockEnd, posProp,
                          sizeProp, sizePropCap, collapsedAxis) {
        var begin = 0,
            owner = this.owner,
            maxSize = owner['max' + sizePropCap],
            minSize = owner['min' + sizePropCap] || 0,
            hasMaxSize = maxSize != null, 
            setSize = 'set' + sizePropCap,
            border, bodyContext, frameSize, padding, end;

        if (sizeModel.shrinkWrap) {
            
            
            if (collapsedAxis) {
                end = 0;
            } else {
                bodyContext = ownerContext.bodyContext;
                end = contentSize + bodyContext.borderInfo[sizeProp];
            }
        } else {
            border    = ownerContext.borderInfo;
            frameSize = ownerContext.framingInfo;
            padding   = ownerContext.paddingInfo;

            end = ownerContext.getProp(sizeProp);
            end -= border[dockEnd] + padding[dockEnd] + frameSize[dockEnd];

            begin = border[dockBegin] + padding[dockBegin] + frameSize[dockBegin];
        }

        return {
            shrinkWrap: sizeModel.shrinkWrap,
            sizeModel: sizeModel,
            
            begin: begin,
            end: end,
            collapsed: collapsedAxis,
            horizontal: posProp == 'x',
            ignoreFrameBegin: false,
            ignoreFrameEnd: false,
            initialSize: end - begin,
            hasMinMaxConstraints: (minSize || hasMaxSize) && sizeModel.shrinkWrap,
            minSize: minSize,
            maxSize: hasMaxSize ? maxSize : 1e9,
            bodyPosProp: this.owner.manageHeight ? posProp : ('margin-' + dockBegin), 
            dockBegin: dockBegin,    
            dockEnd: dockEnd,        
            posProp: posProp,        
            sizeProp: sizeProp,      
            sizePropCap: sizePropCap, 
            setSize: setSize,
            dockedPixelsEnd: 0
        };
    },

    
    dockChild: function (ownerContext, axis, backward, forward) {
        var me = this,
            itemContext = ownerContext.dockedItems[axis.shrinkWrap ? backward : forward],
            item = itemContext.target,
            dock = item.dock, 
            pos;

        if(item.ignoreParentFrame && ownerContext.isCollapsingOrExpanding) {
            
            
            itemContext.clearMarginCache();
        }

        if (dock == axis.dockBegin) {
            if (axis.shrinkWrap) {
                pos = me.dockOutwardBegin(ownerContext, itemContext, item, axis);
            } else {
                pos = me.dockInwardBegin(ownerContext, itemContext, item, axis);
            }
        } else if (dock == axis.dockEnd) {
            if (axis.shrinkWrap) {
                pos = me.dockOutwardEnd(ownerContext, itemContext, item, axis);
            } else {
                pos = me.dockInwardEnd(ownerContext, itemContext, item, axis);
            }
        } else {
            pos = me.dockStretch(ownerContext, itemContext, item, axis);
        }

        itemContext.dockedAt[axis.posProp] = pos;
    },

    
    dockInwardBegin: function (ownerContext, itemContext, item, axis) {
        var pos = axis.begin,
            sizeProp = axis.sizeProp,
            size, 
            dock;

        if (item.ignoreParentFrame) {
            dock = item.dock;
            pos -= ownerContext.borderInfo[dock] + ownerContext.paddingInfo[dock] +
                   ownerContext.framingInfo[dock];
        }

        if (!item.overlay) {
            size = itemContext.getProp(sizeProp) + itemContext.getMarginInfo()[sizeProp];
            axis.begin += size;
        }

        return pos;
    },

    
    dockInwardEnd: function (ownerContext, itemContext, item, axis) {
        var sizeProp = axis.sizeProp,
            size = itemContext.getProp(sizeProp) + itemContext.getMarginInfo()[sizeProp],
            pos = axis.end - size;

        if (!item.overlay) {
            axis.end = pos;
        }

        if (item.ignoreParentFrame) {
            pos += ownerContext.borderInfo[item.dock] + ownerContext.paddingInfo[item.dock] +
                   ownerContext.framingInfo[item.dock];
        }

        return pos;
    },

    
    dockOutwardBegin: function (ownerContext, itemContext, item, axis) {
        var pos = axis.begin,
            sizeProp = axis.sizeProp,
            dock, size;

        if (axis.collapsed) {
            axis.ignoreFrameBegin = axis.ignoreFrameEnd = true;
        } else if (item.ignoreParentFrame) {
            dock = item.dock;
            pos -= ownerContext.borderInfo[dock] + ownerContext.paddingInfo[dock] +
                   ownerContext.framingInfo[dock];

            axis.ignoreFrameBegin = true;
        }

        if (!item.overlay) {
            size = itemContext.getProp(sizeProp) + itemContext.getMarginInfo()[sizeProp];
            pos -= size;
            axis.begin = pos;
        }

        return pos;
    },

    
    dockOutwardEnd: function (ownerContext, itemContext, item, axis) {
        var pos = axis.end,
            sizeProp = axis.sizeProp,
            dock, size;

        size = itemContext.getProp(sizeProp) + itemContext.getMarginInfo()[sizeProp];

        if (axis.collapsed) {
            axis.ignoreFrameBegin = axis.ignoreFrameEnd = true;
        } else if (item.ignoreParentFrame) {
            dock = item.dock;
            pos += ownerContext.borderInfo[dock] + ownerContext.paddingInfo[dock] +
                   ownerContext.framingInfo[dock];

            axis.ignoreFrameEnd = true;
        }

        if (!item.overlay) {
            axis.end = pos + size;
            axis.dockedPixelsEnd += size;
        }

        return pos;
    },

    
    dockStretch: function (ownerContext, itemContext, item, axis) {
        var dock = item.dock, 
            sizeProp = axis.sizeProp, 
            horizontal = dock == 'top' || dock == 'bottom',
            offsets = itemContext.offsets,
            border = ownerContext.borderInfo,
            padding = ownerContext.paddingInfo,
            endProp = horizontal ? 'right' : 'bottom',
            startProp = horizontal ? 'left' : 'top',
            pos = axis.begin + offsets[startProp],
            margin, size, framing;

        if (item.stretch !== false) {
            size = axis.end - pos - offsets[endProp];

            if (item.ignoreParentFrame) {
                framing = ownerContext.framingInfo;
                pos -= border[startProp] + padding[startProp] + framing[startProp];
                size += border[sizeProp] + padding[sizeProp] + framing[sizeProp];
            }

            margin = itemContext.getMarginInfo();
            size -= margin[sizeProp];

            itemContext[axis.setSize](size);
        }

        return pos;
    },

    
    finishAxis: function (ownerContext, axis) {
        var size = axis.end - axis.begin,
            setSizeMethod = axis.setSize,
            beginName = axis.dockBegin, 
            endName = axis.dockEnd, 
            border = ownerContext.borderInfo,
            padding = ownerContext.paddingInfo,
            framing = ownerContext.framingInfo,
            frameSize = padding[beginName] + border[beginName] + framing[beginName],
            bodyContext = ownerContext.bodyContext,
            bodyPos, bodySize, dirty;

        if (axis.shrinkWrap) {
            
            
            
            axis.delta = -axis.begin;  

            bodySize = axis.initialSize;

            if (axis.ignoreFrameBegin) {
                axis.delta -= border[beginName];
                bodyPos = -axis.begin - frameSize;
            } else {
                size += frameSize;
                axis.delta += padding[beginName] + framing[beginName];
                bodyPos = -axis.begin;
            }

            if (!axis.ignoreFrameEnd) {
                size += padding[endName] + border[endName] + framing[endName];
            }

            axis.size = size; 

            if (!axis.horizontal && !this.owner.manageHeight) {
                
                
                dirty = false;
            }
        } else {
            
            
            axis.delta = -border[axis.dockBegin]; 

            
            bodySize = size;
            bodyPos = axis.begin - frameSize;
        }

        bodyContext[setSizeMethod](bodySize, dirty);
        bodyContext.setProp(axis.bodyPosProp, bodyPos);

        return !isNaN(size);
    },

    
    finishConstraints: function (ownerContext, horz, vert) {
        var sizeModels = this.sizeModels,
            publishWidth = horz.shrinkWrap,
            publishHeight = vert.shrinkWrap,
            dirty, height, width, heightModel, widthModel, size;

        if (publishWidth) {
            size = horz.size;

            if (size < horz.minSize) {
                widthModel = sizeModels.constrainedMin;
                width = horz.minSize;
            } else if (size > horz.maxSize) {
                widthModel = sizeModels.constrainedMax;
                width = horz.maxSize;
            } else {
                width = size;
            }
        }

        if (publishHeight) {
            size = vert.size;

            if (size < vert.minSize) {
                heightModel = sizeModels.constrainedMin;
                height = vert.minSize;
            } else if (size > vert.maxSize) {
                heightModel = sizeModels.constrainedMax;
                height = vert.maxSize;
            } else {
                if (!ownerContext.collapsedVert && !this.owner.manageHeight) {
                    
                    
                    dirty = false;

                    
                    ownerContext.bodyContext.setProp('margin-bottom', vert.dockedPixelsEnd);
                }

                height = size;
            }
        }

        

        if (widthModel || heightModel) {
            
            
            if (widthModel && heightModel &&
                        widthModel.constrainedMax &&  heightModel.constrainedMin) {
                ownerContext.invalidate({ widthModel: widthModel });
                return false;
            }

            
            
            
            if (!ownerContext.widthModel.calculatedFromShrinkWrap &&
                        !ownerContext.heightModel.calculatedFromShrinkWrap) {
                
                ownerContext.invalidate({ widthModel: widthModel, heightModel: heightModel });
                return false;
            }

            
            
            
        }

        

        if (publishWidth) {
            ownerContext.setWidth(width);
            if (widthModel) {
                ownerContext.widthModel = widthModel; 
            }
        }
        if (publishHeight) {
            ownerContext.setHeight(height, dirty);
            if (heightModel) {
                ownerContext.heightModel = heightModel; 
            }
        }

        return true;
    },

    
    finishPositions: function (ownerContext, horz, vert) {
        var dockedItems = ownerContext.dockedItems,
            length = dockedItems.length,
            deltaX = horz.delta,
            deltaY = vert.delta,
            index, itemContext;

        for (index = 0; index < length; ++index) {
            itemContext = dockedItems[index];

            itemContext.setProp('x', deltaX + itemContext.dockedAt.x);
            itemContext.setProp('y', deltaY + itemContext.dockedAt.y);
        }
    },

    finishedLayout: function(ownerContext) {
        var me = this,
            target = ownerContext.target;

        me.callParent(arguments);

        if (!ownerContext.animatePolicy) {
            if (ownerContext.isCollapsingOrExpanding === 1) {
                target.afterCollapse(false);
            } else if (ownerContext.isCollapsingOrExpanding === 2) {
                target.afterExpand(false);
            }
        }
    },

    getAnimatePolicy: function(ownerContext) {
        var me = this,
            lastCollapsedState, policy;

        if (ownerContext.isCollapsingOrExpanding == 1) {
            lastCollapsedState = me.lastCollapsedState;
        } else if (ownerContext.isCollapsingOrExpanding == 2) {
            lastCollapsedState = ownerContext.lastCollapsedState;
        }

        if (lastCollapsedState == 'left' || lastCollapsedState == 'right') {
            policy = me.horizontalCollapsePolicy;
        } else if (lastCollapsedState == 'top' || lastCollapsedState == 'bottom') {
            policy = me.verticalCollapsePolicy;
        }

        return policy;
    },

    
    getDockedItems: function(order, beforeBody) {
        var me = this,
            renderedOnly = (order === 'visual'),
            all = renderedOnly ? Ext.ComponentQuery.query('[rendered]', me.owner.dockedItems.items) : me.owner.dockedItems.items,
            sort = all && all.length && order !== false,
            renderOrder,
            dock, dockedItems, i, isBefore, length;

        if (beforeBody == null) {
            dockedItems = sort && !renderedOnly ? all.slice() : all;
        } else {
            dockedItems = [];

            for (i = 0, length = all.length; i < length; ++i) {
                dock = all[i].dock;
                isBefore = (dock == 'top' || dock == 'left');
                if (beforeBody ? isBefore : !isBefore) {
                    dockedItems.push(all[i]);
                }
            }

            sort = sort && dockedItems.length;
        }

        if (sort) {
            renderOrder = (order = order || 'render') == 'render';
            Ext.Array.sort(dockedItems, function(a, b) {
                var aw,
                    bw;

                
                
                if (renderOrder && ((aw = me.owner.dockOrder[a.dock]) !== (bw = me.owner.dockOrder[b.dock]))) {

                    
                    if (!(aw + bw)) {
                        return aw - bw;
                    }
                }

                aw = me.getItemWeight(a, order);
                bw = me.getItemWeight(b, order);
                if ((aw !== undefined) && (bw !== undefined)) {
                    return aw - bw;
                }
                return 0;
            });
        }

        return dockedItems || [];
    },

    getItemWeight: function (item, order) {
        var weight = item.weight || this.owner.defaultDockWeights[item.dock];
        return weight[order] || weight;
    },

    
    getLayoutItems : function() {
        var me = this,
            items,
            itemCount,
            item,
            i,
            result;

        if (me.owner.collapsed) {
            result = me.owner.getCollapsedDockedItems();
        } else {
            items = me.getDockedItems('visual');
            itemCount = items.length;
            result = [];
            for (i = 0; i < itemCount; i++) {
                item = items[i];
                if (!item.hidden) {
                    result.push(item);
                }
            }
        }
        return result;
    },

    
    measureContentWidth: function (ownerContext) {
        var bodyContext = ownerContext.bodyContext;
        return bodyContext.el.getWidth() - bodyContext.getBorderInfo().width;
    },

    measureContentHeight: function (ownerContext) {
        var bodyContext = ownerContext.bodyContext;
        return bodyContext.el.getHeight() - bodyContext.getBorderInfo().height;
    },
    
    redoLayout: function(ownerContext) {
        var me = this,
            owner = me.owner;
        
        
        if (ownerContext.isCollapsingOrExpanding == 1) {
            if (owner.reExpander) {
                owner.reExpander.el.show();
            }
            
            owner.addClsWithUI(owner.collapsedCls);
            ownerContext.redo(true);
        } else if (ownerContext.isCollapsingOrExpanding == 2) {
            
            owner.removeClsWithUI(owner.collapsedCls);
            ownerContext.bodyContext.redo();
        } 
    },

    
    
    renderChildren: function() {
        var me = this,
            items = me.getDockedItems(),
            target = me.getRenderTarget();

        me.renderItems(items, target);
    },

    
    renderItems: function(items, target) {
        var me = this,
            dockedItemCount = items.length,
            itemIndex = 0,
            correctPosition = 0,
            staticNodeCount = 0,
            targetNodes = me.getRenderTarget().dom.childNodes,
            targetChildCount = targetNodes.length,
            i, j, targetChildNode, item;

        
        for (i = 0, j = 0; i < targetChildCount; i++) {
            targetChildNode = targetNodes[i];
            if (Ext.fly(targetChildNode).hasCls('x-resizable-handle')) {
                break;
            }
            for (j = 0; j < dockedItemCount; j++) {
                item = items[j];
                if (item.rendered && item.el.dom === targetChildNode) {
                    break;
                }
            }
            
            
            if (j === dockedItemCount) {
                staticNodeCount++;
            }
        }

        
        for (; itemIndex < dockedItemCount; itemIndex++, correctPosition++) {
            item = items[itemIndex];

            
            
            
            
            
            
            
            if (itemIndex === correctPosition && (item.dock === 'right' || item.dock === 'bottom')) {
                correctPosition += staticNodeCount;
            }

            
            if (item && !item.rendered) {
                me.renderItem(item, target, correctPosition);
            }
            else if (!me.isValidParent(item, target, correctPosition)) {
                me.moveItem(item, target, correctPosition);
            }
        }
    },

    undoLayout: function(ownerContext) {
        var me = this,
            owner = me.owner;
        
        
        if (ownerContext.isCollapsingOrExpanding == 1) {

            
            if (owner.reExpander) {
                owner.reExpander.el.hide();
            }
            
            owner.removeClsWithUI(owner.collapsedCls);
            ownerContext.undo(true);
        } else if (ownerContext.isCollapsingOrExpanding == 2) {
            
            owner.addClsWithUI(owner.collapsedCls);
            ownerContext.bodyContext.undo();
        } 
    },

    sizePolicy: {
        nostretch: {
            setsWidth: 0,
            setsHeight: 0
        },
        stretchH: {
            setsWidth: 1,
            setsHeight: 0
        },
        stretchV: {
            setsWidth: 0,
            setsHeight: 1
        },

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        

        autoStretchH: {
            readsWidth: 1,
            setsWidth: 1,
            setsHeight: 0
        },
        autoStretchV: {
            readsHeight: 1,
            setsWidth: 0,
            setsHeight: 1
        }
    },

    getItemSizePolicy: function (item) {
        var policy = this.sizePolicy,
            dock, vertical;

        if (item.stretch === false) {
            return policy.nostretch;
        }

        dock = item.dock;
        vertical = (dock == 'left' || dock == 'right');

        

        if (vertical) {
            return policy.stretchV;
        }

        return policy.stretchH;
    },

    
    configureItem : function(item, pos) {
        this.callParent(arguments);

        item.addCls(Ext.baseCSSPrefix + 'docked');
        item.addClsWithUI('docked-' + item.dock);
    },

    afterRemove : function(item) {
        this.callParent(arguments);
        if (this.itemCls) {
            item.el.removeCls(this.itemCls + '-' + item.dock);
        }
        var dom = item.el.dom;

        if (!item.destroying && dom) {
            dom.parentNode.removeChild(dom);
        }
        this.childrenChanged = true;
    }
});


Ext.define('Ext.layout.component.FieldSet', {
    extend: 'Ext.layout.component.Body',
    alias: ['layout.fieldset'],

    type: 'fieldset',

    beforeLayoutCycle: function (ownerContext) {
        if (ownerContext.target.collapsed) {
            ownerContext.heightModel = this.sizeModels.shrinkWrap;
        }
    },

    beginLayoutCycle: function (ownerContext) {
        var target = ownerContext.target,
            lastSize;

        this.callParent(arguments);

        
        
        
        if (target.collapsed) {
            ownerContext.setContentHeight(0);

            
            
            
            if (ownerContext.widthModel.shrinkWrap) {
                lastSize = target.lastComponentSize;
                ownerContext.setContentWidth((lastSize && lastSize.contentWidth) || 100);
            }
        }
    },

    calculateOwnerHeightFromContentHeight: function (ownerContext, contentHeight) {
        var border = ownerContext.getBorderInfo(),
            legend = ownerContext.target.legend;
            
        
        return ownerContext.getProp('contentHeight') + ownerContext.getPaddingInfo().height + (legend ? legend.getHeight() : border.top) + border.bottom;
    },

    publishInnerHeight: function (ownerContext, height) {
        
        
        
        var legend = ownerContext.target.legend;
        if (legend) {
            height -= legend.getHeight();
        }
        this.callParent([ownerContext, height]);
    },

    getLayoutItems : function() {
        var legend = this.owner.legend;
        if (legend) {
            return [legend];
        }
        return [];
    }
});

Ext.define('Ext.layout.component.ProgressBar', {

    

    alias: ['layout.progressbar'],

    extend: 'Ext.layout.component.Auto',

    

    type: 'progressbar',

    beginLayout: function (ownerContext) {
        var me = this,
            i, textEls;

        me.callParent(arguments);

        if (!ownerContext.textEls) {
            textEls = me.owner.textEl; 

            if (textEls.isComposite) {
                ownerContext.textEls = [];
                textEls = textEls.elements;
                for (i = textEls.length; i--; ) {
                    ownerContext.textEls[i] = ownerContext.getEl(Ext.get(textEls[i]));
                }
            } else {
                ownerContext.textEls = [ ownerContext.getEl('textEl') ];
            }
        }
    },

    calculate: function(ownerContext) {
        var me = this,
            i, textEls, width;

        me.callParent(arguments);

        if (Ext.isNumber(width = ownerContext.getProp('width'))) {
            width -= ownerContext.getBorderInfo().width;
            textEls = ownerContext.textEls;

            for (i = textEls.length; i--; ) {
                textEls[i].setWidth(width);
            }
        } else {
            me.done = false;
        }
    }
});


Ext.define('Ext.ProgressBar', {
    extend: 'Ext.Component',
    alias: 'widget.progressbar',

    requires: [
        'Ext.Template',
        'Ext.CompositeElement',
        'Ext.TaskManager',
        'Ext.layout.component.ProgressBar'
    ],

    uses: ['Ext.fx.Anim'],

   

   

   

   
    baseCls: Ext.baseCSSPrefix + 'progress',

    
    animate: false,

    
    text: '',

    
    waitTimer: null,

    childEls: [
        'bar'
    ],

    renderTpl: [
        '<tpl if="internalText">',
            '<div class="{baseCls}-text {baseCls}-text-back">{text}</div>',
        '</tpl>',
        '<div id="{id}-bar" class="{baseCls}-bar" style="width:{percentage}%">',
            '<tpl if="internalText">',
                '<div class="{baseCls}-text">',
                    '<div>{text}</div>',
                '</div>',
            '</tpl>',
        '</div>'
    ],

    componentLayout: 'progressbar',

    
    initComponent: function() {
        this.callParent();

        this.addEvents(
            
            "update"
        );
    },

    initRenderData: function() {
        var me = this;
        return Ext.apply(me.callParent(), {
            internalText : !me.hasOwnProperty('textEl'),
            text         : me.text || '&#160;',
            percentage   : me.value ? me.value * 100 : 0
        });
    },

    onRender : function() {
        var me = this;

        me.callParent(arguments);

        
        if (me.textEl) {
            me.textEl = Ext.get(me.textEl);
            me.updateText(me.text);
        }
        
        else {
            
            
            me.textEl = me.el.select('.' + me.baseCls + '-text');
        }
    },

    
    updateProgress: function(value, text, animate) {
        var me = this,
            oldValue = me.value;

        me.value = value || 0;
        if (text) {
            me.updateText(text);
        }
        if (me.rendered && !me.isDestroyed) {
            if (animate === true || (animate !== false && me.animate)) {
                me.bar.stopAnimation();
                me.bar.animate(Ext.apply({
                    from: {
                        width: (oldValue * 100) + '%'
                    },
                    to: {
                        width: (me.value * 100) + '%'
                    }
                }, me.animate));
            } else {
                me.bar.setStyle('width', (me.value * 100) + '%');
            }
        }
        me.fireEvent('update', me, me.value, text);
        return me;
    },

    
    updateText: function(text) {
        var me = this;
        
        me.text = text;
        if (me.rendered) {
            me.textEl.update(me.text);
        }
        return me;
    },

    applyText : function(text) {
        this.updateText(text);
    },
    
    getText: function(){
        return this.text;    
    },

    
    wait: function(o) {
        var me = this, scope;
            
        if (!me.waitTimer) {
            scope = me;
            o = o || {};
            me.updateText(o.text);
            me.waitTimer = Ext.TaskManager.start({
                run: function(i){
                    var inc = o.increment || 10;
                    i -= 1;
                    me.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
                },
                interval: o.interval || 1000,
                duration: o.duration,
                onStop: function(){
                    if (o.fn) {
                        o.fn.apply(o.scope || me);
                    }
                    me.reset();
                },
                scope: scope
            });
        }
        return me;
    },

    
    isWaiting: function(){
        return this.waitTimer !== null;
    },

    
    reset: function(hide){
        var me = this;
        
        me.updateProgress(0);
        me.clearTimer();
        if (hide === true) {
            me.hide();
        }
        return me;
    },

    
    clearTimer: function(){
        var me = this;
        
        if (me.waitTimer) {
            me.waitTimer.onStop = null; 
            Ext.TaskManager.stop(me.waitTimer);
            me.waitTimer = null;
        }
    },

    onDestroy: function(){
        var me = this;
        
        me.clearTimer();
        if (me.rendered) {
            if (me.textEl.isComposite) {
                me.textEl.clear();
            }
            Ext.destroyMembers(me, 'textEl', 'progressBar');
        }
        me.callParent();
    }
});


Ext.define('Ext.layout.component.Tab', {

    extend: 'Ext.layout.component.Button',
    alias: 'layout.tab',

    beginLayout: function(ownerContext) {
        var me = this,
            closable = me.owner.closable;

        
        
        if (me.lastClosable !== closable) {
            me.lastClosable = closable;
            me.clearTargetCache();
        }

        me.callParent(arguments);
    }
});


Ext.define('Ext.layout.component.field.Field', {

    

    extend: 'Ext.layout.component.Auto',

    alias: 'layout.field',

    uses: ['Ext.tip.QuickTip', 'Ext.util.TextMetrics', 'Ext.util.CSS'],

    

    type: 'field',
    
    naturalSizingProp: 'size',

    beginLayout: function(ownerContext) {
        var me = this,
            owner = me.owner,
            widthModel = ownerContext.widthModel,
            ownerNaturalSize = owner[me.naturalSizingProp],
            width;

        me.callParent(arguments);

        ownerContext.labelStrategy = me.getLabelStrategy();
        ownerContext.errorStrategy = me.getErrorStrategy();

        ownerContext.labelContext = ownerContext.getEl('labelEl');
        ownerContext.bodyCellContext = ownerContext.getEl('bodyEl');
        ownerContext.inputContext = ownerContext.getEl('inputEl');
        ownerContext.errorContext = ownerContext.getEl('errorEl');

        
        
        if ((Ext.isIE6 || Ext.isIE7) && Ext.isStrict && ownerContext.inputContext) {
            me.ieInputWidthAdjustment = ownerContext.inputContext.getPaddingInfo().width + ownerContext.inputContext.getBorderInfo().width;
        }

        
        ownerContext.labelStrategy.prepare(ownerContext, owner);
        ownerContext.errorStrategy.prepare(ownerContext, owner);

        
        if (widthModel.shrinkWrap) {
            
            me.beginLayoutShrinkWrap(ownerContext);
        } else if (widthModel.natural) {

            
            if (typeof ownerNaturalSize == 'number' && !owner.inputWidth) {
                me.beginLayoutFixed(ownerContext, (width = ownerNaturalSize * 6.5 + 20), 'px');
            }

            
            else {
                me.beginLayoutShrinkWrap(ownerContext);
            }
            ownerContext.setWidth(width, false);
        } else {
            me.beginLayoutFixed(ownerContext, '100', '%');
        }
    },

    beginLayoutFixed: function (ownerContext, width, suffix) {
        var owner = ownerContext.target,
            inputEl = owner.inputEl,
            inputWidth = owner.inputWidth;

        owner.el.setStyle('table-layout', 'fixed');
        owner.bodyEl.setStyle('width', width + suffix);
        if (inputEl && inputWidth) {
            inputEl.setStyle('width', inputWidth + 'px');
        }
        ownerContext.isFixed = true;
    },

    beginLayoutShrinkWrap: function (ownerContext) {
        var owner = ownerContext.target,
            inputEl = owner.inputEl,
            inputWidth = owner.inputWidth;

        if (inputEl && inputEl.dom) {
            inputEl.dom.removeAttribute('size');
            if (inputWidth) {
                inputEl.setStyle('width', inputWidth + 'px');
            }
        }
        owner.el.setStyle('table-layout', 'auto');
        owner.bodyEl.setStyle('width', '');
    },

    finishedLayout: function(ownerContext){
        var owner = this.owner;

        this.callParent(arguments);        
        ownerContext.labelStrategy.finishedLayout(ownerContext, owner);
        ownerContext.errorStrategy.finishedLayout(ownerContext, owner);
    },

    calculateOwnerHeightFromContentHeight: function(ownerContext, contentHeight) {
        return contentHeight;
    },

    measureContentHeight: function (ownerContext) {
        return ownerContext.el.getHeight();
    },
    
    measureContentWidth: function (ownerContext) {
        return ownerContext.el.getWidth();
    },

    measureLabelErrorHeight: function (ownerContext) {
        return ownerContext.labelStrategy.getHeight(ownerContext) +
               ownerContext.errorStrategy.getHeight(ownerContext);
    },

    onFocus: function() {
        this.getErrorStrategy().onFocus(this.owner);    
    },

    
    getLabelStrategy: function() {
        var me = this,
            strategies = me.labelStrategies,
            labelAlign = me.owner.labelAlign;
        return strategies[labelAlign] || strategies.base;
    },

    
    getErrorStrategy: function() {
        var me = this,
            owner = me.owner,
            strategies = me.errorStrategies,
            msgTarget = owner.msgTarget;
        return !owner.preventMark && Ext.isString(msgTarget) ?
                (strategies[msgTarget] || strategies.elementId) :
                strategies.none;
    },

    
    labelStrategies: (function() {
        var base = {
                prepare: function(ownerContext, owner) {
                    var cls = owner.labelCls + '-' + owner.labelAlign,
                        labelEl = owner.labelEl;

                    if (labelEl) {
                        labelEl.addCls(cls);
                    }
                },

                getHeight: function () {
                    return 0;
                },
                
                finishedLayout: Ext.emptyFn
            };

        return {
            base: base,

            
            top: Ext.applyIf({        
                        
                getHeight: function (ownerContext) {
                    var labelContext = ownerContext.labelContext,
                        props = labelContext.props,
                        height = props.height;
                        
                    if (height === undefined) {
                        props.height = height = labelContext.el.getHeight();
                    }

                    return height;
                }
            }, base),

            
            left: base,

            
            right: base
        };
    }()),

    
    errorStrategies: (function() {
        function showTip(owner) {
            var tip = Ext.layout.component.field.Field.tip,
                target;
                
            if (tip && tip.isVisible()) {
                target = tip.activeTarget;
                if (target && target.el === owner.getActionEl().dom) {
                    tip.toFront(true);
                }
            }
        }

        var applyIf = Ext.applyIf,
            emptyFn = Ext.emptyFn,
            iconCls = Ext.baseCSSPrefix + 'form-invalid-icon',
            iconWidth,
            base = {
                prepare: function(ownerContext, owner) {
                    var el = owner.errorEl;
                    if (el) {
                        el.setDisplayed(false);
                    }
                },
                getHeight: function () {
                    return 0;
                },
                onFocus: emptyFn,
                finishedLayout: emptyFn
            };

        return {
            none: base,

            
            side: applyIf({
                prepare: function(ownerContext, owner) {
                    var errorEl = owner.errorEl,
                        sideErrorCell = owner.sideErrorCell,
                        displayError = owner.hasActiveError(),
                        tempEl;

                    
                    if (!iconWidth) {
                        iconWidth = (tempEl = Ext.getBody().createChild({style: 'position:absolute', cls: iconCls})).getWidth();
                        tempEl.remove();
                    }

                    errorEl.addCls(iconCls);
                    errorEl.set({'data-errorqtip': owner.getActiveError() || ''});
                    if (owner.autoFitErrors) {
                        errorEl.setDisplayed(displayError);
                    }
                    
                    else {
                        errorEl.setVisible(displayError);
                    }

                    
                    if (sideErrorCell && owner.autoFitErrors) {
                        sideErrorCell.setDisplayed(displayError);
                    }
                    owner.bodyEl.dom.colSpan = owner.getBodyColspan();

                    
                    Ext.layout.component.field.Field.initTip();
                },
                onFocus: showTip
            }, base),

            
            under: applyIf({
                prepare: function(ownerContext, owner) {
                    var errorEl = owner.errorEl,
                        cls = Ext.baseCSSPrefix + 'form-invalid-under';

                    errorEl.addCls(cls);
                    errorEl.setDisplayed(owner.hasActiveError());
                },
                getHeight: function (ownerContext) {
                    var height = 0,
                        errorContext, props;

                    if (ownerContext.target.hasActiveError()) {
                        errorContext = ownerContext.errorContext;
                        props = errorContext.props;
                        height = props.height;

                        if (height === undefined) {
                            props.height = height = errorContext.el.getHeight();
                        }
                    }

                    return height;
                }
            }, base),

            
            qtip: applyIf({
                prepare: function(ownerContext, owner) {
                    Ext.layout.component.field.Field.initTip();
                    owner.getActionEl().set({'data-errorqtip': owner.getActiveError() || ''});
                },
                onFocus: showTip
            }, base),

            
            title: applyIf({
                prepare: function(ownerContext, owner) {
                    owner.el.set({'title': owner.getActiveError() || ''});
                }
            }, base),

            
            elementId: applyIf({
                prepare: function(ownerContext, owner) {
                    var targetEl = Ext.fly(owner.msgTarget);
                    if (targetEl) {
                        targetEl.dom.innerHTML = owner.getActiveError() || '';
                        targetEl.setDisplayed(owner.hasActiveError());
                    }
                }
            }, base)
        };
    }()),

    statics: {
        
        initTip: function() {
            var tip = this.tip;
            if (!tip) {
                tip = this.tip = Ext.create('Ext.tip.QuickTip', {
                    baseCls: Ext.baseCSSPrefix + 'form-invalid-tip'
                });
                tip.tagConfig = Ext.apply({}, {attribute: 'errorqtip'}, tip.tagConfig);
            }
        },

        
        destroyTip: function() {
            var tip = this.tip;
            if (tip) {
                tip.destroy();
                delete this.tip;
            }
        }
    }
});

Ext.define('Ext.form.field.Base', {
    extend: 'Ext.Component',
    mixins: {
        labelable: 'Ext.form.Labelable',
        field: 'Ext.form.field.Field'
    },
    alias: 'widget.field',
    alternateClassName: ['Ext.form.Field', 'Ext.form.BaseField'],
    requires: ['Ext.util.DelayedTask', 'Ext.XTemplate', 'Ext.layout.component.field.Field'],

    
    fieldSubTpl: [ 
        '<input id="{id}" type="{type}" {inputAttrTpl}',
            ' size="1"', 
            '<tpl if="name"> name="{name}"</tpl>',
            '<tpl if="value"> value="{[Ext.util.Format.htmlEncode(values.value)]}"</tpl>',
            '<tpl if="placeholder"> placeholder="{placeholder}"</tpl>',
            '{%if (values.maxLength !== undefined){%} maxlength="{maxLength}"{%}%}',
            '<tpl if="readOnly"> readonly="readonly"</tpl>',
            '<tpl if="disabled"> disabled="disabled"</tpl>',
            '<tpl if="tabIdx"> tabIndex="{tabIdx}"</tpl>',
            '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
        ' class="{fieldCls} {typeCls} {editableCls}" autocomplete="off"/>',
        {
            disableFormats: true
        }
    ],

    subTplInsertions: [
        
        'inputAttrTpl'
    ],

    

    
    inputType: 'text',

    

    
    
    invalidText : 'The value in this field is invalid',
    

    
    fieldCls : Ext.baseCSSPrefix + 'form-field',

    

    
    focusCls : 'form-focus',

    
    dirtyCls : Ext.baseCSSPrefix + 'form-dirty',

    
    checkChangeEvents: Ext.isIE && (!document.documentMode || document.documentMode < 9) ?
                        ['change', 'propertychange'] :
                        ['change', 'input', 'textInput', 'keyup', 'dragdrop'],

    
    checkChangeBuffer: 50,

    componentLayout: 'field',

    
    readOnly : false,

    
    readOnlyCls: Ext.baseCSSPrefix + 'form-readonly',

    

    
    validateOnBlur: true,

    
    hasFocus : false,

    baseCls: Ext.baseCSSPrefix + 'field',

    maskOnDisable: false,

    
    initComponent : function() {
        var me = this;

        me.callParent();

        me.subTplData = me.subTplData || {};

        me.addEvents(
            
            'specialkey',

            
            'writeablechange'
        );

        
        me.initLabelable();
        me.initField();

        
        if (!me.name) {
            me.name = me.getInputId();
        }
    },
    
    beforeRender: function(){
        var me = this;
            
        me.callParent(arguments);
        me.beforeLabelableRender(arguments);
        if (me.readOnly) {
            me.addCls(me.readOnlyCls);
        }
    },

    
    getInputId: function() {
        return this.inputId || (this.inputId = this.id + '-inputEl');
    },

    
    getSubTplData: function() {
        var me = this,
            type = me.inputType,
            inputId = me.getInputId(),
            data;
        
        data = Ext.apply({
            id         : inputId,
            cmpId      : me.id,
            name       : me.name || inputId,
            disabled   : me.disabled,
            readOnly   : me.readOnly,
            value      : me.getRawValue(),
            type       : type,
            fieldCls   : me.fieldCls,
            fieldStyle : me.getFieldStyle(),
            tabIdx     : me.tabIndex,
            typeCls    : Ext.baseCSSPrefix + 'form-' + (type === 'password' ? 'text' : type)
        }, me.subTplData);

        me.getInsertionRenderData(data, me.subTplInsertions);

        return data;
    },

    afterFirstLayout: function() {
        this.callParent();
        var el = this.inputEl;
        if (el) {
            el.selectable();
        }
    },

    applyRenderSelectors: function() {
        var me = this;

        me.callParent();

        
        me.inputEl = me.el.getById(me.getInputId());
    },

    
    getSubTplMarkup: function() {
        return this.getTpl('fieldSubTpl').apply(this.getSubTplData());
    },

    initRenderTpl: function() {
        var me = this;
        if (!me.hasOwnProperty('renderTpl')) {
            me.renderTpl = me.getTpl('labelableRenderTpl');
        }
        return me.callParent();
    },

    initRenderData: function() {
        return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
    },

    
    setFieldStyle: function(style) {
        var me = this,
            inputEl = me.inputEl;
        if (inputEl) {
            inputEl.applyStyles(style);
        }
        me.fieldStyle = style;
    },

    getFieldStyle: function() {
        return 'width:100%;' + (Ext.isObject(this.fieldStyle) ? Ext.DomHelper.generateStyles(this.fieldStyle) : this.fieldStyle ||'');
    },

    
    onRender : function() {
        var me = this;
        me.callParent(arguments);
        me.onLabelableRender();
        me.renderActiveError();
    },

    getFocusEl: function() {
        return this.inputEl;
    },

    isFileUpload: function() {
        return this.inputType === 'file';
    },

    extractFileInput: function() {
        var me = this,
            fileInput = me.isFileUpload() ? me.inputEl.dom : null,
            clone;
        if (fileInput) {
            clone = fileInput.cloneNode(true);
            fileInput.parentNode.replaceChild(clone, fileInput);
            me.inputEl = Ext.get(clone);
        }
        return fileInput;
    },

    
    getSubmitData: function() {
        var me = this,
            data = null,
            val;
        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
            val = me.getSubmitValue();
            if (val !== null) {
                data = {};
                data[me.getName()] = val;
            }
        }
        return data;
    },

    
    getSubmitValue: function() {
        return this.processRawValue(this.getRawValue());
    },

    
    getRawValue: function() {
        var me = this,
            v = (me.inputEl ? me.inputEl.getValue() : Ext.value(me.rawValue, ''));
        me.rawValue = v;
        return v;
    },

    
    setRawValue: function(value) {
        var me = this;
        value = Ext.value(me.transformRawValue(value), '');
        me.rawValue = value;

        
        if (me.inputEl) {
            me.inputEl.dom.value = value;
        }
        return value;
    },
    
    
    transformRawValue: function(value) {
        return value;
    },

    
    valueToRaw: function(value) {
        return '' + Ext.value(value, '');
    },

    
    rawToValue: function(rawValue) {
        return rawValue;
    },

    
    processRawValue: function(value) {
        return value;
    },

    
    getValue: function() {
        var me = this,
            val = me.rawToValue(me.processRawValue(me.getRawValue()));
        me.value = val;
        return val;
    },

    
    setValue: function(value) {
        var me = this;
        me.setRawValue(me.valueToRaw(value));
        return me.mixins.field.setValue.call(me, value);
    },

    onBoxReady: function() {
        var me = this;
        me.callParent();
        
        if (me.setReadOnlyOnBoxReady) {
            me.setReadOnly(me.readOnly);
        }
            
    },

    
    onDisable: function() {
        var me = this,
            inputEl = me.inputEl;
            
        me.callParent();
        if (inputEl) {
            inputEl.dom.disabled = true;
            if (me.hasActiveError()) {
                
                me.clearInvalid();
                me.needsValidateOnEnable = true;
            }
        }
    },

    
    onEnable: function() {
        var me = this,
            inputEl = me.inputEl;
            
        me.callParent();
        if (inputEl) {
            inputEl.dom.disabled = false;
            if (me.needsValidateOnEnable) {
                delete me.needsValidateOnEnable;
                
                me.forceValidation = true;
                me.isValid();
                delete me.forceValidation;
            }
        }
    },

    
    setReadOnly: function(readOnly) {
        var me = this,
            inputEl = me.inputEl;
        readOnly = !!readOnly;
        me[readOnly ? 'addCls' : 'removeCls'](me.readOnlyCls);
        me.readOnly = readOnly;
        if (inputEl) {
            inputEl.dom.readOnly = readOnly;
        } else if (me.rendering) {
            me.setReadOnlyOnBoxReady = true;
        }
        me.fireEvent('writeablechange', me, readOnly);
    },

    
    fireKey: function(e){
        if(e.isSpecialKey()){
            this.fireEvent('specialkey', this, new Ext.EventObjectImpl(e));
        }
    },

    
    initEvents : function(){
        var me = this,
            inputEl = me.inputEl,
            onChangeTask,
            onChangeEvent,
            events = me.checkChangeEvents,
            e,
            eLen   = events.length,
            event;

        
        
        if (me.inEditor) {
            me.onBlur = Ext.Function.createBuffered(me.onBlur, 10);
        }
        if (inputEl) {
            me.mon(inputEl, Ext.EventManager.getKeyEvent(), me.fireKey,  me);

            
            onChangeTask = new Ext.util.DelayedTask(me.checkChange, me);
            me.onChangeEvent = onChangeEvent = function() {
                onChangeTask.delay(me.checkChangeBuffer);
            };

            for (e = 0; e < eLen; e++) {
                event = events[e];

                if (event === 'propertychange') {
                    me.usesPropertychange = true;
                }

                me.mon(inputEl, event, onChangeEvent);
            }
        }
        me.callParent();
    },

    doComponentLayout: function() {
        var me = this,
            inputEl = me.inputEl,
            usesPropertychange = me.usesPropertychange,
            ename = 'propertychange',
            onChangeEvent = me.onChangeEvent;

        
        
        
        if (usesPropertychange) {
            me.mun(inputEl, ename, onChangeEvent);
        }
        me.callParent(arguments);
        if (usesPropertychange) {
            me.mon(inputEl, ename, onChangeEvent);
        }
    },

    
    onDirtyChange: function(isDirty) {
        this[isDirty ? 'addCls' : 'removeCls'](this.dirtyCls);
    },


    
    isValid : function() {
        var me = this,
            disabled = me.disabled,
            validate = me.forceValidation || !disabled;
            
        
        return validate ? me.validateValue(me.processRawValue(me.getRawValue())) : disabled;
    },


    
    validateValue: function(value) {
        var me = this,
            errors = me.getErrors(value),
            isValid = Ext.isEmpty(errors);
        if (!me.preventMark) {
            if (isValid) {
                me.clearInvalid();
            } else {
                me.markInvalid(errors);
            }
        }

        return isValid;
    },

    
    markInvalid : function(errors) {
        
        var me = this,
            oldMsg = me.getActiveError();
        me.setActiveErrors(Ext.Array.from(errors));
        if (oldMsg !== me.getActiveError()) {
            me.updateLayout();
        }
    },

    
    clearInvalid : function() {
        
        var me = this,
            hadError = me.hasActiveError();
        me.unsetActiveError();
        if (hadError) {
            me.updateLayout();
        }
    },

    
    renderActiveError: function() {
        var me = this,
            hasError = me.hasActiveError();
        if (me.inputEl) {
            
            me.inputEl[hasError ? 'addCls' : 'removeCls'](me.invalidCls + '-field');
        }
        me.mixins.labelable.renderActiveError.call(me);
    },


    getActionEl: function() {
        return this.inputEl || this.el;
    }

});


Ext.define('Ext.form.field.Checkbox', {
    extend: 'Ext.form.field.Base',
    alias: ['widget.checkboxfield', 'widget.checkbox'],
    alternateClassName: 'Ext.form.Checkbox',
    requires: ['Ext.XTemplate', 'Ext.form.CheckboxManager' ],

    componentLayout: 'field',

    childEls: [
        
        'boxLabelEl'
    ],

    
    fieldSubTpl: [
        '<tpl if="boxLabel && boxLabelAlign == \'before\'">',
            '{beforeBoxLabelTpl}',
            '<label id="{cmpId}-boxLabelEl" {boxLabelAttrTpl} class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">',
                '{beforeBoxLabelTextTpl}',
                '{boxLabel}',
                '{afterBoxLabelTextTpl}',
            '</label>',
            '{afterBoxLabelTpl}',
        '</tpl>',
        
        
        
        '<input type="button" id="{id}" {inputAttrTpl}',
            '<tpl if="tabIdx"> tabIndex="{tabIdx}"</tpl>',
            '<tpl if="disabled"> disabled="disabled"</tpl>',
            '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
            ' class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />',
        '<tpl if="boxLabel && boxLabelAlign == \'after\'">',
            '{beforeBoxLabelTpl}',
            '<label id="{cmpId}-boxLabelEl" {boxLabelAttrTpl} class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">',
                '{beforeBoxLabelTextTpl}',
                '{boxLabel}',
                '{afterBoxLabelTextTpl}',
            '</label>',
            '{afterBoxLabelTpl}',
        '</tpl>',
        {
            disableFormats: true,
            compiled: true
        }
    ],

    subTplInsertions: [
        
        'beforeBoxLabelTpl',

        
        'afterBoxLabelTpl',

        
        'beforeBoxLabelTextTpl',

        
        'afterBoxLabelTextTpl',

        
        'boxLabelAttrTpl',

        
        'inputAttrTpl'
    ],

    
    isCheckbox: true,

    
    focusCls: 'form-cb-focus',

    

    
    fieldBodyCls: Ext.baseCSSPrefix + 'form-cb-wrap',

    
    checked: false,

    
    checkedCls: Ext.baseCSSPrefix + 'form-cb-checked',

    

    
    boxLabelCls: Ext.baseCSSPrefix + 'form-cb-label',

    
    boxLabelAlign: 'after',

    
    inputValue: 'on',

    

    

    

    
    checkChangeEvents: [],
    inputType: 'checkbox',

    
    onRe: /^on$/i,

    initComponent: function() {
        this.callParent(arguments);
        this.getManager().add(this);
    },

    initValue: function() {
        var me = this,
            checked = !!me.checked;

        
        me.originalValue = me.lastValue = checked;

        
        me.setValue(checked);
    },

    getElConfig: function() {
        var me = this;

        
        if (me.isChecked(me.rawValue, me.inputValue)) {
            me.addCls(me.checkedCls);
        }
        return me.callParent();
    },

    getFieldStyle: function() {
        return Ext.isObject(this.fieldStyle) ? Ext.DomHelper.generateStyles(this.fieldStyle) : this.fieldStyle ||'';
    },

    getSubTplData: function() {
        var me = this;
        return Ext.apply(me.callParent(), {
            disabled      : me.readOnly || me.disabled,
            boxLabel      : me.boxLabel,
            boxLabelCls   : me.boxLabelCls,
            boxLabelAlign : me.boxLabelAlign
        });
    },

    initEvents: function() {
        var me = this;
        me.callParent();
        me.mon(me.inputEl, 'click', me.onBoxClick, me);
    },

    
    onBoxClick: function(e) {
        var me = this;
        if (!me.disabled && !me.readOnly) {
            this.setValue(!this.checked);
        }
    },

    
    getRawValue: function() {
        return this.checked;
    },

    
    getValue: function() {
        return this.checked;
    },

    
    getSubmitValue: function() {
        var unchecked = this.uncheckedValue,
            uncheckedVal = Ext.isDefined(unchecked) ? unchecked : null;
        return this.checked ? this.inputValue : uncheckedVal;
    },

    isChecked: function(rawValue, inputValue) {
        return (rawValue === true || rawValue === 'true' || rawValue === '1' || rawValue === 1 ||
                      (((Ext.isString(rawValue) || Ext.isNumber(rawValue)) && inputValue) ? rawValue == inputValue : this.onRe.test(rawValue)));
    },

    
    setRawValue: function(value) {
        var me = this,
            inputEl = me.inputEl,
            checked = me.isChecked(value, me.inputValue);

        if (inputEl) {
            me[checked ? 'addCls' : 'removeCls'](me.checkedCls);
        }

        me.checked = me.rawValue = checked;
        return checked;
    },

    
    setValue: function(checked) {
        var me = this,
            boxes, i, len, box;

        
        
        
        
        if (Ext.isArray(checked)) {
            boxes = me.getManager().getByName(me.name, me.getFormId()).items;
            len = boxes.length;

            for (i = 0; i < len; ++i) {
                box = boxes[i];
                box.setValue(Ext.Array.contains(checked, box.inputValue));
            }
        } else {
            me.callParent(arguments);
        }

        return me;
    },

    
    valueToRaw: function(value) {
        
        return value;
    },

    
    onChange: function(newVal, oldVal) {
        var me = this,
            handler = me.handler;
        if (handler) {
            handler.call(me.scope || me, me, newVal);
        }
        me.callParent(arguments);
    },
    
    resetOriginalValue: function( fromBoxInGroup){
        var me = this,
            boxes,
            box,
            len,
            i;
            
        
        if (!fromBoxInGroup) {
            boxes = me.getManager().getByName(me.name, me.getFormId()).items;
            len  = boxes.length;
            
            for (i = 0; i < len; ++i) {
                box = boxes[i];
                if (box !== me) {
                    boxes[i].resetOriginalValue(true);
                }
            }
        }
        me.callParent();
    },

    
    beforeDestroy: function(){
        this.callParent();
        this.getManager().removeAtKey(this.id);
    },

    
    getManager: function() {
        return Ext.form.CheckboxManager;
    },

    onEnable: function() {
        var me = this,
            inputEl = me.inputEl;
        me.callParent();
        if (inputEl) {
            
            inputEl.dom.disabled = me.readOnly;
        }
    },

    setReadOnly: function(readOnly) {
        var me = this,
            inputEl = me.inputEl;
        if (inputEl) {
            
            inputEl.dom.disabled = !!readOnly || me.disabled;
        }
        me.callParent(arguments);
    },

    getFormId: function(){
        var me = this,
            form;

        if (!me.formId) {
            form = me.up('form');
            if (form) {
                me.formId = form.id;
            }
        }
        return me.formId;
    }
});


Ext.define('Ext.form.field.Display', {
    extend:'Ext.form.field.Base',
    alias: 'widget.displayfield',
    requires: ['Ext.util.Format', 'Ext.XTemplate'],
    alternateClassName: ['Ext.form.DisplayField', 'Ext.form.Display'],
    fieldSubTpl: [
        '<div id="{id}"',
        '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>', 
        ' class="{fieldCls}">{value}</div>',
        {
            compiled: true,
            disableFormats: true
        }
    ],

    
    fieldCls: Ext.baseCSSPrefix + 'form-display-field',

    
    htmlEncode: false,
    
    
    
    

    validateOnChange: false,

    initEvents: Ext.emptyFn,

    submitValue: false,
    
    isDirty: function(){
        return false;
    },

    isValid: function() {
        return true;
    },

    validate: function() {
        return true;
    },

    getRawValue: function() {
        return this.rawValue;
    },

    setRawValue: function(value) {
        var me = this,
            display;
            
        value = Ext.value(value, '');
        me.rawValue = value;
        if (me.rendered) {
            me.inputEl.dom.innerHTML = me.getDisplayValue();
            me.updateLayout();
        }
        return value;
    },

    
    getDisplayValue: function() {
        var me = this,
            value = this.getRawValue(),
            display;
        if (me.renderer) {
             display = me.renderer.call(me.scope || me, value, me);
        } else {
             display = me.htmlEncode ? Ext.util.Format.htmlEncode(value) : value;
        }
        return display;
    },
        
    getSubTplData: function() {
        var ret = this.callParent(arguments);

        ret.value = this.getDisplayValue();

        return ret;
    }

    
    
    
    
    
    
});


Ext.define('Ext.form.field.Hidden', {
    extend:'Ext.form.field.Base',
    alias: ['widget.hiddenfield', 'widget.hidden'],
    alternateClassName: 'Ext.form.Hidden',

    
    inputType : 'hidden',
    hideLabel: true,
    
    initComponent: function(){
        this.formItemCls += '-hidden';
        this.callParent();    
    },
    
    
    isEqual: function(value1, value2) {
        return this.isEqualAsString(value1, value2);
    },

    
    initEvents: Ext.emptyFn,
    setSize : Ext.emptyFn,
    setWidth : Ext.emptyFn,
    setHeight : Ext.emptyFn,
    setPosition : Ext.emptyFn,
    setPagePosition : Ext.emptyFn,
    markInvalid : Ext.emptyFn,
    clearInvalid : Ext.emptyFn
});


Ext.define('Ext.form.field.Radio', {
    extend:'Ext.form.field.Checkbox',
    alias: ['widget.radiofield', 'widget.radio'],
    alternateClassName: 'Ext.form.Radio',
    requires: ['Ext.form.RadioManager'],

    
    isRadio: true,

    

    
    inputType: 'radio',
    ariaRole: 'radio',
    
    formId: null,

    
    getGroupValue: function() {
        var selected = this.getManager().getChecked(this.name, this.getFormId());
        return selected ? selected.inputValue : null;
    },

    
    onBoxClick: function(e) {
        var me = this;
        if (!me.disabled && !me.readOnly) {
            this.setValue(true);
        }
    },
    
    onRemoved: function(){
        this.callParent(arguments);
        this.formId = null;
    },

    
    setValue: function(v) {
        var me = this,
            active;

        if (Ext.isBoolean(v)) {
            me.callParent(arguments);
        } else {
            active = me.getManager().getWithValue(me.name, v, me.getFormId()).getAt(0);
            if (active) {
                active.setValue(true);
            }
        }
        return me;
    },

    
    getSubmitValue: function() {
        return this.checked ? this.inputValue : null;
    },

    getModelData: function() {
        return this.getSubmitData();
    },

    
    onChange: function(newVal, oldVal) {
        var me = this,
            r, rLen, radio, radios;

        me.callParent(arguments);

        if (newVal) {
            radios = me.getManager().getByName(me.name, me.getFormId()).items;
            rLen   = radios.length;

            for (r = 0; r < rLen; r++) {
                radio = radios[r];

                if (radio !== me) {
                    radio.setValue(false);
                }
            }
        }
    },

    
    getManager: function() {
        return Ext.form.RadioManager;
    }
});


Ext.define('Ext.layout.component.field.FieldContainer', {

    

    extend: 'Ext.layout.component.field.Field',

    alias: 'layout.fieldcontainer',

    

    type: 'fieldcontainer',

    waitForOuterHeightInDom: true,
    waitForOuterWidthInDom: true,

    beginLayout: function(ownerContext) {
        this.callParent(arguments);

        
        ownerContext.hasRawContent = true;
        ownerContext.target.bodyEl.setStyle('height', '');
    },

    measureContentHeight: function (ownerContext) {
        
        
        
        return ownerContext.hasDomProp('containerLayoutDone') ? this.callParent(arguments) : NaN;
    },

    measureContentWidth: function (ownerContext) {
        
        return ownerContext.hasDomProp('containerLayoutDone') ? this.callParent(arguments) : NaN;
    },

    publishInnerWidth: function (ownerContext, width) {
        var bodyContext = ownerContext.bodyCellContext;
        bodyContext.setWidth(bodyContext.el.getWidth(), false);
    },
    
    publishInnerHeight: function (ownerContext, height) {
        var bodyContext = ownerContext.bodyCellContext;
        bodyContext.setHeight(height - this.measureLabelErrorHeight(ownerContext));
    }
});


Ext.define('Ext.layout.component.field.HtmlEditor', {
    extend: 'Ext.layout.component.field.Field',
    alias: ['layout.htmleditor'],

    type: 'htmleditor',

    
    toolbarSizePolicy: {
        setsWidth: 0,
        setsHeight: 0
    },

    beginLayout: function(ownerContext) {
        this.callParent(arguments);

        ownerContext.textAreaContext = ownerContext.getEl('textareaEl');
        ownerContext.iframeContext   = ownerContext.getEl('iframeEl');
        ownerContext.toolbarContext  = ownerContext.context.getCmp(this.owner.getToolbar());
    },
    
    
    renderItems: Ext.emptyFn,

    getItemSizePolicy: function (item) {
        
        return this.toolbarSizePolicy;
    },

    getLayoutItems: function () {
        var toolbar = this.owner.getToolbar();
        
        return toolbar ? [toolbar] : [];
    },

    getRenderTarget: function() {
        return this.owner.bodyEl;
    },

    publishInnerHeight: function (ownerContext, height) {
        var me = this,
            innerHeight = height - me.measureLabelErrorHeight(ownerContext) -
                          ownerContext.toolbarContext.getProp('height') -
                          ownerContext.bodyCellContext.getPaddingInfo().height;

        
        if (Ext.isNumber(innerHeight)) {
            ownerContext.textAreaContext.setHeight(innerHeight);
            ownerContext.iframeContext.setHeight(innerHeight);
        } else {
            me.done = false;
        }
    }
});

Ext.define('Ext.layout.component.field.Slider', {

    

    alias: ['layout.sliderfield'],

    extend: 'Ext.layout.component.field.Field',

    

    type: 'sliderfield',

    beginLayout: function(ownerContext) {
        this.callParent(arguments);

        ownerContext.endElContext   = ownerContext.getEl('endEl');
        ownerContext.innerElContext = ownerContext.getEl('innerEl');
        ownerContext.bodyElContext  = ownerContext.getEl('bodyEl');
    },

    publishInnerHeight: function (ownerContext, height) {
        var innerHeight = height - this.measureLabelErrorHeight(ownerContext),
            endElPad,
            inputPad;
        if (this.owner.vertical) {
            endElPad = ownerContext.endElContext.getPaddingInfo();
            inputPad = ownerContext.inputContext.getPaddingInfo();
            ownerContext.innerElContext.setHeight(innerHeight - inputPad.height - endElPad.height);
        } else {
            ownerContext.bodyElContext.setHeight(innerHeight);
        }
    },

    publishInnerWidth: function (ownerContext, width) {
        if (!this.owner.vertical) {
            var endElPad = ownerContext.endElContext.getPaddingInfo(),
                inputPad = ownerContext.inputContext.getPaddingInfo();

            ownerContext.innerElContext.setWidth(width - inputPad.left - endElPad.right - ownerContext.labelContext.getProp('width'));
        }
    },

    beginLayoutFixed: function(ownerContext, width, suffix) {
        var me = this,
            ieInputWidthAdjustment = me.ieInputWidthAdjustment;

        if (ieInputWidthAdjustment) {
            
            
            me.owner.bodyEl.setStyle('padding-right', ieInputWidthAdjustment + 'px');
        }

        me.callParent(arguments);
    }
});


Ext.define('Ext.layout.component.field.Text', {
    extend: 'Ext.layout.component.field.Field',
    alias: 'layout.textfield',
    requires: ['Ext.util.TextMetrics'],

    type: 'textfield',
    
    canGrowWidth: true,

    beginLayoutCycle: function(ownerContext) {
        var me = this;
        
        me.callParent(arguments);
        
        
        if (ownerContext.shrinkWrap) {
            ownerContext.inputContext.el.setStyle('height', '');
        }
    },

    measureContentWidth: function (ownerContext) {
        var me = this,
            owner = me.owner,
            width = me.callParent(arguments),
            inputContext = ownerContext.inputContext,
            inputEl, value, calcWidth, max, min;

        if (owner.grow && me.canGrowWidth && !ownerContext.state.growHandled) {
            inputEl = owner.inputEl;

            
            value = Ext.util.Format.htmlEncode(inputEl.dom.value || (owner.hasFocus ? '' : owner.emptyText) || '');
            value += owner.growAppend;
            calcWidth = inputEl.getTextWidth(value) + inputContext.getFrameInfo().width;

            max = owner.growMax;
            min = Math.min(max, width);
            max = Math.max(owner.growMin, max, min);

            
            calcWidth = Ext.Number.constrain(calcWidth, owner.growMin, max);
            inputContext.setWidth(calcWidth);
            ownerContext.state.growHandled = true;
            
            
            inputContext.domBlock(me, 'width');
            width = NaN;
        }
        return width;
    },
    
    publishInnerHeight: function(ownerContext, height) {
        ownerContext.inputContext.setHeight(height - this.measureLabelErrorHeight(ownerContext));
    },

    beginLayoutFixed: function(ownerContext, width, suffix) {
        var me = this,
            ieInputWidthAdjustment = me.ieInputWidthAdjustment;

        if (ieInputWidthAdjustment) {
            
            
            me.owner.bodyEl.setStyle('padding-right', ieInputWidthAdjustment + 'px');
            if(suffix === 'px') {
                width -= ieInputWidthAdjustment;
            }
        }

        me.callParent(arguments);
    }
});


Ext.define('Ext.form.field.Text', {
    extend:'Ext.form.field.Base',
    alias: 'widget.textfield',
    requires: ['Ext.form.field.VTypes', 'Ext.layout.component.field.Text'],
    alternateClassName: ['Ext.form.TextField', 'Ext.form.Text'],

    

    

    
    size: 20,

    

    
    growMin : 30,

    
    growMax : 800,

    
    
    growAppend: 'W',
    

    

    

    

    
    allowBlank : true,

    
    minLength : 0,

    
    maxLength : Number.MAX_VALUE,

    

    
    
    minLengthText : 'The minimum length for this field is {0}',
    

    
    
    maxLengthText : 'The maximum length for this field is {0}',
    

    

    
    
    blankText : 'This field is required',
    

    

    

    
    regexText : '',

    

    
    emptyCls : Ext.baseCSSPrefix + 'form-empty-field',

    
    requiredCls : Ext.baseCSSPrefix + 'form-required-field',

    

    componentLayout: 'textfield',

    
    valueContainsPlaceholder : false,


    initComponent: function () {
        var me = this;

        me.callParent();

        me.addEvents(
            
            'autosize',

            
            'keydown',
            
            'keyup',
            
            'keypress'
        );
        me.addStateEvents('change');
        me.setGrowSizePolicy();
    },

    
    setGrowSizePolicy: function(){
        if (this.grow) {
            this.shrinkWrap |= 1; 
        }    
    },

    
    initEvents : function(){
        var me = this,
            el = me.inputEl;

        me.callParent();
        if(me.selectOnFocus || me.emptyText){
            me.mon(el, 'mousedown', me.onMouseDown, me);
        }
        if(me.maskRe || (me.vtype && me.disableKeyFilter !== true && (me.maskRe = Ext.form.field.VTypes[me.vtype+'Mask']))){
            me.mon(el, 'keypress', me.filterKeys, me);
        }

        if (me.enableKeyEvents) {
            me.mon(el, {
                scope: me,
                keyup: me.onKeyUp,
                keydown: me.onKeyDown,
                keypress: me.onKeyPress
            });
        }
    },

    
    isEqual: function(value1, value2) {
        return this.isEqualAsString(value1, value2);
    },

    
    onChange: function() {
        this.callParent();
        this.autoSize();
    },

    getSubTplData: function() {
        var me = this,
            value = me.getRawValue(),
            isEmpty = me.emptyText && value.length < 1,
            maxLength = me.maxLength,
            placeholder;
            
        
        
        
        if (me.enforceMaxLength) {
            if (maxLength === Number.MAX_VALUE) {
                maxLength = undefined;
            }
        } else {
            maxLength = undefined;
        }

        if (isEmpty) {
            if (Ext.supports.Placeholder) {
                placeholder = me.emptyText;
            } else {
                value = me.emptyText;
                me.valueContainsPlaceholder = true;
            }
        }

        return Ext.apply(me.callParent(), {
            maxLength   : maxLength,
            readOnly    : me.readOnly,
            placeholder : placeholder,
            value       : value,
            fieldCls    : me.fieldCls + ((isEmpty && (placeholder || value)) ? ' ' + me.emptyCls : '') + (me.allowBlank ? '' :  ' ' + me.requiredCls)
        });
    },

    afterRender: function(){
        this.autoSize();
        this.callParent();
    },

    onMouseDown: function(e){
        var me = this;
        if(!me.hasFocus){
            me.mon(me.inputEl, 'mouseup', Ext.emptyFn, me, { single: true, preventDefault: true });
        }
    },

    
    processRawValue: function(value) {
        var me = this,
            stripRe = me.stripCharsRe,
            newValue;

        if (stripRe) {
            newValue = value.replace(stripRe, '');
            if (newValue !== value) {
                me.setRawValue(newValue);
                value = newValue;
            }
        }
        return value;
    },

    
    onDisable: function(){
        this.callParent();
        if (Ext.isIE) {
            this.inputEl.dom.unselectable = 'on';
        }
    },

    
    onEnable: function(){
        this.callParent();
        if (Ext.isIE) {
            this.inputEl.dom.unselectable = '';
        }
    },

    onKeyDown: function(e) {
        this.fireEvent('keydown', this, e);
    },

    onKeyUp: function(e) {
        this.fireEvent('keyup', this, e);
    },

    onKeyPress: function(e) {
        this.fireEvent('keypress', this, e);
    },

    
    reset : function(){
        this.callParent();
        this.applyEmptyText();
    },

    applyEmptyText : function(){
        var me = this,
            emptyText = me.emptyText,
            isEmpty;

        if (me.rendered && emptyText) {
            isEmpty = me.getRawValue().length < 1 && !me.hasFocus;

            if (Ext.supports.Placeholder) {
                me.inputEl.dom.placeholder = emptyText;
            } else if (isEmpty) {
                me.setRawValue(emptyText);
                me.valueContainsPlaceholder = true;
            }

            
            
            if (isEmpty) {
                me.inputEl.addCls(me.emptyCls);
            }

            me.autoSize();
        }
    },
    
    afterFirstLayout: function() {
        this.callParent();
        if (Ext.isIE && this.disabled) {
            var el = this.inputEl;
            if (el) {
                el.dom.unselectable = 'on';
            }
        }
    },
    
    
    preFocus : function(){
        var me = this,
            inputEl = me.inputEl,
            emptyText = me.emptyText,
            isEmpty;

        me.callParent(arguments);
        if ((emptyText && !Ext.supports.Placeholder) && (inputEl.dom.value === me.emptyText && me.valueContainsPlaceholder)) {
            me.setRawValue('');
            isEmpty = true;
            inputEl.removeCls(me.emptyCls);
            me.valueContainsPlaceholder = false;
        } else if (Ext.supports.Placeholder) {
            me.inputEl.removeCls(me.emptyCls);
        }
        if (me.selectOnFocus || isEmpty) {
            inputEl.dom.select();
        }
    },

    onFocus: function() {
        var me = this;
        me.callParent(arguments);
        if (me.emptyText) {
            me.autoSize();
        }
    },

    
    postBlur : function(){
        this.callParent(arguments);
        this.applyEmptyText();
    },

    
    filterKeys : function(e){
        
        if (e.ctrlKey && !e.altKey) {
            return;
        }
        var key = e.getKey(),
            charCode = String.fromCharCode(e.getCharCode());

        if((Ext.isGecko || Ext.isOpera) && (e.isNavKeyPress() || key === e.BACKSPACE || (key === e.DELETE && e.button === -1))){
            return;
        }

        if((!Ext.isGecko && !Ext.isOpera) && e.isSpecialKey() && !charCode){
            return;
        }
        if(!this.maskRe.test(charCode)){
            e.stopEvent();
        }
    },

    getState: function() {
        return this.addPropertyToState(this.callParent(), 'value');
    },

    applyState: function(state) {
        this.callParent(arguments);
        if(state.hasOwnProperty('value')) {
            this.setValue(state.value);
        }
    },

    
    getRawValue: function() {
        var me = this,
            v = me.callParent();
        if (v === me.emptyText && me.valueContainsPlaceholder) {
            v = '';
        }
        return v;
    },

    
    setValue: function(value) {
        var me = this,
            inputEl = me.inputEl;

        if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
            inputEl.removeCls(me.emptyCls);
            me.valueContainsPlaceholder = false;
        }

        me.callParent(arguments);

        me.applyEmptyText();
        return me;
    },

    
    getErrors: function(value) {
        var me = this,
            errors = me.callParent(arguments),
            validator = me.validator,
            emptyText = me.emptyText,
            allowBlank = me.allowBlank,
            vtype = me.vtype,
            vtypes = Ext.form.field.VTypes,
            regex = me.regex,
            format = Ext.String.format,
            msg;

        value = value || me.processRawValue(me.getRawValue());

        if (Ext.isFunction(validator)) {
            msg = validator.call(me, value);
            if (msg !== true) {
                errors.push(msg);
            }
        }

        if (value.length < 1 || (value === me.emptyText && me.valueContainsPlaceholder)) {
            if (!allowBlank) {
                errors.push(me.blankText);
            }
            
            return errors;
        }

        if (value.length < me.minLength) {
            errors.push(format(me.minLengthText, me.minLength));
        }

        if (value.length > me.maxLength) {
            errors.push(format(me.maxLengthText, me.maxLength));
        }

        if (vtype) {
            if(!vtypes[vtype](value, me)){
                errors.push(me.vtypeText || vtypes[vtype +'Text']);
            }
        }

        if (regex && !regex.test(value)) {
            errors.push(me.regexText || me.invalidText);
        }

        return errors;
    },

    
    selectText : function(start, end){
        var me = this,
            v = me.getRawValue(),
            doFocus = true,
            el = me.inputEl.dom,
            undef,
            range;

        if (v.length > 0) {
            start = start === undef ? 0 : start;
            end = end === undef ? v.length : end;
            if (el.setSelectionRange) {
                el.setSelectionRange(start, end);
            }
            else if(el.createTextRange) {
                range = el.createTextRange();
                range.moveStart('character', start);
                range.moveEnd('character', end - v.length);
                range.select();
            }
            doFocus = Ext.isGecko || Ext.isOpera;
        }
        if (doFocus) {
            me.focus();
        }
    },

    
    autoSize: function() {
        var me = this;
        if (me.grow && me.rendered) {
            me.autoSizing = true;
            me.updateLayout();
        }
    },

    afterComponentLayout: function() {
        var me = this,
            width;

        me.callParent(arguments);
        if (me.autoSizing) {
            width = me.inputEl.getWidth();
            if (width !== me.lastInputWidth) {
                me.fireEvent('autosize', me, width);
                me.lastInputWidth = width;
                delete me.autoSizing;
            }
        }
    }
});


Ext.define('Ext.layout.component.field.TextArea', {
    extend: 'Ext.layout.component.field.Text',
    alias: 'layout.textareafield',

    type: 'textareafield',
    
    canGrowWidth: false,
    
    naturalSizingProp: 'cols',
    
    beginLayout: function(ownerContext){
        this.callParent(arguments);
        ownerContext.target.inputEl.setStyle('height', '');
    },

    measureContentHeight: function (ownerContext) {
        var me = this,
            owner = me.owner,
            height = me.callParent(arguments),
            inputContext, inputEl, value, max, curWidth, calcHeight;

        if (owner.grow && !ownerContext.state.growHandled) {
            inputContext = ownerContext.inputContext;
            inputEl = owner.inputEl;
            curWidth = inputEl.getWidth(true); 

            
            value = Ext.util.Format.htmlEncode(inputEl.dom.value) || '&#160;';
            value += owner.growAppend;
            
            
            value = value.replace(/\n/g, '<br/>');

            
            calcHeight = Ext.util.TextMetrics.measure(inputEl, value, curWidth).height +
                         inputContext.getBorderInfo().height + inputContext.getPaddingInfo().height;

            
            calcHeight = Ext.Number.constrain(calcHeight, owner.growMin, owner.growMax);
            inputContext.setHeight(calcHeight);
            ownerContext.state.growHandled = true;
            
            
            inputContext.domBlock(me, 'height');
            height = NaN;
        }
        return height;
    }
});


Ext.define('Ext.form.field.TextArea', {
    extend:'Ext.form.field.Text',
    alias: ['widget.textareafield', 'widget.textarea'],
    alternateClassName: 'Ext.form.TextArea',
    requires: [
        'Ext.XTemplate', 
        'Ext.layout.component.field.TextArea',
        'Ext.util.DelayedTask'
    ],

    
    
    
    
    
    
    
    fieldSubTpl: [
        '<textarea id="{id}" {inputAttrTpl}',
            '<tpl if="name"> name="{name}"</tpl>',
            '<tpl if="rows"> rows="{rows}" </tpl>',
            '<tpl if="cols"> cols="{cols}" </tpl>',
            '<tpl if="placeholder"> placeholder="{placeholder}"</tpl>',
            '<tpl if="size"> size="{size}"</tpl>',
            '<tpl if="maxLength !== undefined"> maxlength="{maxLength}"</tpl>',
            '<tpl if="readOnly"> readonly="readonly"</tpl>',
            '<tpl if="disabled"> disabled="disabled"</tpl>',
            '<tpl if="tabIdx"> tabIndex="{tabIdx}"</tpl>',
            ' class="{fieldCls} {typeCls}" ',
            '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
            ' autocomplete="off">\n',
            '<tpl if="value">{[Ext.util.Format.htmlEncode(values.value)]}</tpl>',
        '</textarea>',
        {
            disableFormats: true
        }
    ],

    
    growMin: 60,

    
    growMax: 1000,

    
    growAppend: '\n-',

    
    cols: 20,

    
    rows: 4,

    
    enterIsSpecial: false,

    
    preventScrollbars: false,

    
    componentLayout: 'textareafield',
    
    setGrowSizePolicy: Ext.emptyFn,
    
    returnRe: /\r/g,

    
    getSubTplData: function() {
        var me = this,
            fieldStyle = me.getFieldStyle(),
            ret = me.callParent();

        if (me.grow) {
            if (me.preventScrollbars) {
                ret.fieldStyle = (fieldStyle||'') + ';overflow:hidden;height:' + me.growMin + 'px';
            }
        }

        Ext.applyIf(ret, {
            cols: me.cols,
            rows: me.rows
        });

        return ret;
    },

    afterRender: function () {
        var me = this;

        me.callParent(arguments);

        me.needsMaxCheck = me.enforceMaxLength && me.maxLength !== Number.MAX_VALUE && !Ext.supports.TextAreaMaxLength;
        if (me.needsMaxCheck) {
            me.inputEl.on('paste', me.onPaste, me);
        }
    },
    
    
    
    
    
    
    
    transformRawValue: function(value){
        return this.stripReturns(value);
    },
    
    transformOriginalValue: function(value){
        return this.stripReturns(value); 
    },
    
    valueToRaw: function(value){
        value = this.stripReturns(value);
        return this.callParent([value]);
    },
    
    stripReturns: function(value){
        if (value) {
            value = value.replace(this.returnRe, '');
        }
        return value;
    },

    onPaste: function(e){
        var me = this;
        if (!me.pasteTask) {
            me.pasteTask = new Ext.util.DelayedTask(me.pasteCheck, me);
        }
        
        me.pasteTask.delay(1);
    },
    
    pasteCheck: function(){
        var me = this,
            value = me.getValue(),
            max = me.maxLength;
            
        if (value.length > max) {
            value = value.substr(0, max);
            me.setValue(value);
        }
    },

    
    fireKey: function(e) {
        var me = this,
            key = e.getKey(),
            value;
            
        if (e.isSpecialKey() && (me.enterIsSpecial || (key !== e.ENTER || e.hasModifier()))) {
            me.fireEvent('specialkey', me, e);
        }
        
        if (me.needsMaxCheck && key !== e.BACKSPACE && key !== e.DELETE && !e.isNavKeyPress() && !me.isCutCopyPasteSelectAll(e, key)) {
            value = me.getValue();
            if (value.length >= me.maxLength) {
                e.stopEvent();
            }
        }
    },
    
    isCutCopyPasteSelectAll: function(e, key) {
        if (e.CTRL) {
            return key === e.A || key === e.C || key === e.V || key === e.X;
        }
        return false;
    },

    
    autoSize: function() {
        var me = this,
            height;

        if (me.grow && me.rendered) {
            me.updateLayout();
            height = me.inputEl.getHeight();
            if (height !== me.lastInputHeight) {
                
                me.fireEvent('autosize', me, height);
                me.lastInputHeight = height;
            }
        }
    },

    
    initAria: function() {
        this.callParent(arguments);
        this.getActionEl().dom.setAttribute('aria-multiline', true);
    },
    
    beforeDestroy: function(){
        var task = this.pasteTask;
        if (task) {
            task.delay();
        }    
        this.callParent();
    }
});

Ext.define('Ext.layout.component.field.Trigger', {

    

    alias: 'layout.triggerfield',

    extend: 'Ext.layout.component.field.Field',

    

    type: 'triggerfield',

    beginLayout: function(ownerContext) {
        var me = this,
            owner = me.owner,
            flags;

        ownerContext.triggerWrap = ownerContext.getEl('triggerWrap');

        me.callParent(arguments);

        
        flags = owner.getTriggerStateFlags();
        if (flags != owner.lastTriggerStateFlags) {
            owner.lastTriggerStateFlags = flags;
            me.updateEditState();
        }
    },

    beginLayoutFixed: function (ownerContext, width, suffix) {
        var me = this,
            owner = ownerContext.target,
            ieInputWidthAdjustment = me.ieInputWidthAdjustment || 0,
            inputWidth = '100%',
            triggerWrap = owner.triggerWrap;

        me.callParent(arguments);

        owner.inputCell.setStyle('width', '100%');
        if(ieInputWidthAdjustment) {
            
            
            owner.inputCell.setStyle('padding-right', ieInputWidthAdjustment + 'px');
            if(suffix === 'px') {
                if (owner.inputWidth) {
                    inputWidth = owner.inputWidth - owner.getTriggerWidth();
                } else {
                    inputWidth = width - ieInputWidthAdjustment - owner.getTriggerWidth();
                }
                inputWidth += 'px';
            }
        }
        owner.inputEl.setStyle('width', inputWidth);
        inputWidth = owner.inputWidth;
        if (inputWidth) {
            triggerWrap.setStyle('width', inputWidth + (ieInputWidthAdjustment) + 'px');
        } else {
            triggerWrap.setStyle('width', width + suffix);
        }
        triggerWrap.setStyle('table-layout', 'fixed');
    },

    beginLayoutShrinkWrap: function (ownerContext) {
        var owner = ownerContext.target,
            emptyString = '',
            inputWidth = owner.inputWidth,
            triggerWrap = owner.triggerWrap,
            ieInputWidthAdjustment = this.ieInputWidthAdjustment || 0;

        this.callParent(arguments);

        if (inputWidth) {
            triggerWrap.setStyle('width', inputWidth + 'px');
            inputWidth = (inputWidth - owner.getTriggerWidth()) + 'px';
            owner.inputEl.setStyle('width', inputWidth);
            owner.inputCell.setStyle('width', inputWidth);
        } else {
            owner.inputCell.setStyle('width', emptyString);
            owner.inputEl.setStyle('width', emptyString);
            triggerWrap.setStyle('width', emptyString);
            triggerWrap.setStyle('table-layout', 'auto');
        }
    },

    getTextWidth: function () {
        var me = this,
            owner = me.owner,
            inputEl = owner.inputEl,
            value;

        
        value = (inputEl.dom.value || (owner.hasFocus ? '' : owner.emptyText) || '') + owner.growAppend;
        return inputEl.getTextWidth(value);
    },

    measureContentWidth: function (ownerContext) {
        var me = this,
            owner = me.owner,
            width = me.callParent(arguments),
            inputContext = ownerContext.inputContext,
            calcWidth, max, min;

        if (owner.grow && !ownerContext.state.growHandled) {
            calcWidth = me.getTextWidth() + ownerContext.inputContext.getFrameInfo().width;

            max = owner.growMax;
            min = Math.min(max, width);
            max = Math.max(owner.growMin, max, min);

            
            calcWidth = Ext.Number.constrain(calcWidth, owner.growMin, max);
            inputContext.setWidth(calcWidth);
            ownerContext.state.growHandled = true;
            
            
            inputContext.domBlock(me, 'width');
            width = NaN;
        }
        return width;
    },

    updateEditState: function() {
        var me = this,
            owner = me.owner,
            inputEl = owner.inputEl,
            noeditCls = Ext.baseCSSPrefix + 'trigger-noedit',
            displayed,
            readOnly;

        if (me.owner.readOnly) {
            inputEl.addCls(noeditCls);
            readOnly = true;
            displayed = false;
        } else {
            if (me.owner.editable) {
                inputEl.removeCls(noeditCls);
                readOnly = false;
            } else {
                inputEl.addCls(noeditCls);
                readOnly = true;
            }
            displayed = !me.owner.hideTrigger;
        }

        owner.triggerCell.setDisplayed(displayed);
        inputEl.dom.readOnly = readOnly;
    }
});


Ext.define('Ext.form.field.Trigger', {
    extend:'Ext.form.field.Text',
    alias: ['widget.triggerfield', 'widget.trigger'],
    requires: ['Ext.DomHelper', 'Ext.util.ClickRepeater', 'Ext.layout.component.field.Trigger'],
    alternateClassName: ['Ext.form.TriggerField', 'Ext.form.TwinTriggerField', 'Ext.form.Trigger'],

    childEls: [
        
        { name: 'triggerCell', select: '.' + Ext.baseCSSPrefix + 'trigger-cell' },
        { name: 'triggerEl', select: '.' + Ext.baseCSSPrefix + 'form-trigger' },

        
        'triggerWrap',

        
        'inputCell'
    ],

    

    
    triggerBaseCls: Ext.baseCSSPrefix + 'form-trigger',

    
    triggerWrapCls: Ext.baseCSSPrefix + 'form-trigger-wrap',

    
    triggerNoEditCls: Ext.baseCSSPrefix + 'trigger-noedit',

    
    hideTrigger: false,

    
    editable: true,

    
    readOnly: false,

    

    
    repeatTriggerClick: false,


    
    autoSize: Ext.emptyFn,
    
    monitorTab: true,
    
    mimicing: false,
    
    triggerIndexRe: /trigger-index-(\d+)/,

    componentLayout: 'triggerfield',

    initComponent: function() {
        this.wrapFocusCls = this.triggerWrapCls + '-focus';
        this.callParent(arguments);
    },

    getSubTplMarkup: function() {
        var me = this,
            field = me.callParent(arguments);

        return '<table id="' + me.id + '-triggerWrap" class="' + Ext.baseCSSPrefix + 'form-trigger-wrap" cellpadding="0" cellspacing="0"><tbody><tr>' +
            '<td id="' + me.id + '-inputCell" class="' + Ext.baseCSSPrefix + 'form-trigger-input-cell">' + field + '</td>' +
            me.getTriggerMarkup() +
            '</tr></tbody></table>';
    },
    
    getSubTplData: function(){
        var me = this,
            data = me.callParent(),
            readOnly = me.readOnly === true,
            editable = me.editable !== false;
        
        return Ext.apply(data, {
            editableCls: (readOnly || !editable) ? ' ' + me.triggerNoEditCls : '',
            readOnly: !editable || readOnly
        });  
    },

    getLabelableRenderData: function() {
        var me = this,
            triggerWrapCls = me.triggerWrapCls,
            result = me.callParent(arguments);

        return Ext.applyIf(result, {
            triggerWrapCls: triggerWrapCls,
            triggerMarkup: me.getTriggerMarkup()
        });
    },

    getTriggerMarkup: function() {
        var me = this,
            i = 0,
            hideTrigger = (me.readOnly || me.hideTrigger),
            triggerCls,
            triggerBaseCls = me.triggerBaseCls,
            triggerConfigs = [];

        
        
        
        
        if (!me.trigger1Cls) {
            me.trigger1Cls = me.triggerCls;
        }

        
        for (i = 0; (triggerCls = me['trigger' + (i + 1) + 'Cls']) || i < 1; i++) {
            triggerConfigs.push({
                tag: 'td',
                valign: 'top',
                cls: Ext.baseCSSPrefix + 'trigger-cell',
                style: 'width:' + me.triggerWidth + (hideTrigger ? 'px;display:none' : 'px'),
                cn: {
                    cls: [Ext.baseCSSPrefix + 'trigger-index-' + i, triggerBaseCls, triggerCls].join(' '),
                    role: 'button'
                }
            });
        }
        triggerConfigs[i - 1].cn.cls += ' ' + triggerBaseCls + '-last';

        return Ext.DomHelper.markup(triggerConfigs);
    },
    
    disableCheck: function() {
        return !this.disabled;    
    },

    
    beforeRender: function() {
        var me = this,
            triggerBaseCls = me.triggerBaseCls,
            tempEl;
            
        
        if (!me.triggerWidth) {
            tempEl = Ext.resetElement.createChild({
                style: 'position: absolute;', 
                cls: Ext.baseCSSPrefix + 'form-trigger'
            });
            Ext.form.field.Trigger.prototype.triggerWidth = tempEl.getWidth();
            tempEl.remove();
        }

        me.callParent();

        if (triggerBaseCls != Ext.baseCSSPrefix + 'form-trigger') {
            
            
            me.addChildEls({ name: 'triggerEl', select: '.' + triggerBaseCls });
        }

        
        me.lastTriggerStateFlags = me.getTriggerStateFlags();
    },

    onRender: function() {
        var me = this;

        me.callParent(arguments);

        me.doc = Ext.getDoc();
        me.initTrigger();
        me.triggerEl.unselectable();
    },

    
    getTriggerWidth: function() {
        var me = this,
            totalTriggerWidth = 0;

        if (me.triggerWrap && !me.hideTrigger && !me.readOnly) {
            totalTriggerWidth = me.triggerEl.getCount() * me.triggerWidth;
        }
        return totalTriggerWidth;
    },

    setHideTrigger: function(hideTrigger) {
        if (hideTrigger != this.hideTrigger) {
            this.hideTrigger = hideTrigger;
            this.updateLayout();
        }
    },

    
    setEditable: function(editable) {
        if (editable != this.editable) {
            this.editable = editable;
            this.updateLayout();
        }
    },

    
    setReadOnly: function(readOnly) {
        if (readOnly != this.readOnly) {
            this.readOnly = readOnly;
            this.updateLayout();
        }
    },

    
    initTrigger: function() {
        var me = this,
            triggerWrap = me.triggerWrap,
            triggerEl = me.triggerEl,
            disableCheck = me.disableCheck,
            els, eLen, el, e, idx;

        if (me.repeatTriggerClick) {
            me.triggerRepeater = new Ext.util.ClickRepeater(triggerWrap, {
                preventDefault: true,
                handler: me.onTriggerWrapClick,
                listeners: {
                    mouseup: me.onTriggerWrapMouseup,
                    scope: me
                },
                scope: me
            });
        } else {
            me.mon(triggerWrap, {
                click: me.onTriggerWrapClick,
                mouseup: me.onTriggerWrapMouseup,
                scope: me
            });
        }

        triggerEl.setVisibilityMode(Ext.Element.DISPLAY);
        triggerEl.addClsOnOver(me.triggerBaseCls + '-over', disableCheck, me);

        els  = triggerEl.elements;
        eLen = els.length;

        for (e = 0; e < eLen; e++) {
            el = els[e];
            idx = e+1;
            el.addClsOnOver(me['trigger' + (idx) + 'Cls'] + '-over', disableCheck, me);
            el.addClsOnClick(me['trigger' + (idx) + 'Cls'] + '-click', disableCheck, me);
        }

        triggerEl.addClsOnClick(me.triggerBaseCls + '-click', disableCheck, me);

    },

    
    onDestroy: function() {
        var me = this;
        Ext.destroyMembers(me, 'triggerRepeater', 'triggerWrap', 'triggerEl');
        delete me.doc;
        me.callParent();
    },

    
    onFocus: function() {
        var me = this;
        me.callParent(arguments);
        if (!me.mimicing) {
            me.bodyEl.addCls(me.wrapFocusCls);
            me.mimicing = true;
            me.mon(me.doc, 'mousedown', me.mimicBlur, me, {
                delay: 10
            });
            if (me.monitorTab) {
                me.on('specialkey', me.checkTab, me);
            }
        }
    },

    
    checkTab: function(me, e) {
        if (!this.ignoreMonitorTab && e.getKey() == e.TAB) {
            this.triggerBlur();
        }
    },

    
    getTriggerStateFlags: function () {
        var me = this,
            state = 0;

        if (me.readOnly) {
            state += 1;
        }
        if (me.editable) {
            state += 2;
        }
        if (me.hideTrigger) {
            state += 4;
        }
        return state;
    },

    
    onBlur: Ext.emptyFn,

    
    mimicBlur: function(e) {
        if (!this.isDestroyed && !this.bodyEl.contains(e.target) && this.validateBlur(e)) {
            this.triggerBlur(e);
        }
    },

    
    triggerBlur: function(e) {
        var me = this;
        me.mimicing = false;
        me.mun(me.doc, 'mousedown', me.mimicBlur, me);
        if (me.monitorTab && me.inputEl) {
            me.un('specialkey', me.checkTab, me);
        }
        Ext.form.field.Trigger.superclass.onBlur.call(me, e);
        if (me.bodyEl) {
            me.bodyEl.removeCls(me.wrapFocusCls);
        }
    },

    
    
    validateBlur: function(e) {
        return true;
    },

    
    
    
    onTriggerWrapClick: function() {
        var me = this,
            targetEl, match,
            triggerClickMethod,
            event;

        event = arguments[me.triggerRepeater ? 1 : 0];
        if (event && !me.readOnly && !me.disabled) {
                targetEl = event.getTarget('.' + me.triggerBaseCls, null);
                match = targetEl && targetEl.className.match(me.triggerIndexRe);

            if (match) {
                triggerClickMethod = me['onTrigger' + (parseInt(match[1], 10) + 1) + 'Click'] || me.onTriggerClick;
                if (triggerClickMethod) {
                    triggerClickMethod.call(me, event);
                }
            }
        }
    },

    
    
    
    onTriggerWrapMouseup: Ext.emptyFn,

    
    onTriggerClick: Ext.emptyFn

    
    
    
});


Ext.define("Ext.form.field.File", {
    extend: 'Ext.form.field.Trigger',
    alias: ['widget.filefield', 'widget.fileuploadfield'],
    alternateClassName: ['Ext.form.FileUploadField', 'Ext.ux.form.FileUploadField', 'Ext.form.File'],
    uses: ['Ext.button.Button', 'Ext.layout.component.field.Field'],

    
    
    buttonText: 'Browse...',
    

    
    buttonOnly: false,

    
    buttonMargin: 3,

    

    

    

    

    
    fieldBodyCls: Ext.baseCSSPrefix + 'form-file-wrap',

    
    readOnly: true,

    
    triggerNoEditCls: '',

    
    componentLayout: 'triggerfield',

    
    childEls: ['fileInputEl', 'buttonEl', 'buttonEl-btnEl', 'browseButtonWrap'],

    
    onRender: function() {
        var me = this,
            inputEl;

        me.callParent(arguments);

        inputEl = me.inputEl;
        inputEl.dom.name = ''; 

        me.fileInputEl.dom.name = me.getName();
        me.fileInputEl.on({
            scope: me,
            change: me.onFileChange
        });

        if (me.buttonOnly) {
            me.inputCell.setDisplayed(false);
        }

        
        me.browseButtonWrap.dom.style.width = (me.browseButtonWrap.dom.lastChild.offsetWidth + me.buttonEl.getMargin('lr')) + 'px';
        if (Ext.isIE) {
            me.buttonEl.repaint();
        }
    },

    
    getTriggerMarkup: function() {
        var me = this,
            result,
            btn = Ext.widget('button', Ext.apply({
                id: me.id + '-buttonEl',
                ui: me.ui,
                disabled: me.disabled,
                text: me.buttonText,
                cls: Ext.baseCSSPrefix + 'form-file-btn',
                preventDefault: false,
                style: me.buttonOnly ? '' : 'margin-left:' + me.buttonMargin + 'px'
            }, me.buttonConfig)),
            btnCfg = btn.getRenderTree(),
            inputElCfg = {
                id: me.id + '-fileInputEl',
                cls: Ext.baseCSSPrefix + 'form-file-input',
                tag: 'input',
                type: 'file',
                size: 1
            };
        if (me.disabled) {
            inputElCfg.disabled = true;
        }
        btnCfg.cn = inputElCfg;
        result = '<td id="' + me.id + '-browseButtonWrap">' + Ext.DomHelper.markup(btnCfg) + '</td>';
        btn.destroy();
        return result;
    },

    
    createFileInput : function() {
        var me = this;
        me.fileInputEl = me.buttonEl.createChild({
            name: me.getName(),
            id: me.id + '-fileInputEl',
            cls: Ext.baseCSSPrefix + 'form-file-input',
            tag: 'input',
            type: 'file',
            size: 1
        });
        me.fileInputEl.on({
            scope: me,
            change: me.onFileChange
        });
    },

    
    onFileChange: function() {
        this.lastValue = null; 
        Ext.form.field.File.superclass.setValue.call(this, this.fileInputEl.dom.value);
    },

    
    setValue: Ext.emptyFn,

    reset : function(){
        var me = this;
        if (me.rendered) {
            me.fileInputEl.remove();
            me.createFileInput();
            me.inputEl.dom.value = '';
        }
        me.callParent();
    },

    onDisable: function(){
        this.callParent();
        this.disableItems();
    },
    
    disableItems: function(){
        var file = this.fileInputEl;
        if (file) {
            file.dom.disabled = true;
        }
        this['buttonEl-btnEl'].dom.disabled = true;
    },

    onEnable: function(){
        var me = this;
        me.callParent();
        me.fileInputEl.dom.disabled = false;
        this['buttonEl-btnEl'].dom.disabled = false;
    },

    isFileUpload: function() {
        return true;
    },

    extractFileInput: function() {
        var fileInput = this.fileInputEl.dom;
        this.reset();
        return fileInput;
    },

    onDestroy: function(){
        Ext.destroyMembers(this, 'fileInputEl', 'buttonEl');
        this.callParent();
    }
});

Ext.define('Ext.form.field.Picker', {
    extend: 'Ext.form.field.Trigger',
    alias: 'widget.pickerfield',
    alternateClassName: 'Ext.form.Picker',
    requires: ['Ext.util.KeyNav'],

    
    matchFieldWidth: true,

    
    pickerAlign: 'tl-bl?',

    

    
    openCls: Ext.baseCSSPrefix + 'pickerfield-open',

    

    
    editable: true,


    initComponent: function() {
        this.callParent();

        
        this.addEvents(
            
            'expand',
            
            'collapse',
            
            'select'
        );
    },


    initEvents: function() {
        var me = this;
        me.callParent();

        
        me.keyNav = new Ext.util.KeyNav(me.inputEl, {
            down: me.onDownArrow,
            esc: {
                handler: me.onEsc,
                scope: me,
                defaultEventAction: false
            },
            scope: me,
            forceKeyDown: true
        });

        
        if (!me.editable) {
            me.mon(me.inputEl, 'click', me.onTriggerClick, me);
        }

        
        if (Ext.isGecko) {
            me.inputEl.dom.setAttribute('autocomplete', 'off');
        }
    },

    
    onEsc: function(e) {
        var me = this;
        if (me.isExpanded) {
            me.collapse();
            e.stopEvent();
        } else {
            
            
            if (me.up('window')) {
                me.blur();
            }
            
            else if ((!Ext.FocusManager || !Ext.FocusManager.enabled)) {
                e.stopEvent();
            }
        }
    },

    onDownArrow: function(e) {
        if (!this.isExpanded) {
            
            
            this.onTriggerClick();
        }
    },

    
    expand: function() {
        var me = this,
            bodyEl, picker, collapseIf;

        if (me.rendered && !me.isExpanded && !me.isDestroyed) {
            bodyEl = me.bodyEl;
            picker = me.getPicker();
            collapseIf = me.collapseIf;

            
            picker.show();
            me.isExpanded = true;
            me.alignPicker();
            bodyEl.addCls(me.openCls);

            
            me.mon(Ext.getDoc(), {
                mousewheel: collapseIf,
                mousedown: collapseIf,
                scope: me
            });
            Ext.EventManager.onWindowResize(me.alignPicker, me);
            me.fireEvent('expand', me);
            me.onExpand();
        }
    },

    onExpand: Ext.emptyFn,

    
    alignPicker: function() {
        var me = this,
            picker = me.getPicker();

        if (me.isExpanded) {
            if (me.matchFieldWidth) {
                
                picker.setWidth(me.bodyEl.getWidth());
            }
            if (picker.isFloating()) {
                me.doAlign();
            }
        }
    },

    
    doAlign: function(){
        var me = this,
            picker = me.picker,
            aboveSfx = '-above',
            isAbove;

        me.picker.alignTo(me.inputEl, me.pickerAlign, me.pickerOffset);
        
        
        isAbove = picker.el.getY() < me.inputEl.getY();
        me.bodyEl[isAbove ? 'addCls' : 'removeCls'](me.openCls + aboveSfx);
        picker[isAbove ? 'addCls' : 'removeCls'](picker.baseCls + aboveSfx);
    },

    
    collapse: function() {
        if (this.isExpanded && !this.isDestroyed) {
            var me = this,
                openCls = me.openCls,
                picker = me.picker,
                doc = Ext.getDoc(),
                collapseIf = me.collapseIf,
                aboveSfx = '-above';

            
            picker.hide();
            me.isExpanded = false;

            
            me.bodyEl.removeCls([openCls, openCls + aboveSfx]);
            picker.el.removeCls(picker.baseCls + aboveSfx);

            
            doc.un('mousewheel', collapseIf, me);
            doc.un('mousedown', collapseIf, me);
            Ext.EventManager.removeResizeListener(me.alignPicker, me);
            me.fireEvent('collapse', me);
            me.onCollapse();
        }
    },

    onCollapse: Ext.emptyFn,


    
    collapseIf: function(e) {
        var me = this;

        if (!me.isDestroyed && !e.within(me.bodyEl, false, true) && !e.within(me.picker.el, false, true) && !me.isEventWithinPickerLoadMask(e)) {
            me.collapse();
        }
    },

    
    getPicker: function() {
        var me = this;
        return me.picker || (me.picker = me.createPicker());
    },

    
    createPicker: Ext.emptyFn,

    
    onTriggerClick: function() {
        var me = this;
        if (!me.readOnly && !me.disabled) {
            if (me.isExpanded) {
                me.collapse();
            } else {
                me.expand();
            }
            me.inputEl.focus();
        }
    },

    mimicBlur: function(e) {
        var me = this,
            picker = me.picker;
        
        if (!picker || !e.within(picker.el, false, true) && !me.isEventWithinPickerLoadMask(e)) {
            me.callParent(arguments);
        }
    },

    onDestroy : function(){
        var me = this,
            picker = me.picker;

        Ext.EventManager.removeResizeListener(me.alignPicker, me);
        Ext.destroy(me.keyNav);
        if (picker) {
            delete picker.pickerField;
            picker.destroy();
        }
        me.callParent();
    },

    
    isEventWithinPickerLoadMask: function(e) {
        var loadMask = this.picker.loadMask;

        return loadMask ? e.within(loadMask.maskEl, false, true) || e.within(loadMask.el, false, true) : false;
    }

});



Ext.define('Ext.form.field.Spinner', {
    extend: 'Ext.form.field.Trigger',
    alias: 'widget.spinnerfield',
    alternateClassName: 'Ext.form.Spinner',
    requires: ['Ext.util.KeyNav'],

    trigger1Cls: Ext.baseCSSPrefix + 'form-spinner-up',
    trigger2Cls: Ext.baseCSSPrefix + 'form-spinner-down',

    
    spinUpEnabled: true,

    
    spinDownEnabled: true,

    
    keyNavEnabled: true,

    
    mouseWheelEnabled: true,

    
    repeatTriggerClick: true,

    
    onSpinUp: Ext.emptyFn,

    
    onSpinDown: Ext.emptyFn,

    triggerTpl: '<td style="{triggerStyle}">' +
                    '<div class="' + Ext.baseCSSPrefix + 'trigger-index-0 ' + Ext.baseCSSPrefix + 'form-trigger ' + Ext.baseCSSPrefix + 'form-spinner-up" role="button"></div>' +
                    '<div class="' + Ext.baseCSSPrefix + 'trigger-index-1 ' + Ext.baseCSSPrefix + 'form-trigger ' + Ext.baseCSSPrefix + 'form-spinner-down" role="button"></div>' +
                '</td>' +
            '</tr>',

    initComponent: function() {
        this.callParent();

        this.addEvents(
            
            'spin',

            
            'spinup',

            
            'spindown'
        );
    },

    
    onRender: function() {
        var me = this,
            triggers;

        me.callParent(arguments);
        triggers = me.triggerEl;
        
        
        me.spinUpEl = triggers.item(0);
        
        me.spinDownEl = triggers.item(1);
        
        me.triggerCell = me.spinUpEl.parent(); 

        
        me.setSpinUpEnabled(me.spinUpEnabled);
        me.setSpinDownEnabled(me.spinDownEnabled);

        
        if (me.keyNavEnabled) {
            me.spinnerKeyNav = new Ext.util.KeyNav(me.inputEl, {
                scope: me,
                up: me.spinUp,
                down: me.spinDown
            });
        }

        
        if (me.mouseWheelEnabled) {
            me.mon(me.bodyEl, 'mousewheel', me.onMouseWheel, me);
        }
    },

    getSubTplMarkup: function() {
        var me = this,
            field = Ext.form.field.Base.prototype.getSubTplMarkup.apply(me, arguments);

        return '<table id="' + me.id + '-triggerWrap" class="' + Ext.baseCSSPrefix + 'form-trigger-wrap" cellpadding="0" cellspacing="0">' +
            '<tbody>' +
                '<tr><td id="' + me.id + '-inputCell" class="' + Ext.baseCSSPrefix + 'form-trigger-input-cell">' + field + '</td>' +
                me.getTriggerMarkup() +
            '</tbody></table>';
    },

    getTriggerMarkup: function() {
        var me = this,
            hideTrigger = (me.readOnly || me.hideTrigger);

        return me.getTpl('triggerTpl').apply({
            triggerStyle: 'width:' + me.triggerWidth + (hideTrigger ? 'px;display:none' : 'px')
        });
    },

    
    getTriggerWidth: function() {
        var me = this,
            totalTriggerWidth = 0;

        if (me.triggerWrap && !me.hideTrigger && !me.readOnly) {
            totalTriggerWidth = me.triggerWidth;
        }
        return totalTriggerWidth;
    },

    
    onTrigger1Click: function() {
        this.spinUp();
    },

    
    onTrigger2Click: function() {
        this.spinDown();
    },

    
    
    onTriggerWrapMouseup: function() {
        this.inputEl.focus();
    },

    
    spinUp: function() {
        var me = this;
        if (me.spinUpEnabled && !me.disabled) {
            me.fireEvent('spin', me, 'up');
            me.fireEvent('spinup', me);
            me.onSpinUp();
        }
    },

    
    spinDown: function() {
        var me = this;
        if (me.spinDownEnabled && !me.disabled) {
            me.fireEvent('spin', me, 'down');
            me.fireEvent('spindown', me);
            me.onSpinDown();
        }
    },

    
    setSpinUpEnabled: function(enabled) {
        var me = this,
            wasEnabled = me.spinUpEnabled;
        me.spinUpEnabled = enabled;
        if (wasEnabled !== enabled && me.rendered) {
            me.spinUpEl[enabled ? 'removeCls' : 'addCls'](me.trigger1Cls + '-disabled');
        }
    },

    
    setSpinDownEnabled: function(enabled) {
        var me = this,
            wasEnabled = me.spinDownEnabled;
        me.spinDownEnabled = enabled;
        if (wasEnabled !== enabled && me.rendered) {
            me.spinDownEl[enabled ? 'removeCls' : 'addCls'](me.trigger2Cls + '-disabled');
        }
    },

    
    onMouseWheel: function(e) {
        var me = this,
            delta;
        if (me.hasFocus) {
            delta = e.getWheelDelta();
            if (delta > 0) {
                me.spinUp();
            }
            else if (delta < 0) {
                me.spinDown();
            }
            e.stopEvent();
        }
    },

    onDestroy: function() {
        Ext.destroyMembers(this, 'spinnerKeyNav', 'spinUpEl', 'spinDownEl');
        this.callParent();
    }

});

Ext.define('Ext.form.field.Number', {
    extend:'Ext.form.field.Spinner',
    alias: 'widget.numberfield',
    alternateClassName: ['Ext.form.NumberField', 'Ext.form.Number'],

    
    

    
    allowDecimals : true,

    
    
    decimalSeparator : '.',
    
    
    
    
    submitLocaleSeparator: true,
    

    
    
    decimalPrecision : 2,
    

    
    minValue: Number.NEGATIVE_INFINITY,

    
    maxValue: Number.MAX_VALUE,

    
    step: 1,

    
    
    minText : 'The minimum value for this field is {0}',
    

    
    
    maxText : 'The maximum value for this field is {0}',
    

    
    
    nanText : '{0} is not a valid number',
    

    
    
    negativeText : 'The value cannot be negative',
    

    
    baseChars : '0123456789',

    
    autoStripChars: false,

    initComponent: function() {
        var me = this,
            allowed;

        me.callParent();

        me.setMinValue(me.minValue);
        me.setMaxValue(me.maxValue);

        
        if (me.disableKeyFilter !== true) {
            allowed = me.baseChars + '';
            if (me.allowDecimals) {
                allowed += me.decimalSeparator;
            }
            if (me.minValue < 0) {
                allowed += '-';
            }
            allowed = Ext.String.escapeRegex(allowed);
            me.maskRe = new RegExp('[' + allowed + ']');
            if (me.autoStripChars) {
                me.stripCharsRe = new RegExp('[^' + allowed + ']', 'gi');
            }
        }
    },

    
    getErrors: function(value) {
        var me = this,
            errors = me.callParent(arguments),
            format = Ext.String.format,
            num;

        value = Ext.isDefined(value) ? value : this.processRawValue(this.getRawValue());

        if (value.length < 1) { 
             return errors;
        }

        value = String(value).replace(me.decimalSeparator, '.');

        if(isNaN(value)){
            errors.push(format(me.nanText, value));
        }

        num = me.parseValue(value);

        if (me.minValue === 0 && num < 0) {
            errors.push(this.negativeText);
        }
        else if (num < me.minValue) {
            errors.push(format(me.minText, me.minValue));
        }

        if (num > me.maxValue) {
            errors.push(format(me.maxText, me.maxValue));
        }


        return errors;
    },

    rawToValue: function(rawValue) {
        var value = this.fixPrecision(this.parseValue(rawValue));
        if (value === null) {
            value = rawValue || null;
        }
        return  value;
    },

    valueToRaw: function(value) {
        var me = this,
            decimalSeparator = me.decimalSeparator;
        value = me.parseValue(value);
        value = me.fixPrecision(value);
        value = Ext.isNumber(value) ? value : parseFloat(String(value).replace(decimalSeparator, '.'));
        value = isNaN(value) ? '' : String(value).replace('.', decimalSeparator);
        return value;
    },
    
    getSubmitValue: function() {
        var me = this,
            value = me.callParent();
            
        if (!me.submitLocaleSeparator) {
            value = value.replace(me.decimalSeparator, '.');
        }  
        return value;
    },

    onChange: function() {
        this.toggleSpinners();
        this.callParent(arguments);
    },
    
    toggleSpinners: function(){
        var me = this,
            value = me.getValue(),
            valueIsNull = value === null;
            
        me.setSpinUpEnabled(valueIsNull || value < me.maxValue);
        me.setSpinDownEnabled(valueIsNull || value > me.minValue);
    },

    
    setMinValue : function(value) {
        this.minValue = Ext.Number.from(value, Number.NEGATIVE_INFINITY);
        this.toggleSpinners();
    },

    
    setMaxValue: function(value) {
        this.maxValue = Ext.Number.from(value, Number.MAX_VALUE);
        this.toggleSpinners();
    },

    
    parseValue : function(value) {
        value = parseFloat(String(value).replace(this.decimalSeparator, '.'));
        return isNaN(value) ? null : value;
    },

    
    fixPrecision : function(value) {
        var me = this,
            nan = isNaN(value),
            precision = me.decimalPrecision;

        if (nan || !value) {
            return nan ? '' : value;
        } else if (!me.allowDecimals || precision <= 0) {
            precision = 0;
        }

        return parseFloat(Ext.Number.toFixed(parseFloat(value), precision));
    },

    beforeBlur : function() {
        var me = this,
            v = me.parseValue(me.getRawValue());

        if (!Ext.isEmpty(v)) {
            me.setValue(v);
        }
    },

    onSpinUp: function() {
        var me = this;
        if (!me.readOnly) {
            me.setValue(Ext.Number.constrain(me.getValue() + me.step, me.minValue, me.maxValue));
        }
    },

    onSpinDown: function() {
        var me = this;
        if (!me.readOnly) {
            me.setValue(Ext.Number.constrain(me.getValue() - me.step, me.minValue, me.maxValue));
        }
    }
});


Ext.define('Ext.layout.component.field.ComboBox', {
    extend: 'Ext.layout.component.field.Trigger',
    alias: 'layout.combobox',
    requires: ['Ext.util.TextMetrics'],

    type: 'combobox',

    startingWidth: null,

    getTextWidth: function () {
        var me = this,
            owner = me.owner,
            store = owner.store,
            field = owner.displayField,
            storeLn = store.data.length,
            value = '',
            i = 0, n = 0, ln, item, width;

        for (; i < storeLn; i++) {
            item = store.getAt(i).data[field];
            ln = item.length;
            
            if (ln > n) {
                n = ln;
                value = item;
            }
        }

        width = Math.max(me.callParent(arguments), owner.inputEl.getTextWidth(value + owner.growAppend));

        
        
        if (!me.startingWidth || owner.removingRecords) {
            me.startingWidth = width;

            
            
            if (width < owner.growMin) {
                owner.defaultListConfig.minWidth = owner.growMin;
            }

            owner.removingRecords = false;
        }
 
        
        return (width < me.startingWidth) ? me.startingWidth : width;
    }
});


Ext.define('Ext.layout.container.Container', {

    

    extend: 'Ext.layout.Layout',

    alternateClassName: 'Ext.layout.ContainerLayout',

    mixins: {
        elementCt: 'Ext.util.ElementContainer'
    },

    requires: [
        'Ext.XTemplate'
    ],

    type: 'container',

    

    

    
    manageOverflow: 0,

    
    beginCollapse: Ext.emptyFn,

    
    beginExpand: Ext.emptyFn,

    
    animatePolicy: null,

    childEls: [
        
        'overflowPadderEl'
    ],

    renderTpl: [
        '{%this.renderBody(out,values)%}'
    ],

    usesContainerHeight: true,
    usesContainerWidth: true,
    usesHeight: true,
    usesWidth: true,


    
    reserveScrollbar: false,

    
    lastOverflowAdjust: {
        width: 0,
        height: 0
    },

    constructor: function () {
        this.callParent(arguments);
        this.mixins.elementCt.constructor.call(this);
    },

    destroy : function() {
        this.callParent();
        this.mixins.elementCt.destroy.call(this);
    },

    initLayout: function() {
        var me = this,
            scrollbarWidth = Ext.getScrollbarSize().width;

        me.callParent();

        
        
        
        if (scrollbarWidth && me.manageOverflow && !me.hasOwnProperty('lastOverflowAdjust')) {
            if (me.owner.autoScroll || me.reserveScrollbar) {
                me.lastOverflowAdjust = {
                    width: scrollbarWidth,
                    height: 0
                };
            }
        }
    },

    
    beginLayout: function (ownerContext) {
        this.callParent(arguments);

        ownerContext.targetContext = ownerContext.getEl('getTarget', this);

        this.cacheChildItems(ownerContext);
    },

    beginLayoutCycle: function (ownerContext, firstCycle) {
        var me = this,
            padEl = me.overflowPadderEl;

        me.callParent(arguments);

        
        
        if (!ownerContext.state.overflowAdjust) {
            ownerContext.state.overflowAdjust = me.lastOverflowAdjust;
        }

        if (firstCycle) {
            if (me.usesContainerHeight) {
                ++ownerContext.consumersContainerHeight;
            }
            if (me.usesContainerWidth) {
                ++ownerContext.consumersContainerWidth;
            }
        }

        if (padEl) {
            padEl.setStyle('display', 'none');
        }
    },

    completeLayout: function (ownerContext) {
        
        this.lastOverflowAdjust = ownerContext.state.overflowAdjust;
    },

    cacheChildItems: function (ownerContext) {
        var context = ownerContext.context,
            childItems = [],
            items = this.getVisibleItems(),
            length = items.length,
            i;

        ownerContext.childItems = childItems;
        ownerContext.visibleItems = items;

        for (i = 0; i < length; ++i) {
            childItems.push(context.getCmp(items[i]));
        }
    },

    cacheElements: function () {
        var owner = this.owner;

        this.applyChildEls(owner.el, owner.id); 
    },

    calculateContentSize: function (ownerContext, dimensions) {
        var me = this,
            containerDimensions = (dimensions || 0) | me.manageOverflow |
                   ((ownerContext.widthModel.shrinkWrap ? 1 : 0) |
                    (ownerContext.heightModel.shrinkWrap ? 2 : 0)),
            calcWidth = (containerDimensions & 1) || undefined,
            calcHeight = (containerDimensions & 2) || undefined,
            childItems = ownerContext.childItems,
            length = childItems.length,
            contentHeight = 0,
            contentWidth = 0,
            needed = 0,
            props = ownerContext.props,
            targetXY, targetX, targetY, targetPadding,
            borders, child, childContext, childX, childY, height, i, margins, width, xy;

        if (calcWidth) {
            if (isNaN(props.contentWidth)) {
                ++needed;
            } else {
                calcWidth = undefined;
            }
        }
        if (calcHeight) {
            if (isNaN(props.contentHeight)) {
                ++needed;
            } else {
                calcHeight = undefined;
            }
        }

        if (needed) {
            
            
            
            for (i = 0; i < length; ++i) {
                childContext = childItems[i];
                child = childContext.target;
                height = calcHeight && childContext.getProp('height');
                width = calcWidth && childContext.getProp('width');
                margins = childContext.getMarginInfo();

                
                
                if ((calcWidth && isNaN(child.x)) || (calcHeight && isNaN(child.y))) {
                    xy = child.el.getXY();
                    if (!targetXY) {
                        targetXY = ownerContext.targetContext.el.getXY();
                        borders = ownerContext.targetContext.getBorderInfo();
                        targetX = targetXY[0] + borders.left;
                        targetY = targetXY[1] + borders.top;
                    }
                    
                    childX = xy[0] - targetX;
                    childY = xy[1] - targetY;
                } else {
                    
                    childX = child.x;
                    childY = child.y;
                }
                

                height += margins.bottom;
                width  += margins.right;

                contentHeight = Math.max(contentHeight, childY + height);
                contentWidth = Math.max(contentWidth, childX + width);

                if (isNaN(contentHeight) && isNaN(contentWidth)) {
                    me.done = false;
                    return;
                }
            }

            if (calcWidth || calcHeight) {
                targetPadding = ownerContext.targetContext.getPaddingInfo();
            }
            if (calcWidth && !ownerContext.setContentWidth(contentWidth + targetPadding.right)) {
                me.done = false;
            }
            if (calcHeight && !ownerContext.setContentHeight(contentHeight + targetPadding.bottom)) {
                me.done = false;
            }

            
        }
    },

    
    calculateOverflow: function (ownerContext, containerSize, dimensions) {
        var me = this,
            owner = me.owner,
            manageOverflow = me.manageOverflow,
            state = ownerContext.state,
            overflowAdjust = state.overflowAdjust,
            padWidth, padHeight, padElContext, padding, scrollRangeFlags,
            overflow, scrollbarSize, contentW, contentH, ownerW, ownerH, scrollbars,
            xauto, yauto;

        if (manageOverflow && !state.secondPass && !me.reserveScrollbar) {
            
            
            if (owner.autoScroll) {
                xauto = yauto = true;
            } else {
                if (owner.overflowX) {
                    xauto = owner.overflowX == 'auto';
                } else {
                    overflow = ownerContext.targetContext.getStyle('overflow-x');
                    xauto = overflow && overflow != 'hidden' && overflow != 'scroll';
                }

                if (owner.overflowY) {
                    yauto = owner.overflowY == 'auto';
                } else {
                    overflow = ownerContext.targetContext.getStyle('overflow-y');
                    yauto = overflow && overflow != 'hidden' && overflow != 'scroll';
                }
            }

            
            
            
            if (!containerSize.gotWidth) {
                xauto = false;
            }
            if (!containerSize.gotHeight) {
                yauto = false;
            }

            if (xauto || yauto) {
                scrollbarSize = Ext.getScrollbarSize();

                
                
                contentW = ownerContext.peek('contentWidth');
                contentH = ownerContext.peek('contentHeight');
                ownerW = containerSize.width;
                ownerH = containerSize.height;

                scrollbars = me.getScrollbarsNeeded(ownerW, ownerH, contentW, contentH);
                state.overflowState = scrollbars;

                if (typeof dimensions == 'number') {
                    scrollbars &= ~dimensions; 
                }

                overflowAdjust = {
                    width:  (xauto && (scrollbars & 2)) ? scrollbarSize.width : 0,
                    height: (yauto && (scrollbars & 1)) ? scrollbarSize.height : 0
                };

                
                
                if (overflowAdjust.width !== me.lastOverflowAdjust.width || overflowAdjust.height !== me.lastOverflowAdjust.height) {
                    me.done = false;

                    
                    
                    ownerContext.invalidate({
                        state: {
                            overflowAdjust: overflowAdjust,
                            overflowState: state.overflowState,
                            secondPass: true
                        }
                    });
                }
            }
        }

        if (!me.done) {
            return;
        }

        padElContext = ownerContext.padElContext ||
                      (ownerContext.padElContext = ownerContext.getEl('overflowPadderEl', me));

        
        
        if (padElContext) {
            scrollbars = state.overflowState; 
            padWidth = containerSize.width;
            padHeight = 0;

            if (scrollbars) {
                padding = ownerContext.targetContext.getPaddingInfo();
                scrollRangeFlags = me.scrollRangeFlags;

                if ((scrollbars & 2) && (scrollRangeFlags & 1)) { 
                    padHeight += padding.bottom;
                }

                if ((scrollbars & 1) && (scrollRangeFlags & 4)) { 
                    padWidth += padding.right;
                }
                padElContext.setProp('display', '');
                padElContext.setSize(padWidth, padHeight);
            } else {
                padElContext.setProp('display', 'none');
            }
        }
    },

    
    configureItem: function(item) {
        var me = this,
            ownerItemCls = me.owner.itemCls,
            addClasses = [].concat(me.itemCls || []);

        me.callParent(arguments);

        if (ownerItemCls) {
            addClasses = Ext.Array.push(addClasses, ownerItemCls);
        }
        item.addCls(addClasses);
    },

    doRenderBody: function (out, renderData) {
        
        

        this.renderItems(out, renderData);
        this.renderContent(out, renderData);
    },

    doRenderContainer: function (out, renderData) {
        
        

        var me = renderData.$comp.layout,
            tpl = me.getRenderTpl(),
            data = me.getRenderData();

        tpl.applyOut(data, out);
    },

    doRenderItems: function (out, renderData) {
        
        

        var me = renderData.$layout,
            tree = me.getRenderTree();

        if (tree) {
            Ext.DomHelper.generateMarkup(tree, out);
        }
    },

    
    doRenderPadder: function (out, renderData) {
        
        

        var me = renderData.$layout,
            owner = me.owner,
            scrollRangeFlags = me.getScrollRangeFlags();

        if (me.manageOverflow == 2) {
            if (scrollRangeFlags & 5) { 
                out.push('<div id="',owner.id,'-overflowPadderEl" ',
                    'style="font-size: 1px; width:1px; height: 1px;');

                
                
                
                
                
                
                

                out.push('"></div>');

                me.scrollRangeFlags = scrollRangeFlags; 
            }
        }
    }, 

    finishRender: function () {
        var me = this,
            target, items;

        me.callParent();

        me.cacheElements();

        target = me.getRenderTarget();
        items = me.getLayoutItems();

        if (me.targetCls) {
            me.getTarget().addCls(me.targetCls);
        }

        me.finishRenderItems(target, items);
    },

    
    notifyOwner: function() {
        this.owner.afterLayout(this);
    },

    
    getContainerSize : function(ownerContext, inDom) {
        
        
        
        
        

        var targetContext = ownerContext.targetContext,
            frameInfo = targetContext.getFrameInfo(),
            padding = targetContext.getPaddingInfo(),
            got = 0,
            needed = 0,
            overflowAdjust = ownerContext.state.overflowAdjust,
            gotWidth, gotHeight, width, height;

        
        
        

        
        
        

        if (!ownerContext.widthModel.shrinkWrap) {
            ++needed;
            width = inDom ? targetContext.getDomProp('width') : targetContext.getProp('width');
            gotWidth = (typeof width == 'number');
            if (gotWidth) {
                ++got;
                width -= frameInfo.width + padding.width;
                if (overflowAdjust) {
                    width -= overflowAdjust.width;
                }
            }
        }

        if (!ownerContext.heightModel.shrinkWrap) {
            ++needed;
            height = inDom ? targetContext.getDomProp('height') : targetContext.getProp('height');
            gotHeight = (typeof height == 'number');
            if (gotHeight) {
                ++got;
                height -= frameInfo.height + padding.height;
                if (overflowAdjust) {
                    height -= overflowAdjust.height;
                }
            }
        }

        return {
            width: width,
            height: height,
            needed: needed,
            got: got,
            gotAll: got == needed,
            gotWidth: gotWidth,
            gotHeight: gotHeight
        };
    },

    
    getLayoutItems: function() {
        var owner = this.owner,
            items = owner && owner.items;

        return (items && items.items) || [];
    },

    getRenderData: function () {
        var comp = this.owner;

        return {
            $comp: comp,
            $layout: this,
            ownerId: comp.id
        };
    },

    
    getRenderedItems: function() {
        var me = this,
            target = me.getRenderTarget(),
            items = me.getLayoutItems(),
            ln = items.length,
            renderedItems = [],
            i, item;

        for (i = 0; i < ln; i++) {
            item = items[i];
            if (item.rendered && me.isValidParent(item, target, i)) {
                renderedItems.push(item);
            }
        }

        return renderedItems;
    },

    
    getRenderTarget: function() {
        return this.owner.getTargetEl();
    },

    
    getElementTarget: function() {
        return this.getRenderTarget();
    },

    getRenderTpl: function () {
        var me = this,
            renderTpl = Ext.XTemplate.getTpl(this, 'renderTpl');

        
        
        if (!renderTpl.renderContent) {
            me.owner.setupRenderTpl(renderTpl);
        }

        return renderTpl;
    },

    getRenderTree: function () {
        var result,
            items = this.owner.items,
            itemsGen,
            renderCfgs = {};
        
        do {
            itemsGen = items.generation;
            result = this.getItemsRenderTree(this.getLayoutItems(), renderCfgs);
        } while (items.generation !== itemsGen);
        return result;
    },

    getScrollbarsNeeded: function (width, height, contentWidth, contentHeight) {
        var scrollbarSize = Ext.getScrollbarSize(),
            hasWidth = typeof width == 'number',
            hasHeight = typeof height == 'number',
            needHorz = 0,
            needVert = 0;

        
        if (!scrollbarSize.width) {
            return 0;
        }
        if (hasHeight && height < contentHeight) {
            needVert = 2;
            width -= scrollbarSize.width;
        }

        if (hasWidth && width < contentWidth) {
            needHorz = 1;
            if (!needVert && hasHeight) {
                height -= scrollbarSize.height;
                if (height < contentHeight) {
                    needVert = 2;
                }
            }
        }

        return needVert + needHorz;
    },

    
    getScrollRangeFlags: (function () {
        var flags = -1;

        return function () {
            if (flags < 0) {
                var div = Ext.getBody().createChild({
                        
                        cls: Ext.baseCSSPrefix + 'border-box',
                        style: {
                            width: '100px', height: '100px', padding: '10px',
                            overflow: 'auto'
                        },
                        children: [{
                            style: {
                                border: '1px solid red',
                                width: '150px', height: '150px',
                                margin: '0 5px 5px 0' 
                            }
                        }]
                    }),
                    scrollHeight = div.dom.scrollHeight,
                    scrollWidth = div.dom.scrollWidth,
                    heightFlags = {
                        
                        175: 0,
                        
                        165: 1,
                        
                        170: 2,
                        
                        160: 3
                    },
                    widthFlags = {
                        
                        175: 0,
                        
                        165: 4,
                        
                        170: 8,
                        
                        160: 12
                    };

                flags = (heightFlags[scrollHeight] || 0) | (widthFlags[scrollWidth] || 0);
                
                div.remove();
            }

            return flags;
        };
    }()),

    
    getTarget: function() {
        return this.owner.getTargetEl();
    },

    
    getVisibleItems: function() {
        var target   = this.getRenderTarget(),
            items = this.getLayoutItems(),
            ln = items.length,
            visibleItems = [],
            i, item;

        for (i = 0; i < ln; i++) {
            item = items[i];
            if (item.rendered && this.isValidParent(item, target, i) && item.hidden !== true) {
                visibleItems.push(item);
            }
        }

        return visibleItems;
    },

    setupRenderTpl: function (renderTpl) {
        var me = this;

        renderTpl.renderBody = me.doRenderBody;
        renderTpl.renderContainer = me.doRenderContainer;
        renderTpl.renderItems = me.doRenderItems;
        renderTpl.renderPadder = me.doRenderPadder;
    }
});


Ext.define('Ext.layout.container.Auto', {

    

    alias: ['layout.auto', 'layout.autocontainer'],

    extend: 'Ext.layout.container.Container',

    

    type: 'autocontainer',

    childEls: [
        'clearEl'
    ],

    renderTpl: [
        '{%this.renderBody(out,values)%}',
        
        '<div id="{ownerId}-clearEl" class="', Ext.baseCSSPrefix, 'clear" role="presentation"></div>'
    ],

    

    calculate: function(ownerContext) {
        var me = this,
            containerSize;

        if (!ownerContext.hasDomProp('containerChildrenDone')) {
            me.done = false;
        } else {
            
            containerSize = me.getContainerSize(ownerContext);
            if (!containerSize.gotAll) {
                me.done = false;
            }

            me.calculateContentSize(ownerContext);
        }
    }
});


Ext.define('Ext.container.AbstractContainer', {

    

    extend: 'Ext.Component',

    requires: [
        'Ext.util.MixedCollection',
        'Ext.layout.container.Auto',
        'Ext.ZIndexManager'
    ],

    

    renderTpl: '{%this.renderContainer(out,values)%}',

    

    

    

    

    
    suspendLayout : false,

    
    autoDestroy : true,

     
    defaultType: 'panel',
    
    
    detachOnRemove: true,

    
    isContainer : true,

    
    layoutCounter : 0,

    baseCls: Ext.baseCSSPrefix + 'container',

    
    bubbleEvents: ['add', 'remove'],

    
    initComponent : function(){
        var me = this;
        me.addEvents(
            
            'afterlayout',
            
            'beforeadd',
            
            'beforeremove',
            
            'add',
            
            'remove'
        );

        me.callParent();

        me.getLayout();
        me.initItems();
    },

    
    initItems : function() {
        var me = this,
            items = me.items;

        
        me.items = new Ext.util.AbstractMixedCollection(false, me.getComponentId);

        if (items) {
            if (!Ext.isArray(items)) {
                items = [items];
            }

            me.add(items);
        }
    },

    
    getFocusEl: function() {
        return this.getTargetEl();
    },

    finishRenderChildren: function () {
        this.callParent();

        var layout = this.getLayout();

        if (layout) {
            layout.finishRender();
        }
    },

    beforeRender: function () {
        var me = this,
            layout = me.getLayout();

        me.callParent();

        if (!layout.initialized) {
            layout.initLayout();
        }
    },
    
    setupRenderTpl: function (renderTpl) {
        var layout = this.getLayout();

        this.callParent(arguments);

        layout.setupRenderTpl(renderTpl);
    },

    
    setLayout : function(layout) {
        var currentLayout = this.layout;

        if (currentLayout && currentLayout.isLayout && currentLayout != layout) {
            currentLayout.setOwner(null);
        }

        this.layout = layout;
        layout.setOwner(this);
    },

    
    getLayout : function() {
        var me = this;
        if (!me.layout || !me.layout.isLayout) {
            
            me.setLayout(Ext.layout.Layout.create(me.layout, me.self.prototype.layout || 'autocontainer'));
        }

        return me.layout;
    },

    
    doLayout : function() {
        this.updateLayout();
        return this;
    },

    
    afterLayout : function(layout) {
        var me = this;
        ++me.layoutCounter;
        if (me.hasListeners.afterlayout) {
            me.fireEvent('afterlayout', me, layout);
        }
    },

    
    prepareItems : function(items, applyDefaults) {
        
        
        if (Ext.isArray(items)) {
            items = items.slice();
        } else {
            items = [items];
        }

        
        var me = this,
            i = 0,
            len = items.length,
            item;

        for (; i < len; i++) {
            item = items[i];
            if (item == null) {
                Ext.Array.erase(items, i, 1);
                --i;
                --len;
            } else {
                if (applyDefaults) {
                    item = this.applyDefaults(item);
                }

                
                item.isContained = me;
                items[i] = me.lookupComponent(item);
                delete item.isContained;
            }
        }

        return items;
    },

    
    applyDefaults : function(config) {
        var defaults = this.defaults;

        if (defaults) {
            if (Ext.isFunction(defaults)) {
                defaults = defaults.call(this, config);
            }

            if (Ext.isString(config)) {
                config = Ext.ComponentManager.get(config);
            }
            Ext.applyIf(config, defaults);
        }
        return config;
    },

    
    lookupComponent : function(comp) {
        return (typeof comp == 'string') ? Ext.ComponentManager.get(comp)
                                         : Ext.ComponentManager.create(comp, this.defaultType);
    },

    
    getComponentId : function(comp) {
        return comp.getItemId();
    },

    
    add : function() {
        var me = this,
            args = Ext.Array.slice(arguments),
            index = (typeof args[0] == 'number') ? args.shift() : -1,
            layout = me.getLayout(),
            addingArray, items, i, length, item, pos, ret;

        if (args.length == 1 && Ext.isArray(args[0])) {
            items = args[0];
            addingArray = true;
        } else {
            items = args;
        }

        ret = items = me.prepareItems(items, true);
        length = items.length;

        if (me.rendered) {
            Ext.suspendLayouts(); 
        }

        if (!addingArray && length == 1) { 
            ret = items[0];
        }

        
        for (i = 0; i < length; i++) {
            item = items[i];

            pos = (index < 0) ? me.items.length : (index + i);

            
            if (item.floating) {
                me.floatingItems = me.floatingItems || new Ext.util.MixedCollection();
                me.floatingItems.add(item);
                item.onAdded(me, pos);
            } else if ((!me.hasListeners.beforeadd || me.fireEvent('beforeadd', me, item, pos) !== false) && me.onBeforeAdd(item) !== false) {
                me.items.insert(pos, item);
                item.onAdded(me, pos);
                me.onAdd(item, pos);
                layout.onAdd(item, pos);

                if (me.hasListeners.add) {
                    me.fireEvent('add', me, item, pos);
                }
            }
        }

        
        me.updateLayout();
        if (me.rendered) {
            Ext.resumeLayouts(true);
        }

        return ret;
    },

    
    onAdd : Ext.emptyFn,

    
    onRemove : Ext.emptyFn,

    
    insert : function(index, comp) {
        return this.add(index, comp);
    },

    
    move : function(fromIdx, toIdx) {
        var items = this.items,
            item;
        item = items.removeAt(fromIdx);
        if (item === false) {
            return false;
        }
        items.insert(toIdx, item);
        this.doLayout();
        return item;
    },

    
    onBeforeAdd : function(item) {
        var me = this,
            border = item.border;

        
        if (item.ownerCt && item.ownerCt !== me) {
            item.ownerCt.remove(item, false);
        }

        if (me.border === false || me.border === 0) {
            
            item.border = Ext.isDefined(border) && border !== false && border !== 0;
        }
    },

    
    remove : function(comp, autoDestroy) {
        var me = this,
            c = me.getComponent(comp);

        if (c && (!me.hasListeners.beforeremove || me.fireEvent('beforeremove', me, c) !== false)) {
            me.doRemove(c, autoDestroy);
            if (me.hasListeners.remove) {
                me.fireEvent('remove', me, c);
            }

            if (!me.destroying) {
                me.doLayout();
            }
        }

        return c;
    },

    
    doRemove : function(component, autoDestroy) {
        var me = this,
            layout = me.layout,
            hasLayout = layout && me.rendered,
            destroying = autoDestroy === true || (autoDestroy !== false && me.autoDestroy);

        autoDestroy = autoDestroy === true || (autoDestroy !== false && me.autoDestroy);
        me.items.remove(component);

        
        if (hasLayout) {
            
            if (layout.running) {
                Ext.AbstractComponent.cancelLayout(component, destroying);
            }
            layout.onRemove(component, destroying);
        }

        component.onRemoved(destroying);

        me.onRemove(component, destroying);

        
        if (destroying) {
            component.destroy();
        }
        
        else {
            if (hasLayout) {
                layout.afterRemove(component);       
            }
            if (me.detachOnRemove && component.rendered) {
                Ext.getDetachedBody().appendChild(component.getEl());
            }
        }
    },

    
    removeAll : function(autoDestroy) {
        var me = this,
            removeItems = me.items.items.slice(),
            items = [],
            i = 0,
            len = removeItems.length,
            item;

        
        me.suspendLayouts();
        for (; i < len; i++) {
            item = removeItems[i];
            me.remove(item, autoDestroy);

            if (item.ownerCt !== me) {
                items.push(item);
            }
        }

        
        me.resumeLayouts(!!len);
        return items;
    },

    
    
    
    
    
    
    
    
    getRefItems : function(deep) {
        var me = this,
            items = me.items.items,
            len = items.length,
            i = 0,
            item,
            result = [];

        for (; i < len; i++) {
            item = items[i];
            result.push(item);
            if (deep && item.getRefItems) {
                result.push.apply(result, item.getRefItems(true));
            }
        }

        
        if (me.floatingItems) {
            result.push.apply(result, me.floatingItems.items);
        }

        return result;
    },

    
    cascade : function(fn, scope, origArgs){
        var me = this,
            cs = me.items ? me.items.items : [],
            len = cs.length,
            i = 0,
            c,
            args = origArgs ? origArgs.concat(me) : [me],
            componentIndex = args.length - 1;

        if (fn.apply(scope || me, args) !== false) {
            for (; i < len; i++){
                c = cs[i];
                if (c.cascade) {
                    c.cascade(fn, scope, origArgs);
                } else {
                    args[componentIndex] = c;
                    fn.apply(scope || cs, args);
                }
            }
        }
        return this;
    },

    
    isAncestor: function(possibleDescendant) {
        while (possibleDescendant) {
            if (possibleDescendant.ownerCt === this) {
                return true;
            }
            possibleDescendant = possibleDescendant.ownerCt;
        }
    },

    
    getComponent : function(comp) {
        if (Ext.isObject(comp)) {
            comp = comp.getItemId();
        }

        return this.items.get(comp);
    },

    
    query : function(selector) {
        selector = selector || '*';
        return Ext.ComponentQuery.query(selector, this);
    },
    
    
    queryBy: function(fn, scope) {
        var out = [],
            items = this.getRefItems(true),
            i = 0,
            len = items.length,
            item;
            
        for (; i < len; ++i) {
            item = items[i];
            if (fn.call(scope || item, item) !== false) {
                out.push(item);
            }
        }
        return out;
    },
    
    
    queryById: function(id){
        return this.down('#' + id);
    },

    
    child : function(selector) {
        selector = selector || '';
        return this.query('> ' + selector)[0] || null;
    },

    nextChild: function(child, selector) {
        var me = this,
            result,
            childIndex = me.items.indexOf(child);

        if (childIndex !== -1) {
            result = selector ? Ext.ComponentQuery(selector, me.items.items.slice(childIndex + 1)) : me.items.getAt(childIndex + 1);
            if (!result && me.ownerCt) {
                result = me.ownerCt.nextChild(me, selector);
            }
        }
        return result;
    },

    prevChild: function(child, selector) {
        var me = this,
            result,
            childIndex = me.items.indexOf(child);

        if (childIndex !== -1) {
            result = selector ? Ext.ComponentQuery(selector, me.items.items.slice(childIndex + 1)) : me.items.getAt(childIndex + 1);
            if (!result && me.ownerCt) {
                result = me.ownerCt.nextChild(me, selector);
            }
        }
        return result;
    },

    
    down : function(selector) {
        return this.query(selector)[0] || null;
    },

    
    
    
    enable: function() {
        this.callParent(arguments);

        var itemsToDisable = this.getChildItemsToDisable(),
            length         = itemsToDisable.length,
            item, i;

        for (i = 0; i < length; i++) {
            item = itemsToDisable[i];

            if (item.resetDisable) {
                item.enable();
            }
        }

        return this;
    },

    
    
    
    disable: function() {
        this.callParent(arguments);

        var itemsToDisable = this.getChildItemsToDisable(),
            length         = itemsToDisable.length,
            item, i;

        for (i = 0; i < length; i++) {
            item = itemsToDisable[i];

            if (item.resetDisable !== false && !item.disabled) {
                item.disable();
                item.resetDisable = true;
            }
        }

        return this;
    },
    
    
    getChildItemsToDisable: function(){
        return this.query('[isFormField],button');
    },

    
    beforeLayout: function() {
        return true;
    },

    
    beforeDestroy : function() {
        var me = this,
            items = me.items,
            c;

        if (items) {
            while ((c = items.first())) {
                me.doRemove(c, true);
            }
        }

        Ext.destroy(
            me.layout
        );
        me.callParent();
    }
});


Ext.define('Ext.container.Container', {
    extend: 'Ext.container.AbstractContainer',
    alias: 'widget.container',
    alternateClassName: 'Ext.Container',

    
    fireHierarchyEvent: function (ename) {
        this.hierarchyEventSource.fireEvent(ename, this);
    },

    
    afterHide: function() {
        this.callParent(arguments);
        this.fireHierarchyEvent('hide');
    },
    
    afterShow: function(){
        this.callParent(arguments);
        this.fireHierarchyEvent('show');
    },

    onAdded: function() {
        this.callParent(arguments);
        if (this.hierarchyEventSource.hasListeners.added) {
            this.fireHierarchyEvent('added');
        }
    },

    
    getChildByElement: function(el, deep) {
        var item,
            itemEl,
            i = 0,
            it = this.getRefItems(),
            ln = it.length;

        el = Ext.getDom(el);
        for (; i < ln; i++) {
            item = it[i];
            itemEl = item.getEl();
            if (itemEl && ((itemEl.dom === el) || itemEl.contains(el))) {
                return (deep && item.getChildByElement) ? item.getChildByElement(el, deep) : item;
            }
        }
        return null;
    }
}, function () {
    
    this.hierarchyEventSource = this.prototype.hierarchyEventSource = new Ext.util.Observable({ events: {
        hide: true,
        show: true,
        collapse: true,
        expand: true,
        added: true
    }});
});


Ext.define('Ext.container.Viewport', {
    extend: 'Ext.container.Container',
    alias: 'widget.viewport',
    requires: ['Ext.EventManager'],
    alternateClassName: 'Ext.Viewport',

    
    
    

    

    

    

    

    

    
    isViewport: true,

    ariaRole: 'application',
    
    preserveElOnDestroy: true,

    initComponent : function() {
        var me = this,
            html = document.body.parentNode,
            el;

        
        Ext.getScrollbarSize();
        
        
        me.width = me.height = undefined;

        me.callParent(arguments);
        Ext.fly(html).addCls(Ext.baseCSSPrefix + 'viewport');
        if (me.autoScroll) {
            delete me.autoScroll;
            Ext.fly(html).setStyle('overflow', 'auto');
        }
        me.el = el = Ext.getBody();
        el.setHeight = Ext.emptyFn;
        el.setWidth = Ext.emptyFn;
        el.setSize = Ext.emptyFn;
        el.dom.scroll = 'no';
        me.allowDomMove = false;
        me.renderTo = me.el;
    },
    
    onRender: function() {
        var me = this;

        me.callParent(arguments);

        
        
        me.width = Ext.Element.getViewportWidth();
        me.height = Ext.Element.getViewportHeight();
    },

    afterFirstLayout: function() {
        var me = this;

        me.callParent(arguments);
        setTimeout(function() {
            Ext.EventManager.onWindowResize(me.fireResize, me);
        }, 1);
    },

    fireResize : function(width, height){
        
        
        if (width != this.width || height != this.height) {
            this.setSize(width, height);
        }
    }
});


Ext.define('Ext.form.FieldContainer', {
    extend: 'Ext.container.Container',
    mixins: {
        labelable: 'Ext.form.Labelable',
        fieldAncestor: 'Ext.form.FieldAncestor'
    },
    requires: 'Ext.layout.component.field.FieldContainer',

    alias: 'widget.fieldcontainer',

    componentLayout: 'fieldcontainer',
    
    componentCls: Ext.baseCSSPrefix + 'form-fieldcontainer',

    
    combineLabels: false,

    
    
    labelConnector: ', ',
    

    
    combineErrors: false,

    maskOnDisable: false,

    fieldSubTpl: '{%this.renderContainer(out,values)%}',

    initComponent: function() {
        var me = this;

        
        me.initLabelable();
        me.initFieldAncestor();

        me.callParent();
    },

    beforeRender: function(){
        this.callParent(arguments);
        this.beforeLabelableRender(arguments);
    },

    
    onLabelableAdded: function(labelable) {
        var me = this;
        me.mixins.fieldAncestor.onLabelableAdded.call(this, labelable);
        me.updateLabel();
    },

    
    onLabelableRemoved: function(labelable) {
        var me = this;
        me.mixins.fieldAncestor.onLabelableRemoved.call(this, labelable);
        me.updateLabel();
    },

    initRenderTpl: function() {
        var me = this;
        if (!me.hasOwnProperty('renderTpl')) {
            me.renderTpl = me.getTpl('labelableRenderTpl');
        }
        return me.callParent();
    },

    initRenderData: function() {
        return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
    },

    
    getFieldLabel: function() {
        var label = this.fieldLabel || '';
        if (!label && this.combineLabels) {
            label = Ext.Array.map(this.query('[isFieldLabelable]'), function(field) {
                return field.getFieldLabel();
            }).join(this.labelConnector);
        }
        return label;
    },

    getSubTplData: function() {
        var ret = this.initRenderData();

        Ext.apply(ret, this.subTplData);
        return ret;
    },

    getSubTplMarkup: function() {
        var me = this,
            tpl = me.getTpl('fieldSubTpl'),
            html;

        if (!tpl.renderContent) {
            me.setupRenderTpl(tpl);
        }

        html = tpl.apply(me.getSubTplData());
        return html;
    },

    
    updateLabel: function() {
        var me = this,
            label = me.labelEl;
        if (label) {
            me.setFieldLabel(me.getFieldLabel());
        }
    },


    
    onFieldErrorChange: function(field, activeError) {
        if (this.combineErrors) {
            var me = this,
                oldError = me.getActiveError(),
                invalidFields = Ext.Array.filter(me.query('[isFormField]'), function(field) {
                    return field.hasActiveError();
                }),
                newErrors = me.getCombinedErrors(invalidFields);

            if (newErrors) {
                me.setActiveErrors(newErrors);
            } else {
                me.unsetActiveError();
            }

            if (oldError !== me.getActiveError()) {
                me.doComponentLayout();
            }
        }
    },

    
    getCombinedErrors: function(invalidFields) {
        var errors = [],
            f,
            fLen   = invalidFields.length,
            field,
            activeErrors, a, aLen,
            error, label;

        for (f = 0; f < fLen; f++) {
            field = invalidFields[f];
            activeErrors = field.getActiveErrors();
            aLen         = activeErrors.length;

            for (a = 0; a < aLen; a++) {
                error = activeErrors[a];
                label = field.getFieldLabel();

                errors.push((label ? label + ': ' : '') + error);
            }
        }

        return errors;
    },

    getTargetEl: function() {
        return this.bodyEl || this.callParent();
    }
});


Ext.define('Ext.form.FieldSet', {
    extend: 'Ext.container.Container',
    alias: 'widget.fieldset',
    uses: ['Ext.form.field.Checkbox', 'Ext.panel.Tool', 'Ext.layout.container.Anchor', 'Ext.layout.component.FieldSet'],

    

    

    

    

    
    collapsed: false,

    
    toggleOnTitleClick : true,

    

    
    baseCls: Ext.baseCSSPrefix + 'fieldset',

    
    layout: 'anchor',

    border: 1,

    componentLayout: 'fieldset',

    autoEl: 'fieldset',

    childEls: [
        'body'
    ],

    renderTpl: [
        '{%this.renderLegend(out,values);%}',
        '<div id="{id}-body" class="{baseCls}-body">',
            '{%this.renderContainer(out,values);%}',
        '</div>'
    ],

    stateEvents : [ 'collapse', 'expand' ],

    maskOnDisable: false,

    beforeDestroy: function(){
        var me = this,
            legend = me.legend;

        if (legend) {
            
            delete legend.ownerCt;
            legend.destroy();
            me.legend = null;
        }
        me.callParent();
    },

    initComponent: function() {
        var me = this,
            baseCls = me.baseCls;

        me.callParent();

        me.addEvents(

            
            "beforeexpand",

            
            "beforecollapse",

            
            "expand",

            
            "collapse"
        );

        if (me.collapsed) {
            me.addCls(baseCls + '-collapsed');
            me.collapse();
        }
        if (me.title) {
            me.addCls(baseCls + '-with-title');
        }
        if (me.title || me.checkboxToggle || me.collapsible) {
            me.addCls(baseCls + '-with-legend');
            me.legend = Ext.widget(me.createLegendCt());
        }
    },

    
    initRenderData: function() {
        var data = this.callParent();

        data.baseCls = this.baseCls;

        return data;
    },

    getState: function () {
        var state = this.callParent();

        state = this.addPropertyToState(state, 'collapsed');

        return state;
    },

    afterCollapse: Ext.emptyFn,
    afterExpand: Ext.emptyFn,

    collapsedHorizontal: function () {
        return true;
    },

    collapsedVertical: function () {
        return true;
    },

    createLegendCt: function () {
        var me = this,
            items = [],
            legend = {
                xtype: 'container',
                baseCls: me.baseCls + '-header',
                id: me.id + '-legend',
                autoEl: 'legend',
                items: items,
                ownerCt: me,
                ownerLayout: me.componentLayout
            };

        
        if (me.checkboxToggle) {
            items.push(me.createCheckboxCmp());
        } else if (me.collapsible) {
            
            items.push(me.createToggleCmp());
        }

        
        items.push(me.createTitleCmp());

        return legend;
    },

    
    createTitleCmp: function() {
        var me  = this,
            cfg = {
                xtype : 'component',
                html  : me.title,
                cls   : me.baseCls + '-header-text',
                id    : me.id + '-legendTitle'
            };

        if (me.collapsible && me.toggleOnTitleClick) {
            cfg.listeners = {
                el : {
                    scope : me,
                    click : me.toggle
                }
            };
            cfg.cls += ' ' + me.baseCls + '-header-text-collapsible';
        }

        return (me.titleCmp = Ext.widget(cfg));
    },

    

    
    createCheckboxCmp: function() {
        var me = this,
            suffix = '-checkbox';

        me.checkboxCmp = Ext.widget({
            xtype: 'checkbox',
            hideEmptyLabel: true,
            name: me.checkboxName || me.id + suffix,
            cls: me.baseCls + '-header' + suffix,
            id: me.id + '-legendChk',
            checked: !me.collapsed,
            listeners: {
                change: me.onCheckChange,
                scope: me
            }
        });
        return me.checkboxCmp;
    },

    

    
    createToggleCmp: function() {
        var me = this;
        me.toggleCmp = Ext.widget({
            xtype: 'tool',
            type: 'toggle',
            handler: me.toggle,
            id: me.id + '-legendToggle',
            scope: me
        });
        return me.toggleCmp;
    },

    doRenderLegend: function (out, renderData) {
        
        

        var me = renderData.$comp,
            legend = me.legend,
            tree;
            
        
        if (legend) {
            legend.ownerLayout.configureItem(legend);
            tree = legend.getRenderTree();
            Ext.DomHelper.generateMarkup(tree, out);
        }
    },

    finishRender: function () {
        var legend = this.legend;

        this.callParent();

        if (legend) {
            legend.finishRender();
        }
    },

    getCollapsed: function () {
        return this.collapsed ? 'top' : false;
    },

    getCollapsedDockedItems: function () {
        var legend = this.legend;

        return legend ? [ legend ] : [];
    },

    
    setTitle: function(title) {
        var me = this,
            legend = me.legend;
            
        me.title = title;
        if (me.rendered) {
            if (!me.legend) {
                me.legend = legend = Ext.widget(me.createLegendCt());
                legend.ownerLayout.configureItem(legend);
                legend.render(me.el, 0);
            }
            me.titleCmp.update(title);
        }
        return me;
    },

    getTargetEl : function() {
        return this.body || this.frameBody || this.el;
    },

    getContentTarget: function() {
        return this.body;
    },

    
    expand : function(){
        return this.setExpanded(true);
    },

    
    collapse : function() {
        return this.setExpanded(false);
    },

    
    setExpanded: function(expanded) {
        var me = this,
            checkboxCmp = me.checkboxCmp,
            operation = expanded ? 'expand' : 'collapse';

        if (!me.rendered || me.fireEvent('before' + operation, me) !== false) {
            expanded = !!expanded;

            if (checkboxCmp) {
                checkboxCmp.setValue(expanded);
            }

            if (expanded) {
                me.removeCls(me.baseCls + '-collapsed');
            } else {
                me.addCls(me.baseCls + '-collapsed');
            }
            me.collapsed = !expanded;
            if (me.rendered) {
                
                
                
                me.updateLayout({ isRoot: false });
                me.fireEvent(operation, me);
            }
        }
        return me;
    },
    
    getRefItems: function(deep) {
        var refItems = this.callParent(arguments),
            legend = this.legend;

        
        if (legend) {
            refItems.unshift(legend);
            if (deep) {
                refItems.unshift.apply(refItems, legend.getRefItems(true));
            }
        }
        return refItems;
    },

    
    toggle: function() {
        this.setExpanded(!!this.collapsed);
    },

    
    onCheckChange: function(cmp, checked) {
        this.setExpanded(checked);
    },

    setupRenderTpl: function (renderTpl) {
        this.callParent(arguments);

        renderTpl.renderLegend = this.doRenderLegend;
    }
});


Ext.define('Ext.layout.container.Anchor', {

    

    alias: 'layout.anchor',
    extend: 'Ext.layout.container.Container',
    alternateClassName: 'Ext.layout.AnchorLayout',

    

    type: 'anchor',

    manageOverflow: 2,

    renderTpl: [
        '{%this.renderBody(out,values);this.renderPadder(out,values)%}'
    ],

    

    
    defaultAnchor: '100%',

    parseAnchorRE: /^(r|right|b|bottom)$/i,

    beginLayout: function (ownerContext) {
        var me = this,
            dimensions = 0,
            anchorSpec, childContext, childItems, i, length, target;

        me.callParent(arguments);

        childItems = ownerContext.childItems; 
        length = childItems.length;

        for (i = 0; i < length; ++i) {
            childContext = childItems[i];
            anchorSpec = childContext.target.anchorSpec;

            if (anchorSpec) {
                if (childContext.widthModel.calculated && anchorSpec.right) {
                    dimensions |= 1;
                }
                if (childContext.heightModel.calculated && anchorSpec.bottom) {
                    dimensions |= 2;
                }

                if (dimensions == 3) { 
                    break;
                }
            }
        }

        ownerContext.anchorDimensions = dimensions;

        
        
        if (!Ext.supports.RightMargin && !me.rightMarginCleanerFn) {
            target = ownerContext.targetContext.el; 

            me.rightMarginCleanerFn = Ext.Element.getRightMarginFixCleaner(target);
            target.addCls(Ext.baseCSSPrefix + 'inline-children');
        }

    },

    calculate: function (ownerContext) {
        var me = this,
            containerSize = me.getContainerSize(ownerContext);

        if (ownerContext.anchorDimensions !== ownerContext.state.calculatedAnchors) {
            me.calculateAnchors(ownerContext, containerSize);
        }

        if (ownerContext.hasDomProp('containerChildrenDone')) {
            

            if (!containerSize.gotAll) {
                me.done = false;
            }

            me.calculateContentSize(ownerContext, ownerContext.anchorDimensions);

            if (me.done) {
                me.calculateOverflow(ownerContext, containerSize, ownerContext.anchorDimensions);
                return;
            }
        }

        me.done = false;
    },

    calculateAnchors: function (ownerContext, containerSize) {
        var me = this,
            childItems = ownerContext.childItems,
            length = childItems.length,
            gotHeight = containerSize.gotHeight,
            gotWidth = containerSize.gotWidth,
            ownerHeight = containerSize.height,
            ownerWidth = containerSize.width,
            state = ownerContext.state,
            calculatedAnchors = (gotWidth ? 1 : 0) | (gotHeight ? 2 : 0),
            anchorSpec, childContext, childMargins, height, i, width;

        state.calculatedAnchors = (state.calculatedAnchors || 0) | calculatedAnchors;

        for (i = 0; i < length; i++) {
            childContext = childItems[i];
            childMargins = childContext.getMarginInfo();
            anchorSpec = childContext.target.anchorSpec;

            
            
            
            
            if (gotWidth && childContext.widthModel.calculated) {
                width = anchorSpec.right(ownerWidth) - childMargins.width;
                width = me.adjustWidthAnchor(width, childContext);

                childContext.setWidth(width);
            }

            
            if (gotHeight && childContext.heightModel.calculated) {
                height = anchorSpec.bottom(ownerHeight) - childMargins.height;
                height = me.adjustHeightAnchor(height, childContext);

                childContext.setHeight(height);
            }
        }
    },

    finishedLayout: function (ownerContext) {
        var cleanerFn = this.rightMarginCleanerFn;

        if (cleanerFn) {
            delete this.rightMarginCleanerFn;
            ownerContext.targetContext.el.removeCls(Ext.baseCSSPrefix + 'inline-children');
            cleanerFn();
        }
    },


    
    anchorFactory: {
        offset: function (delta) {
            return function(v) {
                return v + delta;
            };
        },
        ratio: function (ratio) {
            return function(v) {
                return Math.floor(v * ratio);
            };
        },
        standard: function (diff) {
            return function(v) {
                return v - diff;
            };
        }
    },

    parseAnchor: function(a, start, cstart) {
        if (a && a != 'none') {
            var factory = this.anchorFactory,
                delta;

            if (this.parseAnchorRE.test(a)) {
                return factory.standard(cstart - start);
            }    
            if (a.indexOf('%') != -1) {
                return factory.ratio(parseFloat(a.replace('%', '')) * 0.01);
            }    
            delta = parseInt(a, 10);
            if (!isNaN(delta)) {
                return factory.offset(delta);
            }
        }
        return null;
    },

    
    adjustWidthAnchor: function(value, childContext) {
        return value;
    },

    
    adjustHeightAnchor: function(value, childContext) {
        return value;
    },

    configureItem: function(item) {
        var me = this,
            owner = me.owner,
            anchor= item.anchor,
            anchorsArray,
            anchorWidth,
            anchorHeight;

        me.callParent(arguments);

        if (!item.anchor && item.items && !Ext.isNumber(item.width) && !(Ext.isIE6 && Ext.isStrict)) {
            item.anchor = anchor = me.defaultAnchor;
        }

         
        if (owner.anchorSize) {
            if (typeof owner.anchorSize == 'number') {
                anchorWidth = owner.anchorSize;
            } else {
                anchorWidth = owner.anchorSize.width;
                anchorHeight = owner.anchorSize.height;
            }
        } else {
            anchorWidth = owner.initialConfig.width;
            anchorHeight = owner.initialConfig.height;
        }

        if (anchor) {
            
            anchorsArray = anchor.split(' ');
            item.anchorSpec = {
                right: me.parseAnchor(anchorsArray[0], item.initialConfig.width, anchorWidth),
                bottom: me.parseAnchor(anchorsArray[1], item.initialConfig.height, anchorHeight)
            };
        }
    },

    sizePolicy: {
        '': {
            setsWidth: 0,
            setsHeight: 0
        },
        b: {
            setsWidth: 0,
            setsHeight: 1
        },
        r: {
            '': {
                setsWidth: 1,
                setsHeight: 0
            },
            b: {
                setsWidth: 1,
                setsHeight: 1

            }
        }
    },

    getItemSizePolicy: function (item) {
        var anchorSpec = item.anchorSpec,
            key = '',
            policy = this.sizePolicy,
            sizeModel;

        if (anchorSpec) {
            sizeModel = this.owner.getSizeModel();
            if (anchorSpec.right && !sizeModel.width.shrinkWrap) {
                policy = policy.r;
            }
            if (anchorSpec.bottom && !sizeModel.height.shrinkWrap) {
                key = 'b';
            }
        }

        return policy[key];
    }
});


Ext.define('Ext.layout.container.Absolute', {

    

    alias: 'layout.absolute',
    extend: 'Ext.layout.container.Anchor',
    alternateClassName: 'Ext.layout.AbsoluteLayout',

    

    targetCls: Ext.baseCSSPrefix + 'abs-layout-ct',
    itemCls: Ext.baseCSSPrefix + 'abs-layout-item',

    
    ignoreOnContentChange: true,

    type: 'absolute',

    
    adjustWidthAnchor: function(value, childContext) {
        var padding = this.targetPadding,
            x = childContext.getStyle('left');

        return value - x + padding.left;
    },

    
    adjustHeightAnchor: function(value, childContext) {
        var padding = this.targetPadding,
            y = childContext.getStyle('top');

        return value - y + padding.top;
    },

    isItemLayoutRoot: function (item) {
        return this.ignoreOnContentChange || this.callParent(arguments);
    },

    isItemShrinkWrap: function (item) {
        return true;
    },

    beginLayout: function (ownerContext) {
        var me = this,
            target = me.getTarget();

        me.callParent(arguments);

        
        if (target.dom !== document.body) {
            target.position();
        }

        me.targetPadding = ownerContext.targetContext.getPaddingInfo();
    },

    isItemBoxParent: function (itemContext) {
        return true;
    },

    onContentChange: function () {
        if (this.ignoreOnContentChange) {
            return false;
        }
        return this.callParent(arguments);
    }
});


Ext.define('Ext.layout.container.CheckboxGroup', {
    extend: 'Ext.layout.container.Container',
    alias: ['layout.checkboxgroup'],

    
    autoFlex: true,

    type: 'checkboxgroup',

    childEls: [
        'innerCt'
    ],

    renderTpl: [
        '<table id="{ownerId}-innerCt" role="presentation" style="{tableStyle}"><tbody><tr>',
            '<tpl for="columns">',
                '<td class="{parent.colCls}" valign="top" style="{style}">',
                    '{% this.renderColumn(out,parent,xindex-1) %}',
                '</td>',
            '</tpl>',
        '</tr></tbody></table>'
    ],

    lastOwnerItemsGeneration : null,

    beginLayout: function(ownerContext) {
        var me = this,
            columns,
            numCols,
            i, width, cwidth,
            totalFlex = 0, flexedCols = 0,
            autoFlex = me.autoFlex,
            innerCtStyle = me.innerCt.dom.style;

        me.callParent(arguments);

        columns = me.columnNodes;
        ownerContext.innerCtContext = ownerContext.getEl('innerCt', me);

        
        if (!ownerContext.widthModel.shrinkWrap) {
            numCols = columns.length;

            
            if (me.columnsArray) {

                
                for (i = 0; i < numCols; i++) {
                    width = me.owner.columns[i];
                    if (width < 1) {
                        totalFlex += width;
                        flexedCols++;
                    }
                }

                
                for (i = 0; i < numCols; i++) {
                    width = me.owner.columns[i];
                    if (width < 1) {
                        cwidth = ((width / totalFlex) * 100) + '%';
                    } else {
                        cwidth = width + 'px';
                    }
                    columns[i].style.width = cwidth;
                }
            }

            
            else {
                for (i = 0; i < numCols; i++) {
                    
                    
                    
                    cwidth = autoFlex
                        ? (1 / numCols * 100) + '%'
                        : '';
                    columns[i].style.width = cwidth;
                    flexedCols++;
                }
            }

            
            if (!flexedCols) {
                innerCtStyle.tableLayout = 'fixed';
                innerCtStyle.width = '';
            
            } else if (flexedCols < numCols) {
                innerCtStyle.tableLayout = 'fixed';
                innerCtStyle.width = '100%';
            
            } else {
                innerCtStyle.tableLayout = 'auto';
                
                if (autoFlex) {
                    innerCtStyle.width = '100%';
                } else {
                    innerCtStyle.width = '';
                }
            }

        } else {
            innerCtStyle.tableLayout = 'auto';
            innerCtStyle.width = '';
        }
    },

    cacheElements: function () {
        var me = this;

        
        me.callParent();

        me.rowEl = me.innerCt.down('tr');

        
        me.columnNodes = me.rowEl.dom.childNodes;
    },

    
    calculate: function(ownerContext) {
        var me = this,
            targetContext, widthShrinkWrap, heightShrinkWrap, shrinkWrap, table, targetPadding;

        
        
        if (!ownerContext.getDomProp('containerChildrenDone')) {
            me.done = false;
        } else {
            targetContext = ownerContext.innerCtContext;
            widthShrinkWrap = ownerContext.widthModel.shrinkWrap;
            heightShrinkWrap = ownerContext.heightModel.shrinkWrap;
            shrinkWrap = heightShrinkWrap || widthShrinkWrap;
            table = targetContext.el.dom;
            targetPadding = shrinkWrap && targetContext.getPaddingInfo();

            if (widthShrinkWrap) {
                ownerContext.setContentWidth(table.offsetWidth + targetPadding.width, true);
            }

            if (heightShrinkWrap) {
                ownerContext.setContentHeight(table.offsetHeight + targetPadding.height, true);
            }
        }
    },

    doRenderColumn: function (out, renderData, columnIndex) {
        
        

        var me = renderData.$layout,
            owner = me.owner,
            columnCount = renderData.columnCount,
            items = owner.items.items,
            itemCount = items.length,
            item, itemIndex, rowCount, increment, tree;

        
        
        

        if (owner.vertical) {
            
            
            
            
            
            
            
            
            
            

            rowCount = Math.ceil(itemCount / columnCount); 
            itemIndex = columnIndex * rowCount;
            itemCount = Math.min(itemCount, itemIndex + rowCount);
            increment = 1;
        } else {
            
            
            
            
            
            
            
            
            
            

            itemIndex = columnIndex;
            increment = columnCount;
        }

        for ( ; itemIndex < itemCount; itemIndex += increment) {
            item = items[itemIndex];
            me.configureItem(item);
            tree = item.getRenderTree();
            Ext.DomHelper.generateMarkup(tree, out);
        }
    },

    
    getColumnCount: function() {
        var me = this,
            owner = me.owner,
            ownerColumns = owner.columns;

        
        
        if (me.columnsArray) {
            return ownerColumns.length;
        }

        if (Ext.isNumber(ownerColumns)) {
            return ownerColumns;
        }
        return owner.items.length;
    },

    getItemSizePolicy: function (item) {
        return this.autoSizePolicy;
    },

    getRenderData: function () {
        var me = this,
            data = me.callParent(),
            owner = me.owner,
            i, columns = me.getColumnCount(),
            width, column, cwidth,
            autoFlex = me.autoFlex,
            totalFlex = 0, flexedCols = 0;

        
        if (me.columnsArray) {
            for (i=0; i < columns; i++) {
                width = me.owner.columns[i];
                if (width < 1) {
                    totalFlex += width;
                    flexedCols++;
                }
            }
        }

        data.colCls = owner.groupCls;
        data.columnCount = columns;

        data.columns = [];
        for (i = 0; i < columns; i++) {
            column = (data.columns[i] = {});

            if (me.columnsArray) {
                width = me.owner.columns[i];
                if (width < 1) {
                    cwidth = ((width / totalFlex) * 100) + '%';
                } else {
                    cwidth = width + 'px';
                }
                column.style = 'width:' + cwidth;
            } else {
                column.style = 'width:' + (1 / columns * 100) + '%';
                flexedCols++;
            }
        }

        
        data.tableStyle =
            !flexedCols ? 'table-layout:fixed;' :
            (flexedCols < columns) ? 'table-layout:fixed;width:100%' :
            (autoFlex) ? 'table-layout:auto;width:100%' : 'table-layout:auto;';

        return data;
    },

    initLayout: function () {
        var me = this,
            owner = me.owner;

        me.columnsArray = Ext.isArray(owner.columns);
        me.autoColumns = !owner.columns || owner.columns === 'auto';
        me.vertical = owner.vertical;

        me.callParent();
    },

    
    isValidParent: function() {
        return true;
    },

    setupRenderTpl: function (renderTpl) {
        this.callParent(arguments);

        renderTpl.renderColumn = this.doRenderColumn;
    },

    renderChildren: function () {
        var me = this,
            generation = me.owner.items.generation;

        if (me.lastOwnerItemsGeneration !== generation) {
            me.lastOwnerItemsGeneration = generation;
            me.renderItems(me.getLayoutItems());
        }
    },

    
    renderItems : function(items) {
        var me = this,
            itemCount = items.length,
            i,
            item,
            rowCount,
            columnCount,
            rowIndex,
            columnIndex;

        if (itemCount) {
            Ext.suspendLayouts();

            if (me.autoColumns) {
                me.addMissingColumns(itemCount);
            }

            columnCount = me.columnNodes.length;
            rowCount = Math.ceil(itemCount / columnCount);

            for (i = 0; i < itemCount; i++) {
                item = items[i];
                rowIndex = me.getRenderRowIndex(i, rowCount, columnCount);
                columnIndex = me.getRenderColumnIndex(i, rowCount, columnCount);

                if (!item.rendered) {
                    me.renderItem(item, rowIndex, columnIndex);
                } else if (!me.isItemAtPosition(item, rowIndex, columnIndex)) {
                    me.moveItem(item, rowIndex, columnIndex);
                }
            }

            if (me.autoColumns) {
                me.removeExceedingColumns(itemCount);
            }

            Ext.resumeLayouts(true);
        }
    },

    isItemAtPosition : function(item, rowIndex, columnIndex) {
        return item.el.dom === this.getNodeAt(rowIndex, columnIndex);
    },

    getRenderColumnIndex : function(itemIndex, rowCount, columnCount) {
        if (this.vertical) {
            return Math.floor(itemIndex / rowCount);
        } else {
            return itemIndex % columnCount;
        }
    },

    getRenderRowIndex : function(itemIndex, rowCount, columnCount) {
        var me = this;
        if (me.vertical) {
            return itemIndex % rowCount;
        } else {
            return Math.floor(itemIndex / columnCount);
        }
    },

    getNodeAt : function(rowIndex, columnIndex) {
        return this.columnNodes[columnIndex].childNodes[rowIndex];
    },

    addMissingColumns : function(itemsCount) {
        var me = this,
            existingColumnsCount = me.columnNodes.length,
            missingColumnsCount,
            row,
            cls,
            i;
        if (existingColumnsCount < itemsCount) {
            missingColumnsCount = itemsCount - existingColumnsCount;
            row = me.rowEl;
            cls = me.owner.groupCls;
            for (i = 0; i < missingColumnsCount; i++) {
                row.createChild({
                    cls: cls,
                    tag: 'td',
                    vAlign: 'top'
                });
            }
        }
    },

    removeExceedingColumns : function(itemsCount) {
        var me = this,
            existingColumnsCount = me.columnNodes.length,
            exceedingColumnsCount,
            row,
            i;
        if (existingColumnsCount > itemsCount) {
            exceedingColumnsCount = existingColumnsCount - itemsCount;
            row = me.rowEl;
            for (i = 0; i < exceedingColumnsCount; i++) {
                row.last().remove();
            }
        }
    },

    
    renderItem : function(item, rowIndex, columnIndex) {
        var me = this;

        me.configureItem(item);
        item.render(Ext.get(me.columnNodes[columnIndex]), rowIndex);
        me.afterRenderItem(item);
    },

    
    moveItem : function(item, rowIndex, columnIndex) {
        var me = this,
            column = me.columnNodes[columnIndex],
            targetNode = column.childNodes[rowIndex];
        column.insertBefore(item.el.dom, targetNode || null);
    }

});

Ext.define('Ext.form.CheckboxGroup', {
    extend:'Ext.form.FieldContainer',
    mixins: {
        field: 'Ext.form.field.Field'
    },
    alias: 'widget.checkboxgroup',
    requires: ['Ext.layout.container.CheckboxGroup', 'Ext.form.field.Base'],

    

    

    
    columns : 'auto',

    
    vertical : false,

    
    allowBlank : true,

    
    
    blankText : "You must select at least one item in this group",
    

    
    defaultType : 'checkboxfield',

    
    groupCls : Ext.baseCSSPrefix + 'form-check-group',

    
    fieldBodyCls: Ext.baseCSSPrefix + 'form-checkboxgroup-body',

    
    layout: 'checkboxgroup',

    initComponent: function() {
        var me = this;
        me.callParent();
        me.initField();
    },

    
    initValue: function() {
        var me = this,
            valueCfg = me.value;
        me.originalValue = me.lastValue = valueCfg || me.getValue();
        if (valueCfg) {
            me.setValue(valueCfg);
        }
    },

    
    onFieldAdded: function(field) {
        var me = this;
        if (field.isCheckbox) {
            me.mon(field, 'change', me.checkChange, me);
        }
        me.callParent(arguments);
    },

    onFieldRemoved: function(field) {
        var me = this;
        if (field.isCheckbox) {
            me.mun(field, 'change', me.checkChange, me);
        }
        me.callParent(arguments);
    },

    
    isEqual: function(value1, value2) {
        var toQueryString = Ext.Object.toQueryString;
        return toQueryString(value1) === toQueryString(value2);
    },

    
    getErrors: function() {
        var errors = [];
        if (!this.allowBlank && Ext.isEmpty(this.getChecked())) {
            errors.push(this.blankText);
        }
        return errors;
    },

    
    getBoxes: function(query) {
        return this.query('[isCheckbox]' + (query||''));
    },

    
    eachBox: function(fn, scope) {
        Ext.Array.forEach(this.getBoxes(), fn, scope || this);
    },

    
    getChecked: function() {
        return this.getBoxes('[checked]');
    },

    
    isDirty: function(){
        var boxes = this.getBoxes(),
            b ,
            bLen  = boxes.length;

        for (b = 0; b < bLen; b++) {
            if (boxes[b].isDirty()) {
                return true;
            }
        }
    },

    
    setReadOnly: function(readOnly) {
        var boxes = this.getBoxes(),
            b,
            bLen  = boxes.length;

        for (b = 0; b < bLen; b++) {
            boxes[b].setReadOnly(readOnly);
        }

        this.readOnly = readOnly;
    },

    
    reset: function() {
        var me = this,
            hadError = me.hasActiveError(),
            preventMark = me.preventMark;
        me.preventMark = true;
        me.batchChanges(function() {
            var boxes = me.getBoxes(),
                b,
                bLen  = boxes.length;

            for (b = 0; b < bLen; b++) {
                boxes[b].reset();
            }
        });
        me.preventMark = preventMark;
        me.unsetActiveError();
        if (hadError) {
            me.updateLayout();
        }
    },

    resetOriginalValue: function(){
        var me    = this,
            boxes = me.getBoxes(),
            b,
            bLen  = boxes.length;

        for (b = 0; b < bLen; b++) {
            boxes[b].resetOriginalValue();
        }

        me.originalValue = me.getValue();
        me.checkDirty();
    },


    
    setValue: function(value) {
        var me    = this,
            boxes = me.getBoxes(),
            b,
            bLen  = boxes.length,
            box, name,
            cbValue;

        me.batchChanges(function() {
            for (b = 0; b < bLen; b++) {
                box = boxes[b];
                name = box.getName();
                cbValue = false;

                if (value && value.hasOwnProperty(name)) {
                    if (Ext.isArray(value[name])) {
                        cbValue = Ext.Array.contains(value[name], box.inputValue);
                    } else {
                        
                        cbValue = value[name];
                    }
                }

                box.setValue(cbValue);
            }
        });
        return me;
    },


    
    getValue: function() {
        var values = {},
            boxes  = this.getBoxes(),
            b,
            bLen   = boxes.length,
            box, name, inputValue, bucket;

        for (b = 0; b < bLen; b++) {
            box        = boxes[b];
            name       = box.getName();
            inputValue = box.inputValue;

            if (box.getValue()) {
                if (values.hasOwnProperty(name)) {
                    bucket = values[name];
                    if (!Ext.isArray(bucket)) {
                        bucket = values[name] = [bucket];
                    }
                    bucket.push(inputValue);
                } else {
                    values[name] = inputValue;
                }
            }
        }

        return values;
    },

    
    getSubmitData: function() {
        return null;
    },

    
    getModelData: function() {
        return null;
    },

    validate: function() {
        var me = this,
            errors,
            isValid,
            wasValid;

        if (me.disabled) {
            isValid = true;
        } else {
            errors = me.getErrors();
            isValid = Ext.isEmpty(errors);
            wasValid = !me.hasActiveError();
            if (isValid) {
                me.unsetActiveError();
            } else {
                me.setActiveError(errors);
            }
        }
        if (isValid !== wasValid) {
            me.fireEvent('validitychange', me, isValid);
            me.updateLayout();
        }

        return isValid;
    }

}, function() {

    this.borrow(Ext.form.field.Base, ['markInvalid', 'clearInvalid']);

});



Ext.define('Ext.form.RadioGroup', {
    extend: 'Ext.form.CheckboxGroup',
    alias: 'widget.radiogroup',

    
    
    allowBlank : true,
    
    
    blankText : 'You must select one item in this group',
    

    
    defaultType : 'radiofield',

    
    groupCls : Ext.baseCSSPrefix + 'form-radio-group',

    getBoxes: function(query) {
        return this.query('[isRadio]' + (query||''));
    },
    
    checkChange: function() {
        var value = this.getValue(),
            key = Ext.Object.getKeys(value)[0];
            
        
        
        if (Ext.isArray(value[key])) {
            return;
        }
        this.callParent(arguments);    
    },

    
    setValue: function(value) {
        var cbValue, first, formId, radios,
            i, len, name;

        if (Ext.isObject(value)) {
            for (name in value) {
                if (value.hasOwnProperty(name)) {
                    cbValue = value[name];
                    first = this.items.first();
                    formId = first ? first.getFormId() : null;
                    radios = Ext.form.RadioManager.getWithValue(name, cbValue, formId).items;
                    len = radios.length;

                    for (i = 0; i < len; ++i) {
                        radios[i].setValue(true);
                    }
                }
            }
        }
        return this;
    }
});


Ext.define('Ext.layout.container.Column', {

    extend: 'Ext.layout.container.Container',
    alias: ['layout.column'],
    alternateClassName: 'Ext.layout.ColumnLayout',

    type: 'column',

    itemCls: Ext.baseCSSPrefix + 'column',

    targetCls: Ext.baseCSSPrefix + 'column-layout-ct',

    
    columnWidthSizePolicy: {
        setsWidth: 1,
        setsHeight: 0
    },

    childEls: [
        'innerCt'
    ],

    manageOverflow: 2,

    renderTpl: [
        '<div id="{ownerId}-innerCt" class="',Ext.baseCSSPrefix,'column-inner">',
            '{%this.renderBody(out,values)%}',
            '<div class="',Ext.baseCSSPrefix,'clear"></div>',
        '</div>',
        '{%this.renderPadder(out,values)%}'
    ],

    getItemSizePolicy: function (item) {
        if (item.columnWidth) {
            return this.columnWidthSizePolicy;
        }
        return this.autoSizePolicy;
    },

    beginLayout: function() {
        this.callParent(arguments);
        this.innerCt.dom.style.width = '';
    },

    calculate: function (ownerContext) {
        var me = this,
            containerSize = me.getContainerSize(ownerContext),
            state = ownerContext.state;

        if (state.calculatedColumns || (state.calculatedColumns = me.calculateColumns(ownerContext))) {
            if (me.calculateHeights(ownerContext)) {
                me.calculateOverflow(ownerContext, containerSize);
                return;
            }
        }

        me.done = false;
    },

    calculateColumns: function (ownerContext) {
        var me = this,
            containerSize = me.getContainerSize(ownerContext),
            innerCtContext = ownerContext.getEl('innerCt', me),
            items = ownerContext.childItems,
            len = items.length,
            contentWidth = 0,
            blocked, availableWidth, i, itemContext, itemMarginWidth, itemWidth;

        
        
        
        if (!ownerContext.heightModel.shrinkWrap && !ownerContext.targetContext.hasProp('height')) {
            return false;
        }

        
        if (!containerSize.gotWidth) { 
            ownerContext.targetContext.block(me, 'width');
            blocked = true;
        } else {
            availableWidth = containerSize.width;

            innerCtContext.setWidth(availableWidth);
        }

        
        
        for (i = 0; i < len; ++i) {
            itemContext = items[i];

            
            
            
            itemMarginWidth = itemContext.getMarginInfo().width;

            if (!itemContext.widthModel.calculated) {
                itemWidth = itemContext.getProp('width');
                if (typeof itemWidth != 'number') {
                    itemContext.block(me, 'width');
                    blocked = true;
                }

                contentWidth += itemWidth + itemMarginWidth;
            }
        }

        if (!blocked) {
            availableWidth = (availableWidth < contentWidth) ? 0 : availableWidth - contentWidth;

            for (i = 0; i < len; ++i) {
                itemContext = items[i];
                if (itemContext.widthModel.calculated) {
                    itemMarginWidth = itemContext.marginInfo.width; 
                    itemWidth = itemContext.target.columnWidth;
                    itemWidth = Math.floor(itemWidth * availableWidth) - itemMarginWidth;
                    itemWidth = itemContext.setWidth(itemWidth); 
                    contentWidth += itemWidth + itemMarginWidth;
                }
            }

            ownerContext.setContentWidth(contentWidth);
        }

        
        return !blocked;
    },

    calculateHeights: function (ownerContext) {
        var me = this,
            items = ownerContext.childItems,
            len = items.length,
            blocked, i, itemContext;

        
        
        blocked = false;
        for (i = 0; i < len; ++i) {
            itemContext = items[i];

            if (!itemContext.hasDomProp('height')) {
                itemContext.domBlock(me, 'height');
                blocked = true;
            }
        }

        if (!blocked) {
            ownerContext.setContentHeight(me.innerCt.getHeight() + ownerContext.targetContext.getPaddingInfo().height);
        }

        return !blocked;
    },

    finishedLayout: function (ownerContext) {
        var bc = ownerContext.bodyContext;

        
        if (bc && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks)) {
            
            bc.el.repaint();
        }

        this.callParent(arguments);
    },

    getRenderTarget : function() {
        return this.innerCt;
    }
});


Ext.define('Ext.layout.container.Editor', {

    

    alias: 'layout.editor',

    extend: 'Ext.layout.container.Container',

    

    autoSizeDefault: {
        width: 'field',
        height: 'field'    
    },

    getItemSizePolicy: function (item) {
        var me = this,
            autoSize = me.owner.autoSize;

        return me.sizePolicy || (me.sizePolicy = {
            setsWidth:  autoSize && autoSize.width  === 'boundEl' ? 1 : 0,
            setsHeight: autoSize && autoSize.height === 'boundEl' ? 1 : 0
        });
    },

    calculate: function(ownerContext) {
        var me = this,
            owner = me.owner,
            autoSize = owner.autoSize,
            fieldWidth,
            fieldHeight;
            
        if (autoSize === true) {
            autoSize = me.autoSizeDefault;
        }

        
        if (autoSize) {
            fieldWidth  = me.getDimension(owner, autoSize.width,  'getWidth',  owner.width);
            fieldHeight = me.getDimension(owner, autoSize.height, 'getHeight', owner.height);
        }

        
        ownerContext.childItems[0].setSize(fieldWidth, fieldHeight);

        
        ownerContext.setWidth(fieldWidth);
        ownerContext.setHeight(fieldHeight);

        
        ownerContext.setContentSize(fieldWidth || owner.field.getWidth(),
                                    fieldHeight || owner.field.getHeight());
    },

    getDimension: function(owner, type, getMethod, ownerSize){
        switch (type) {
            
            case 'boundEl':
                return owner.boundEl[getMethod]();

            
            case 'field':
                return undefined;

            
            default:
                return ownerSize;
        }
    }
});

Ext.define('Ext.Editor', {

    

    extend: 'Ext.container.Container',

    alias: 'widget.editor',

    requires: ['Ext.layout.container.Editor'],

    

   layout: 'editor',

    

    
    allowBlur: true,

    

    
    revertInvalid: true,

    

    

    
    value : '',

    
    alignment: 'c-c?',

    
    offsets: [0, 0],

    
    shadow : 'frame',

    
    constrain : false,

    
    swallowKeys : true,

    
    completeOnEnter : true,

    
    cancelOnEsc : true,

    
    updateEl : false,

    

    
    hidden: true,
    baseCls: Ext.baseCSSPrefix + 'editor',

    initComponent : function() {
        var me = this,
            field = me.field = Ext.ComponentManager.create(me.field, 'textfield');

        Ext.apply(field, {
            inEditor: true,
            msgTarget: field.msgTarget == 'title' ? 'title' :  'qtip'
        });
        me.mon(field, {
            scope: me,
            blur: {
                fn: me.onFieldBlur,
                
                delay: 1
            },
            specialkey: me.onSpecialKey
        });

        if (field.grow) {
            me.mon(field, 'autosize', me.onFieldAutosize,  me, {delay: 1});
        }
        me.floating = {
            constrain: me.constrain
        };
        me.items = field;

        me.callParent(arguments);

        me.addEvents(
            
            'beforestartedit',

            
            'startedit',

            
            'beforecomplete',
            
            'complete',
            
            'canceledit',
            
            'specialkey'
        );
    },

    
    onFieldAutosize: function(){
        this.updateLayout();
    },

    
    afterRender : function(ct, position) {
        var me = this,
            field = me.field,
            inputEl = field.inputEl;

        me.callParent(arguments);

        
        if (inputEl) {
            inputEl.dom.name = '';
            if (me.swallowKeys) {
                inputEl.swallowEvent([
                    'keypress', 
                    'keydown'   
                ]);
            }
        }
    },

    
    onSpecialKey : function(field, event) {
        var me = this,
            key = event.getKey(),
            complete = me.completeOnEnter && key == event.ENTER,
            cancel = me.cancelOnEsc && key == event.ESC;

        if (complete || cancel) {
            event.stopEvent();
            
            
            Ext.defer(function() {
                if (complete) {
                    me.completeEdit();
                } else {
                    me.cancelEdit();
                }
                if (field.triggerBlur) {
                    field.triggerBlur(event);
                }
            }, 10);
        }

        me.fireEvent('specialkey', me, field, event);
    },

    
    startEdit : function(el, value) {
        var me = this,
            field = me.field;

        me.completeEdit();
        me.boundEl = Ext.get(el);
        value = Ext.isDefined(value) ? value : Ext.String.trim(me.boundEl.dom.innerText || me.boundEl.dom.innerHTML);

        if (!me.rendered) {
            me.render(me.parentEl || document.body);
        }

        if (me.fireEvent('beforestartedit', me, me.boundEl, value) !== false) {
            me.startValue = value;
            me.show();
            
            field.suspendEvents();
            field.reset();
            field.setValue(value);
            field.resumeEvents();
            me.realign(true);
            field.focus(false, 10);
            if (field.autoSize) {
                field.autoSize();
            }
            me.editing = true;
        }
    },

    
    realign : function(autoSize) {
        var me = this;
        if (autoSize === true) {
            me.updateLayout();
        }
        me.alignTo(me.boundEl, me.alignment, me.offsets);
    },

    
    completeEdit : function(remainVisible) {
        var me = this,
            field = me.field,
            value;

        if (!me.editing) {
            return;
        }

        
        if (field.assertValue) {
            field.assertValue();
        }

        value = me.getValue();
        if (!field.isValid()) {
            if (me.revertInvalid !== false) {
                me.cancelEdit(remainVisible);
            }
            return;
        }

        if (String(value) === String(me.startValue) && me.ignoreNoChange) {
            me.hideEdit(remainVisible);
            return;
        }

        if (me.fireEvent('beforecomplete', me, value, me.startValue) !== false) {
            
            value = me.getValue();
            if (me.updateEl && me.boundEl) {
                me.boundEl.update(value);
            }
            me.hideEdit(remainVisible);
            me.fireEvent('complete', me, value, me.startValue);
        }
    },

    
    onShow : function() {
        var me = this;

        me.callParent(arguments);
        if (me.hideEl !== false) {
            me.boundEl.hide();
        }
        me.fireEvent('startedit', me, me.boundEl, me.startValue);
    },

    
    cancelEdit : function(remainVisible) {
        var me = this,
            startValue = me.startValue,
            field = me.field,
            value;

        if (me.editing) {
            value = me.getValue();
            
            field.suspendEvents();
            me.setValue(startValue);
            field.resumeEvents();
            me.hideEdit(remainVisible);
            me.fireEvent('canceledit', me, value, startValue);
        }
    },

    
    hideEdit: function(remainVisible) {
        if (remainVisible !== true) {
            this.editing = false;
            this.hide();
        }
    },

    
    onFieldBlur : function(field, e) {
        var me = this,
            target;

        
        if(me.allowBlur === true && me.editing && me.selectSameEditor !== true) {
            me.completeEdit();
        }

        
        if (e && Ext.fly(target = e.getTarget()).focusable()) {
            target.focus();
        }
    },

    
    onHide : function() {
        var me = this,
            field = me.field;

        if (me.editing) {
            me.completeEdit();
            return;
        }
        if (field.hasFocus) {
            field.blur();
        }
        if (field.collapse) {
            field.collapse();
        }

        
        if (me.hideEl !== false) {
            me.boundEl.show();
        }
        me.callParent(arguments);
    },

    
    setValue : function(value) {
        this.field.setValue(value);
    },

    
    getValue : function() {
        return this.field.getValue();
    },

    beforeDestroy : function() {
        var me = this;

        Ext.destroy(me.field);
        delete me.field;
        delete me.parentEl;
        delete me.boundEl;

        me.callParent(arguments);
    }
});


Ext.define('Ext.grid.CellEditor', {
    extend: 'Ext.Editor',
    constructor: function(config) {
        config = Ext.apply({}, config);
        
        if (config.field) {
            config.field.monitorTab = false;
        }
        this.callParent([config]);
    },
    
    
    onShow: function() {
        var me = this,
            innerCell = me.boundEl.first(),
            lastChild,
            textNode;

        if (innerCell) {
            lastChild = innerCell.dom.lastChild;
            if(lastChild && lastChild.nodeType === 3) {
                
                textNode = me.cellTextNode = innerCell.dom.lastChild;
                
                me.cellTextValue = textNode.nodeValue;
                
                
                textNode.nodeValue = '\u00a0';
            }
        }
        me.callParent(arguments);
    },

    
    onHide: function() {
        var me = this,
            innerCell = me.boundEl.first();

        if (innerCell && me.cellTextNode) {
            me.cellTextNode.nodeValue = me.cellTextValue;
            delete me.cellTextNode;
            delete me.cellTextValue;
        }
        me.callParent(arguments);
    },

    
    afterRender: function() {
        var me = this,
            field = me.field;

        me.callParent(arguments);
        if (field.isXType('checkboxfield')) {
            field.mon(field.inputEl, {
                mousedown: me.onCheckBoxMouseDown,
                click: me.onCheckBoxClick,
                scope: me
            });
        }
    },
    
    
    onCheckBoxMouseDown: function() {
        this.completeEdit = Ext.emptyFn;
    },
    
    
    onCheckBoxClick: function() {
        delete this.completeEdit;
        this.field.focus(false, 10);
    },
    
    
    realign: function(autoSize) {
        var me = this,
            boundEl = me.boundEl,
            innerCell = boundEl.first(),
            children = innerCell.dom.childNodes,
            childCount = children.length,
            offsets = Ext.Array.clone(me.offsets),
            inputEl = me.field.inputEl,
            lastChild, leftBound, rightBound, width;

        
        
        
        
        
        if(me.isForTree && (childCount > 1 || (childCount === 1 && children[0].nodeType !== 3))) {
            
            lastChild = innerCell.last();
            
            leftBound = lastChild.getOffsetsTo(innerCell)[0] + lastChild.getWidth();
            
            
            
            rightBound = innerCell.getWidth();
            
            
            width = rightBound - leftBound;
            
            
            if(!me.editingPlugin.grid.columnLines) {
                width --;
            }
            
            offsets[0] += leftBound;

            me.addCls(Ext.baseCSSPrefix + 'grid-editor-on-text-node');
        } else {
            width = boundEl.getWidth() - 1;
        }

        if (autoSize === true) {
            me.field.setWidth(width);
        }

        me.alignTo(boundEl, me.alignment, offsets);
    },
    
    onEditorTab: function(e){
        var field = this.field;
        if (field.onEditorTab) {
            field.onEditorTab(e);
        }
    },

    alignment: "tl-tl",
    hideEl : false,
    cls: Ext.baseCSSPrefix + "small-editor " + Ext.baseCSSPrefix + "grid-editor",
    shim: false,
    shadow: false
});

Ext.define('Ext.layout.container.Fit', {

    
    extend: 'Ext.layout.container.Container',
    alternateClassName: 'Ext.layout.FitLayout',

    alias: 'layout.fit',

    

    itemCls: Ext.baseCSSPrefix + 'fit-item',
    targetCls: Ext.baseCSSPrefix + 'layout-fit',
    type: 'fit',
   
    
    defaultMargins: {
        top: 0,
        right: 0,
        bottom: 0,
        left: 0
    },

    manageMargins: true,

    sizePolicies: {
        0: { setsWidth: 0, setsHeight: 0 },
        1: { setsWidth: 1, setsHeight: 0 },
        2: { setsWidth: 0, setsHeight: 1 },
        3: { setsWidth: 1, setsHeight: 1 }
    },

    getItemSizePolicy: function (item, ownerSizeModel) {
        
        var sizeModel = ownerSizeModel || this.owner.getSizeModel(),
            mode = (sizeModel.width.shrinkWrap ? 0 : 1) |
                   (sizeModel.height.shrinkWrap ? 0 : 2);

       return this.sizePolicies[mode];
    },

    beginLayoutCycle: function (ownerContext, firstCycle) {
        var me = this,
            
            resetHeight = me.lastHeightModel && me.lastHeightModel.calculated,
            resetWidth = me.lastWidthModel && me.lastWidthModel.calculated,
            resetSizes = resetWidth || resetHeight,
            maxChildMinHeight = 0, maxChildMinWidth = 0,
            c, childItems, i, item, length, margins, minHeight, minWidth, style, undef;

        me.callParent(arguments);

        
        
        
        
        if (resetSizes && ownerContext.targetContext.el.dom.tagName.toUpperCase() != 'TD') {
            resetSizes = resetWidth = resetHeight = false;
        }

        childItems = ownerContext.childItems;
        length = childItems.length;

        for (i = 0; i < length; ++i) {
            item = childItems[i];

            
            
            
            if (firstCycle) {
                c = item.target;
                minHeight = c.minHeight;
                minWidth = c.minWidth;

                if (minWidth || minHeight) {
                    margins = item.marginInfo || item.getMarginInfo();
                    
                    
                    minHeight += margins.height;
                    minWidth += margins.height;

                    
                    
                    if (maxChildMinHeight < minHeight) {
                        maxChildMinHeight = minHeight;
                    }
                    if (maxChildMinWidth < minWidth) {
                        maxChildMinWidth = minWidth;
                    }
                }
            }

            if (resetSizes) {
                style = item.el.dom.style;

                if (resetHeight) {
                    style.height = '';
                }
                if (resetWidth) {
                    style.width = '';
                }
            }
        }

        if (firstCycle) {
            ownerContext.maxChildMinHeight = maxChildMinHeight;
            ownerContext.maxChildMinWidth = maxChildMinWidth;
        }

        
        
        
        c = ownerContext.target;
        ownerContext.overflowX = (!ownerContext.widthModel.shrinkWrap && 
                                   ownerContext.maxChildMinWidth &&
                                   (c.autoScroll || c.overflowX)) || undef;

        ownerContext.overflowY = (!ownerContext.heightModel.shrinkWrap &&
                                   ownerContext.maxChildMinHeight &&
                                   (c.autoScroll || c.overflowY)) || undef;
    },

    calculate : function (ownerContext) {
        var me = this,
            childItems = ownerContext.childItems,
            length = childItems.length,
            containerSize = me.getContainerSize(ownerContext),
            info = {
                length: length,
                ownerContext: ownerContext,
                targetSize: containerSize
            },
            shrinkWrapWidth = ownerContext.widthModel.shrinkWrap,
            shrinkWrapHeight = ownerContext.heightModel.shrinkWrap,
            overflowX = ownerContext.overflowX,
            overflowY = ownerContext.overflowY,
            scrollbars, scrollbarSize, padding, i, contentWidth, contentHeight;

        if (overflowX || overflowY) {
            
            
            
            scrollbars = me.getScrollbarsNeeded(
                    overflowX && containerSize.width, overflowY && containerSize.height,
                    ownerContext.maxChildMinWidth, ownerContext.maxChildMinHeight);

            if (scrollbars) {
                scrollbarSize = Ext.getScrollbarSize();
                if (scrollbars & 1) { 
                    containerSize.height -= scrollbarSize.height;
                }
                if (scrollbars & 2) { 
                    containerSize.width -= scrollbarSize.width;
                }
            }
        }

        
        for (i = 0; i < length; ++i) {
            info.index = i;
            me.fitItem(childItems[i], info);
        }
        
        if (shrinkWrapHeight || shrinkWrapWidth) {
            padding = ownerContext.targetContext.getPaddingInfo();
            
            if (shrinkWrapWidth) {
                if (overflowY && !containerSize.gotHeight) {
                    
                    
                    
                    me.done = false;
                } else {
                    contentWidth = info.contentWidth + padding.width;
                    
                    
                    
                    if (scrollbars & 2) { 
                        contentWidth += scrollbarSize.width;
                    }
                    if (!ownerContext.setContentWidth(contentWidth)) {
                        me.done = false;
                    }
                }
            }

            if (shrinkWrapHeight) {
                if (overflowX && !containerSize.gotWidth) {
                    
                    
                    
                    me.done = false;
                } else {
                    contentHeight = info.contentHeight + padding.height;
                    
                    
                    
                    if (scrollbars & 1) { 
                        contentHeight += scrollbarSize.height;
                    }
                    if (!ownerContext.setContentHeight(contentHeight)) {
                        me.done = false;
                    }
                }
            }
        }
    },

    fitItem: function (itemContext, info) {
        var me = this;

        if (itemContext.invalid) {
            me.done = false;
            return;
        }

        info.margins = itemContext.getMarginInfo();
        info.needed = info.got = 0;

        me.fitItemWidth(itemContext, info);
        me.fitItemHeight(itemContext, info);

        
        if (info.got != info.needed) {
            me.done = false;
        }
    },

    fitItemWidth: function (itemContext, info) {
        var contentWidth, width;
        
        if (info.ownerContext.widthModel.shrinkWrap) {
            
            width = itemContext.getProp('width') + info.margins.width;
            

            contentWidth = info.contentWidth;
            if (contentWidth === undefined) {
                info.contentWidth = width;
            } else {
                info.contentWidth = Math.max(contentWidth, width);
            }
        } else if (itemContext.widthModel.calculated) {
            ++info.needed;
            if (info.targetSize.gotWidth) {
                ++info.got;
                this.setItemWidth(itemContext, info);
            }
        }

        this.positionItemX(itemContext, info);
    },

    fitItemHeight: function (itemContext, info) {
        var contentHeight, height;
        if (info.ownerContext.heightModel.shrinkWrap) {
            
            height = itemContext.getProp('height') + info.margins.height;
            

            contentHeight = info.contentHeight;
            if (contentHeight === undefined) {
                info.contentHeight = height;
            } else {
                info.contentHeight = Math.max(contentHeight, height);
            }
        } else if (itemContext.heightModel.calculated) {
            ++info.needed;
            if (info.targetSize.gotHeight) {
                ++info.got;
                this.setItemHeight(itemContext, info);
            }
        }

        this.positionItemY(itemContext, info);
    },

    positionItemX: function (itemContext, info) {
        var margins = info.margins;

        
        
        if (info.index || margins.left) {
            itemContext.setProp('x', margins.left);
        }

        if (margins.width) {
            
            itemContext.setProp('margin-right', margins.width);
        }
    },

    positionItemY: function (itemContext, info) {
        var margins = info.margins;

        if (info.index || margins.top) {
            itemContext.setProp('y', margins.top);
        }

        if (margins.height) {
            
            itemContext.setProp('margin-bottom', margins.height);
        }
    },

    setItemHeight: function (itemContext, info) {
        itemContext.setHeight(info.targetSize.height - info.margins.height);
    },

    setItemWidth: function (itemContext, info) {
        itemContext.setWidth(info.targetSize.width - info.margins.width);
    }
});


Ext.define('Ext.layout.container.Card', {

    

    extend: 'Ext.layout.container.Fit',

    alternateClassName: 'Ext.layout.CardLayout',

    alias: 'layout.card',

    

    type: 'card',

    hideInactive: true,

    
    deferredRender : false,
    
    getRenderTree: function () {
        var me = this,
            activeItem = me.getActiveItem();

        if (activeItem) {

            
            if (activeItem.hasListeners.beforeactivate && activeItem.fireEvent('beforeactivate', activeItem) === false) {
 
                
                
                
                activeItem = me.activeItem = me.owner.activeItem = null;
            }
            
            
            else if (activeItem.hasListeners.activate) {
                activeItem.on({
                    boxready: function() {
                        activeItem.fireEvent('activate', activeItem);
                    },
                    single: true
                });
            }

            if (me.deferredRender) {
                if (activeItem) {
                    return me.getItemsRenderTree([activeItem]);
                }
            } else {
                return me.callParent(arguments);
            }
        }
    },

    renderChildren: function () {
        var me = this,
            active = me.getActiveItem();
            
        if (!me.deferredRender) {
            me.callParent();
        } else if (active) {
            
            me.renderItems([active], me.getRenderTarget());
        }
    },

    isValidParent : function(item, target, position) {
        
        
        var itemEl = item.el ? item.el.dom : Ext.getDom(item);
        return (itemEl && itemEl.parentNode === (target.dom || target)) || false;
    },

    
    getActiveItem: function() {
        var me = this,
            
            result = me.parseActiveItem(me.activeItem || (me.owner && me.owner.activeItem));

        
        if (result && me.owner.items.indexOf(result) != -1) {
            me.activeItem = result;
        } else {
            me.activeItem = null;
        }

        return me.activeItem;
    },

    
    parseActiveItem: function(item) {
        if (item && item.isComponent) {
            return item;
        } else if (typeof item == 'number' || item === undefined) {
            return this.getLayoutItems()[item || 0];
        } else {
            return this.owner.getComponent(item);
        }
    },

    
    
    configureItem: function(item) {
        if (item === this.getActiveItem()) {
            item.hidden = false;
        } else {
            item.hidden = true;
        }
        this.callParent(arguments);
    },

    onRemove: function(component) {
        var me = this;
        
        if (component === me.activeItem) {
            me.activeItem = null;
        }
    },

    
    getAnimation: function(newCard, owner) {
        var newAnim = (newCard || {}).cardSwitchAnimation;
        if (newAnim === false) {
            return false;
        }
        return newAnim || owner.cardSwitchAnimation;
    },

    
    getNext: function() {
        
        
        var wrap = arguments[0],
            items = this.getLayoutItems(),
            index = Ext.Array.indexOf(items, this.activeItem);
            
        return items[index + 1] || (wrap ? items[0] : false);
    },

    
    next: function() {
        
        
        var anim = arguments[0], 
            wrap = arguments[1];
        return this.setActiveItem(this.getNext(wrap), anim);
    },

    
    getPrev: function() {
        
        
        var wrap = arguments[0],
            items = this.getLayoutItems(),
            index = Ext.Array.indexOf(items, this.activeItem);
            
        return items[index - 1] || (wrap ? items[items.length - 1] : false);
    },

    
    prev: function() {
        
        
        var anim = arguments[0], 
            wrap = arguments[1];
        return this.setActiveItem(this.getPrev(wrap), anim);
    },

    
    setActiveItem: function(newCard) {
        var me = this,
            owner = me.owner,
            oldCard = me.activeItem,
            rendered = owner.rendered,
            newIndex;

        newCard = me.parseActiveItem(newCard);
        newIndex = owner.items.indexOf(newCard);

        
        
        if (newIndex == -1) {
            newIndex = owner.items.items.length;
            Ext.suspendLayouts();
            newCard = owner.add(newCard);
            Ext.resumeLayouts();
        }

        
        if (newCard && oldCard != newCard) {
            
            if (newCard.fireEvent('beforeactivate', newCard, oldCard) === false) {
                return false;
            }
            if (oldCard && oldCard.fireEvent('beforedeactivate', oldCard, newCard) === false) {
                return false;
            }

            if (rendered) {
                Ext.suspendLayouts();

                
                if (!newCard.rendered) {
                    me.renderItem(newCard, me.getRenderTarget(), owner.items.length);
                }

                if (oldCard) {
                    if (me.hideInactive) {
                        oldCard.hide();
                        oldCard.hiddenByLayout = true;
                    }
                    oldCard.fireEvent('deactivate', oldCard, newCard);
                }
                
                if (newCard.hidden) {
                    newCard.show();
                }

                
                if (!newCard.hidden) {
                    me.activeItem = newCard;
                }
                Ext.resumeLayouts(true);
            } else {
                me.activeItem = newCard;
            }

            newCard.fireEvent('activate', newCard, oldCard);

            return me.activeItem;
        }
        return false;
    }
});


Ext.define('Ext.layout.container.Form', {

    

    alias: 'layout.form',
    extend: 'Ext.layout.container.Auto',
    alternateClassName: 'Ext.layout.FormLayout',

    
   
    tableCls: Ext.baseCSSPrefix + 'form-layout-table',

    type: 'form',

    manageOverflow: 2,

    childEls: ['formTable'],
    
    padRow: '<tr><td class="' + Ext.baseCSSPrefix + 'form-item-pad" colspan="3"></td></tr>',

    renderTpl: [
        '<table id="{ownerId}-formTable" class="{tableCls}" style="width:100%" cellpadding="0">',
            '{%this.renderBody(out,values)%}',
        '</table>',
        '{%this.renderPadder(out,values)%}'
    ],
    
    getRenderData: function(){
        var data = this.callParent();
        data.tableCls = this.tableCls;
        return data;    
    },

    calculate : function (ownerContext) {
        var me = this,
            containerSize = me.getContainerSize(ownerContext, true),
            tableWidth,
            childItems,
            i = 0, length;

        
        if (containerSize.gotWidth) {
            this.callParent(arguments);
            tableWidth = me.formTable.dom.offsetWidth;
            childItems = ownerContext.childItems;

            for (length = childItems.length; i < length; ++i) {
                childItems[i].setWidth(tableWidth, false);
            }
        } else {
            me.done = false;
        }
    },

    getRenderTarget: function() {
        return this.formTable;
    },

    getRenderTree: function() {
        var me = this,
            result = me.callParent(arguments),
            i, len;

        for (i = 0, len = result.length; i < len; i++) {
            result[i] = me.transformItemRenderTree(result[i]);
        }
        return result;
    },

    transformItemRenderTree: function(item) {

        if (item.tag && item.tag == 'table') {
            item.tag = 'tbody';
            delete item.cellspacing;
            delete item.cellpadding;

            
            
            
            
            if (Ext.isIE6) {
                item.cn = this.padRow;
            }

            return item;
        }

        return {
            tag: 'tbody',
            cn: {
                tag: 'tr',
                cn: {
                    tag: 'td',
                    colspan: 3,
                    style: 'width:100%',
                    cn: item
                }
            }
        };

    },

    isValidParent: function(item, target, position) {
        return true;
    },

    isItemShrinkWrap: function(item) {
        return ((item.shrinkWrap === true) ? 3 : item.shrinkWrap||0) & 2;
    },

    getItemSizePolicy: function(item) {
        return {
            setsWidth: 1,
            setsHeight: 0
        };
    }
});


Ext.define('Ext.layout.container.Table', {

    

    alias: ['layout.table'],
    extend: 'Ext.layout.container.Container',
    alternateClassName: 'Ext.layout.TableLayout',

    

    

    
    monitorResize:false,

    type: 'table',

    clearEl: true, 

    targetCls: Ext.baseCSSPrefix + 'table-layout-ct',
    tableCls: Ext.baseCSSPrefix + 'table-layout',
    cellCls: Ext.baseCSSPrefix + 'table-layout-cell',

    
    tableAttrs: null,

    

    

    itemSizePolicy: {
        setsWidth: 0,
        setsHeight: 0
    },

    getItemSizePolicy: function (item) {
        return this.itemSizePolicy;
    },

    getLayoutItems: function() {
        var me = this,
            result = [],
            items = me.callParent(),
            item,
            len = items.length, i;

        for (i = 0; i < len; i++) {
            item = items[i];
            if (!item.hidden) {
                result.push(item);
            }
        }
        return result;
    },

    
    renderChildren: function() {
        var me = this,
            items = me.getLayoutItems(),
            tbody = me.owner.getTargetEl().child('table', true).tBodies[0],
            rows = tbody.rows,
            i = 0,
            len = items.length,
            cells, curCell, rowIdx, cellIdx, item, trEl, tdEl, itemCt;

        
        cells = me.calculateCells(items);

        
        
        
        for (; i < len; i++) {
            curCell = cells[i];
            rowIdx = curCell.rowIdx;
            cellIdx = curCell.cellIdx;
            item = items[i];

            
            trEl = rows[rowIdx];
            if (!trEl) {
                trEl = tbody.insertRow(rowIdx);
                if (me.trAttrs) {
                    trEl.set(me.trAttrs);
                }
            }

            
            itemCt = tdEl = Ext.get(trEl.cells[cellIdx] || trEl.insertCell(cellIdx));
            if (me.needsDivWrap()) { 
                itemCt = tdEl.first() || tdEl.createChild({tag: 'div'});
                itemCt.setWidth(null);
            }

            
            if (!item.rendered) {
                me.renderItem(item, itemCt, 0);
            }
            else if (!me.isValidParent(item, itemCt, rowIdx, cellIdx, tbody)) {
                me.moveItem(item, itemCt, 0);
            }

            
            if (me.tdAttrs) {
                tdEl.set(me.tdAttrs);
            }
            if (item.tdAttrs) {
                tdEl.set(item.tdAttrs);
            }
            tdEl.set({
                colSpan: item.colspan || 1,
                rowSpan: item.rowspan || 1,
                id: item.cellId || '',
                cls: me.cellCls + ' ' + (item.cellCls || '')
            });

            
            if (!cells[i + 1] || cells[i + 1].rowIdx !== rowIdx) {
                cellIdx++;
                while (trEl.cells[cellIdx]) {
                    trEl.deleteCell(cellIdx);
                }
            }
        }

        
        rowIdx++;
        while (tbody.rows[rowIdx]) {
            tbody.deleteRow(rowIdx);
        }
    },

    calculate: function (ownerContext) {
        if (!ownerContext.hasDomProp('containerChildrenDone')) {
            this.done = false;
        } else {
            var targetContext = ownerContext.targetContext,
                widthShrinkWrap = ownerContext.widthModel.shrinkWrap,
                heightShrinkWrap = ownerContext.heightModel.shrinkWrap,
                shrinkWrap = heightShrinkWrap || widthShrinkWrap,
                table = shrinkWrap && targetContext.el.child('table', true),
                targetPadding = shrinkWrap && targetContext.getPaddingInfo();

            if (widthShrinkWrap) {
                ownerContext.setContentWidth(table.offsetWidth + targetPadding.width, true);
            }

            if (heightShrinkWrap) {
                ownerContext.setContentHeight(table.offsetHeight + targetPadding.height, true);
            }
        }
    },

    finalizeLayout: function() {
        if (this.needsDivWrap()) {
            
            var items = this.getLayoutItems(),
                i,
                iLen  = items.length,
                item;

            for (i = 0; i < iLen; i++) {
                item = items[i];

                Ext.fly(item.el.dom.parentNode).setWidth(item.getWidth());
            }
        }
        if (Ext.isIE6 || (Ext.isIEQuirks)) {
            
            this.owner.getTargetEl().child('table').repaint();
        }
    },

    
    calculateCells: function(items) {
        var cells = [],
            rowIdx = 0,
            colIdx = 0,
            cellIdx = 0,
            totalCols = this.columns || Infinity,
            rowspans = [], 
            i = 0, j,
            len = items.length,
            item;

        for (; i < len; i++) {
            item = items[i];

            
            while (colIdx >= totalCols || rowspans[colIdx] > 0) {
                if (colIdx >= totalCols) {
                    
                    colIdx = 0;
                    cellIdx = 0;
                    rowIdx++;

                    
                    for (j = 0; j < totalCols; j++) {
                        if (rowspans[j] > 0) {
                            rowspans[j]--;
                        }
                    }
                } else {
                    colIdx++;
                }
            }

            
            cells.push({
                rowIdx: rowIdx,
                cellIdx: cellIdx
            });

            
            for (j = item.colspan || 1; j; --j) {
                rowspans[colIdx] = item.rowspan || 1;
                ++colIdx;
            }
            ++cellIdx;
        }

        return cells;
    },

    getRenderTree: function() {
        var me = this,
            items = me.getLayoutItems(),
            cells,
            rows = [],
            result = Ext.apply({
                tag: 'table',
                role: 'presentation',
                cls: me.tableCls,
                cellspacing: 0,
                cn: {
                    tag: 'tbody',
                    cn: rows
                }
            }, me.tableAttrs),
            tdAttrs = me.tdAttrs,
            needsDivWrap = me.needsDivWrap(),
            i, len = items.length, item, curCell, tr, rowIdx, cellIdx, cell;

        
        cells = me.calculateCells(items);

        for (i = 0; i < len; i++) {
            item = items[i];
            
            curCell = cells[i];
            rowIdx = curCell.rowIdx;
            cellIdx = curCell.cellIdx;

            
            tr = rows[rowIdx];
            if (!tr) {
                tr = rows[rowIdx] = {
                    tag: 'tr',
                    cn: []
                };
                if (me.trAttrs) {
                    Ext.apply(tr, me.trAttrs);
                }
            }

            
            cell = tr.cn[cellIdx] = {
                tag: 'td'
            };
            if (tdAttrs) {
                Ext.apply(cell, tdAttrs);
            }
            Ext.apply(cell, {
                colSpan: item.colspan || 1,
                rowSpan: item.rowspan || 1,
                id: item.cellId || '',
                cls: me.cellCls + ' ' + (item.cellCls || '')
            });

            if (needsDivWrap) { 
                cell = cell.cn = {
                    tag: 'div'
                };
            }

            me.configureItem(item);
            
            cell.cn = item.getRenderTree();
        }
        return result;
    },

    isValidParent: function(item, target, rowIdx, cellIdx) {
        var tbody,
            correctCell,
            table;

        
        if (arguments.length === 3) {
            table = item.el.up('table');
            return table && table.dom.parentNode === target.dom;
        }
        tbody = this.owner.getTargetEl().child('table', true).tBodies[0];
        correctCell = tbody.rows[rowIdx].cells[cellIdx];
        return item.el.dom.parentNode === correctCell;
    },

    
    needsDivWrap: function() {
        return Ext.isOpera10_5;
    }
});


Ext.define('Ext.layout.container.boxOverflow.Scroller', {

    

    extend: 'Ext.layout.container.boxOverflow.None',
    requires: ['Ext.util.ClickRepeater', 'Ext.Element'],
    alternateClassName: 'Ext.layout.boxOverflow.Scroller',
    mixins: {
        observable: 'Ext.util.Observable'
    },
    
    

    
    animateScroll: false,

    
    scrollIncrement: 20,

    
    wheelIncrement: 10,

    
    scrollRepeatInterval: 60,

    
    scrollDuration: 400,

    

    

    
    scrollerCls: Ext.baseCSSPrefix + 'box-scroller',

    

    

    constructor: function(layout, config) {
        var me = this;

        me.layout = layout;
        Ext.apply(me, config || {});

        
        me.mixins.observable.constructor.call(me);

        me.addEvents(
            
            'scroll'
        );
        me.scrollPosition = 0;
        me.scrollSize = 0;
    },

    getPrefixConfig: function() {
        var me = this;
        me.initCSSClasses();
        return {
            cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls,
            cn : {
                id : me.layout.owner.id + '-before-scroller',
                cls: me.scrollerCls + ' ' + me.beforeScrollerCls,
                style: 'display:none'
            }
        };
    },

    getSuffixConfig: function() {
        var me = this;
        return {
            cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls,
            cn : {
                id : me.layout.owner.id + '-after-scroller',
                cls: me.scrollerCls + ' ' + me.afterScrollerCls,
                style: 'display:none'
            }
        };
    },

    getOverflowCls: function() {
        return Ext.baseCSSPrefix + this.layout.direction + '-box-overflow-body';
    },

    initCSSClasses: function() {
        var me = this,
            prefix = Ext.baseCSSPrefix,
            layout = me.layout,
            names = layout.getNames(),
            leftName = names.left,
            rightName = names.right,
            type = me.getOwnerType(layout.owner);

        me.beforeCtCls = me.beforeCtCls || prefix + 'box-scroller-' + leftName;
        me.afterCtCls  = me.afterCtCls  || prefix + 'box-scroller-' + rightName;
        
        me.beforeScrollerCls = me.beforeScrollerCls || prefix + type + '-scroll-' + leftName;
        me.afterScrollerCls  = me.afterScrollerCls  || prefix + type + '-scroll-' + rightName;
    },

    beginLayout: function (ownerContext) {
        var layout = this.layout,
            names = layout.getNames();

        ownerContext.innerCtScrollPos = layout.innerCt.dom['scroll' + names.leftCap];

        this.callParent(arguments);
    },

    completeLayout: function (ownerContext) {
        
        this.scrollSize = ownerContext.props['content'+this.layout.getNames().widthCap];

        this.callParent(arguments);
    },
    
    finishedLayout: function(ownerContext) {
        var me = this,
            layout = me.layout,
            names = layout.getNames(),
            scrollPos = Math.min(me.getMaxScrollPosition(), ownerContext.innerCtScrollPos);

        layout.innerCt.dom['scroll' + names.leftCap] = scrollPos;
    },

    handleOverflow: function(ownerContext) {
        var me = this,
            layout = me.layout,
            names = layout.getNames(),
            methodName = 'get' + names.widthCap;

        me.captureChildElements();
        me.showScrollers();

        return {
            reservedSpace: me.beforeCt[methodName]() + me.afterCt[methodName]()
        };
    },

    
    captureChildElements: function() {
        var me = this,
            el = me.layout.owner.el,
            before,
            after;

        
        if (!me.beforeCt) {
            before = me.beforeScroller = el.getById(me.layout.owner.id + '-before-scroller');
            after = me.afterScroller = el.getById(me.layout.owner.id + '-after-scroller');
            me.beforeCt = before.up('');
            me.afterCt = after.up('');
            me.createWheelListener();

            before.addClsOnOver(me.beforeScrollerCls + '-hover');
            after.addClsOnOver(me.afterScrollerCls + '-hover');

            before.setVisibilityMode(Ext.Element.DISPLAY);
            after.setVisibilityMode(Ext.Element.DISPLAY);

            me.beforeRepeater = new Ext.util.ClickRepeater(before, {
                interval: me.scrollRepeatInterval,
                handler : me.scrollLeft,
                scope   : me
            });

            me.afterRepeater = new Ext.util.ClickRepeater(after, {
                interval: me.scrollRepeatInterval,
                handler : me.scrollRight,
                scope   : me
            });
        }
    },

    
    createWheelListener: function() {
        this.layout.innerCt.on({
            mousewheel: function(e) {
                this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
            },
            stopEvent: true,
            scope: this
        });
    },

    
    clearOverflow: function () {
        var layout = this.layout;

        this.hideScrollers();
    },

    
    showScrollers: function() {
        var me = this;

        me.captureChildElements();
        me.beforeScroller.show();
        me.afterScroller.show();
        me.updateScrollButtons();
        me.layout.owner.addClsWithUI('scroller');
        
    },

    
    hideScrollers: function() {
        var me = this;

        if (me.beforeScroller !== undefined) {
            me.beforeScroller.hide();
            me.afterScroller.hide();
            me.layout.owner.removeClsWithUI('scroller');
            
        }
    },

    
    destroy: function() {
        var me = this;

        Ext.destroy(me.beforeRepeater, me.afterRepeater, me.beforeScroller, me.afterScroller, me.beforeCt, me.afterCt);
    },

    
    scrollBy: function(delta, animate) {
        this.scrollTo(this.getScrollPosition() + delta, animate);
    },

    
    getScrollAnim: function() {
        return {
            duration: this.scrollDuration, 
            callback: this.updateScrollButtons, 
            scope   : this
        };
    },

    
    updateScrollButtons: function() {
        var me = this,
            beforeMeth,
            afterMeth,
            beforeCls,
            afterCls;
            
        if (me.beforeScroller === undefined || me.afterScroller === undefined) {
            return;
        }

        beforeMeth = me.atExtremeBefore()  ? 'addCls' : 'removeCls';
        afterMeth  = me.atExtremeAfter() ? 'addCls' : 'removeCls';
        beforeCls  = me.beforeScrollerCls + '-disabled';
        afterCls   = me.afterScrollerCls  + '-disabled';

        me.beforeScroller[beforeMeth](beforeCls);
        me.afterScroller[afterMeth](afterCls);
        me.scrolling = false;
    },

    
    atExtremeBefore: function() {
        return !this.getScrollPosition();
    },

    
    scrollLeft: function() {
        this.scrollBy(-this.scrollIncrement, false);
    },

    
    scrollRight: function() {
        this.scrollBy(this.scrollIncrement, false);
    },

    
    getScrollPosition: function(){
        var me = this,
            layout = me.layout,
            result;

        
        if (me.hasOwnProperty('scrollPosition')) {
            result = me.scrollPosition;
        } else {
            result = parseInt(layout.innerCt.dom['scroll' + layout.getNames().leftCap], 10) || 0;
        }
        return result;
    },

    
    getMaxScrollPosition: function() {
        var me = this,
            layout = me.layout,
            names = layout.getNames(),
            maxScrollPos = me.scrollSize - layout.innerCt['get'+names.widthCap]();

        return (maxScrollPos < 0) ? 0 : maxScrollPos;
    },

    
    atExtremeAfter: function() {
        return this.getScrollPosition() >= this.getMaxScrollPosition();
    },

    
    scrollTo: function(position, animate) {
        var me = this,
            layout = me.layout,
            names = layout.getNames(),
            oldPosition = me.getScrollPosition(),
            newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition());

        if (newPosition != oldPosition && !me.scrolling) {
            delete me.scrollPosition;
            if (animate === undefined) {
                animate = me.animateScroll;
            }

            layout.innerCt.scrollTo(names.left, newPosition, animate ? me.getScrollAnim() : false);
            if (animate) {
                me.scrolling = true;
            } else {
                me.updateScrollButtons();
            }
            me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false);
        }
    },

    
    scrollToItem: function(item, animate) {
        var me = this,
            layout = me.layout,
            names = layout.getNames(),
            visibility,
            box,
            newPos;

        item = me.getItem(item);
        if (item !== undefined) {
            visibility = me.getItemVisibility(item);
            if (!visibility.fullyVisible) {
                box  = item.getBox(true, true);
                newPos = box[names.x];
                if (visibility.hiddenEnd) {
                    newPos -= (me.layout.innerCt['get' + names.widthCap]() - box[names.width]);
                }
                me.scrollTo(newPos, animate);
            }
        }
    },

    
    getItemVisibility: function(item) {
        var me          = this,
            box         = me.getItem(item).getBox(true, true),
            layout      = me.layout,
            names       = layout.getNames(),
            itemStart   = box[names.x],
            itemEnd     = itemStart + box[names.width],
            scrollStart = me.getScrollPosition(),
            scrollEnd   = scrollStart + layout.innerCt['get' + names.widthCap]();

        return {
            hiddenStart : itemStart < scrollStart,
            hiddenEnd   : itemEnd > scrollEnd,
            fullyVisible: itemStart > scrollStart && itemEnd < scrollEnd
        };
    }
});


Ext.define('Ext.menu.Item', {
    extend: 'Ext.Component',
    alias: 'widget.menuitem',
    alternateClassName: 'Ext.menu.TextItem',

    

    

    
    activeCls: Ext.baseCSSPrefix + 'menu-item-active',

    
    ariaRole: 'menuitem',

    
    canActivate: true,

    
    clickHideDelay: 1,

    
    destroyMenu: true,

    
    disabledCls: Ext.baseCSSPrefix + 'menu-item-disabled',

    

    

    
    hideOnClick: true,

    

    

    isMenuItem: true,

    

    

    
    menuAlign: 'tl-tr?',

    
    menuExpandDelay: 200,

    
    menuHideDelay: 200,

    

    

    
    tooltipType: 'qtip',

    arrowCls: Ext.baseCSSPrefix + 'menu-item-arrow',

    childEls: [
        'itemEl', 'iconEl', 'textEl', 'arrowEl'
    ],

    renderTpl: [
        '<tpl if="plain">',
            '{text}',
        '<tpl else>',
            '<a id="{id}-itemEl" class="' + Ext.baseCSSPrefix + 'menu-item-link" href="{href}" <tpl if="hrefTarget">target="{hrefTarget}"</tpl> hidefocus="true" unselectable="on">',
                '<img id="{id}-iconEl" src="{icon}" class="' + Ext.baseCSSPrefix + 'menu-item-icon {iconCls}" />',
                '<span id="{id}-textEl" class="' + Ext.baseCSSPrefix + 'menu-item-text" <tpl if="arrowCls">style="margin-right: 17px;"</tpl> >{text}</span>',
                '<img id="{id}-arrowEl" src="{blank}" class="{arrowCls}" />',
            '</a>',
        '</tpl>'
    ],

    maskOnDisable: false,

    

    

    activate: function() {
        var me = this;

        if (!me.activated && me.canActivate && me.rendered && !me.isDisabled() && me.isVisible()) {
            me.el.addCls(me.activeCls);
            me.focus();
            me.activated = true;
            me.fireEvent('activate', me);
        }
    },

    getFocusEl: function() {
        return this.itemEl;
    },

    deactivate: function() {
        var me = this;

        if (me.activated) {
            me.el.removeCls(me.activeCls);
            me.blur();
            me.hideMenu();
            me.activated = false;
            me.fireEvent('deactivate', me);
        }
    },

    deferExpandMenu: function() {
        var me = this;

        if (me.activated && (!me.menu.rendered || !me.menu.isVisible())) {
            me.parentMenu.activeChild = me.menu;
            me.menu.parentItem = me;
            me.menu.parentMenu = me.menu.ownerCt = me.parentMenu;
            me.menu.showBy(me, me.menuAlign);
        }
    },

    deferHideMenu: function() {
        if (this.menu.isVisible()) {
            this.menu.hide();
        }
    },
    
    cancelDeferHide: function(){
        clearTimeout(this.hideMenuTimer);
    },

    deferHideParentMenus: function() {
        var ancestor;
        Ext.menu.Manager.hideAll();

        if (!Ext.Element.getActiveElement()) {
            
            ancestor = this.up(':not([hidden])');
            if (ancestor) {
                ancestor.focus();
            }
        }
    },

    expandMenu: function(delay) {
        var me = this;

        if (me.menu) {
            me.cancelDeferHide();
            if (delay === 0) {
                me.deferExpandMenu();
            } else {
                me.expandMenuTimer = Ext.defer(me.deferExpandMenu, Ext.isNumber(delay) ? delay : me.menuExpandDelay, me);
            }
        }
    },

    getRefItems: function(deep){
        var menu = this.menu,
            items;

        if (menu) {
            items = menu.getRefItems(deep);
            items.unshift(menu);
        }
        return items || [];
    },

    hideMenu: function(delay) {
        var me = this;

        if (me.menu) {
            clearTimeout(me.expandMenuTimer);
            me.hideMenuTimer = Ext.defer(me.deferHideMenu, Ext.isNumber(delay) ? delay : me.menuHideDelay, me);
        }
    },

    initComponent: function() {
        var me = this,
            prefix = Ext.baseCSSPrefix,
            cls = [prefix + 'menu-item'],
            menu;

        me.addEvents(
            
            'activate',

            
            'click',

            
            'deactivate'
        );

        if (me.plain) {
            cls.push(prefix + 'menu-item-plain');
        }

        if (me.cls) {
            cls.push(me.cls);
        }

        me.cls = cls.join(' ');

        if (me.menu) {
            menu = me.menu;
            delete me.menu;
            me.setMenu(menu);
        }

        me.callParent(arguments);
    },

    onClick: function(e) {
        var me = this;

        if (!me.href) {
            e.stopEvent();
        }

        if (me.disabled) {
            return;
        }

        if (me.hideOnClick) {
            me.deferHideParentMenusTimer = Ext.defer(me.deferHideParentMenus, me.clickHideDelay, me);
        }

        Ext.callback(me.handler, me.scope || me, [me, e]);
        me.fireEvent('click', me, e);

        if (!me.hideOnClick) {
            me.focus();
        }
    },

    onRemoved: function() {
        var me = this;

        
        if (me.activated && me.parentMenu.activeItem === me) {
            me.parentMenu.deactivateActiveItem();
        }
        me.callParent(arguments);
        delete me.parentMenu;
        delete me.ownerButton;
    },

    
    beforeDestroy: function() {
        var me = this;
        if (me.rendered) {
            me.clearTip();
        }
        me.callParent();
    },

    onDestroy: function() {
        var me = this;

        clearTimeout(me.expandMenuTimer);
        me.cancelDeferHide();
        clearTimeout(me.deferHideParentMenusTimer);

        me.setMenu(null);
        me.callParent(arguments);
    },

    beforeRender: function() {
        var me = this,
            blank = Ext.BLANK_IMAGE_URL,
            iconCls,
            arrowCls;

        me.callParent();

        if (me.iconAlign === 'right') {
            iconCls = me.checkChangeDisabled ? me.disabledCls : '';
            arrowCls = Ext.baseCSSPrefix + 'menu-item-icon-right ' + me.iconCls;
        } else {
            iconCls = me.iconCls + (me.checkChangeDisabled ? ' ' + me.disabledCls : '');
            arrowCls = me.menu ? me.arrowCls : '';
        }
        Ext.applyIf(me.renderData, {
            href: me.href || '#',
            hrefTarget: me.hrefTarget,
            icon: me.icon || blank,
            iconCls: iconCls,
            plain: me.plain,
            text: me.text,
            arrowCls: arrowCls,
            blank: blank
        });
    },

    onRender: function() {
        var me = this;

        me.callParent(arguments);

        if (me.tooltip) {
            me.setTooltip(me.tooltip, true);
        }
    },
    
    
    setMenu: function(menu, destroyMenu) {
        var me = this,
            oldMenu = me.menu,
            arrowEl = me.arrowEl;
            
        if (oldMenu) {
            delete oldMenu.parentItem;
            delete oldMenu.parentMenu;
            delete oldMenu.ownerCt;
            delete oldMenu.ownerItem;
            
            if (destroyMenu === true || (destroyMenu !== false && me.destroyMenu)) {
                Ext.destroy(oldMenu);
            }
        }
        if (menu) {
            me.menu = Ext.menu.Manager.get(menu);
            me.menu.ownerItem = me;
        } else {
            me.menu = null;
        }
        
        if (me.rendered && !me.destroying && arrowEl) {
            arrowEl[me.menu ? 'addCls' : 'removeCls'](me.arrowCls);
        }
    },

    
    setHandler: function(fn, scope) {
        this.handler = fn || null;
        this.scope = scope;
    },
    
    
    setIcon: function(icon){
        var iconEl = this.iconEl;
        if (iconEl) {
            iconEl.src = icon || Ext.BLANK_IMAGE_URL;
        }
        this.icon = icon;
    },

    
    setIconCls: function(iconCls) {
        var me = this,
            iconEl = me.iconEl;

        if (iconEl) {
            if (me.iconCls) {
                iconEl.removeCls(me.iconCls);
            }

            if (iconCls) {
                iconEl.addCls(iconCls);
            }
        }

        me.iconCls = iconCls;
    },

    
    setText: function(text) {
        var me = this,
            el = me.textEl || me.el;

        me.text = text;

        if (me.rendered) {
            el.update(text || '');
            
            me.ownerCt.updateLayout();
        }
    },

    getTipAttr: function(){
        return this.tooltipType == 'qtip' ? 'data-qtip' : 'title';
    },

    
    clearTip: function() {
        if (Ext.isObject(this.tooltip)) {
            Ext.tip.QuickTipManager.unregister(this.itemEl);
        }
    },

    
    setTooltip: function(tooltip, initial) {
        var me = this;

        if (me.rendered) {
            if (!initial) {
                me.clearTip();
            }

            if (Ext.isObject(tooltip)) {
                Ext.tip.QuickTipManager.register(Ext.apply({
                    target: me.itemEl.id
                },
                tooltip));
                me.tooltip = tooltip;
            } else {
                me.itemEl.dom.setAttribute(me.getTipAttr(), tooltip);
            }
        } else {
            me.tooltip = tooltip;
        }

        return me;
    }
});


Ext.define('Ext.menu.CheckItem', {
    extend: 'Ext.menu.Item',
    alias: 'widget.menucheckitem',
    
    
    
    

    
    
    

    
    checkedCls: Ext.baseCSSPrefix + 'menu-item-checked',
    
    uncheckedCls: Ext.baseCSSPrefix + 'menu-item-unchecked',
    
    groupCls: Ext.baseCSSPrefix + 'menu-group-icon',

    
    hideOnClick: false,
    
    
    checkChangeDisabled: false,

    afterRender: function() {
        var me = this;
        me.callParent();
        me.checked = !me.checked;
        me.setChecked(!me.checked, true);
        if (me.checkChangeDisabled) {
            me.disableCheckChange();
        }
    },

    initComponent: function() {
        var me = this;
        me.addEvents(
            
            'beforecheckchange',

            
            'checkchange'
        );

        me.callParent(arguments);

        Ext.menu.Manager.registerCheckable(me);

        if (me.group) {
            if (!me.iconCls) {
                me.iconCls = me.groupCls;
            }
            if (me.initialConfig.hideOnClick !== false) {
                me.hideOnClick = true;
            }
        }
    },

    
    disableCheckChange: function() {
        var me = this,
            iconEl = me.iconEl;

        if (iconEl) {
            iconEl.addCls(me.disabledCls);
        }
        
        
        if (!(Ext.isIE9 && Ext.isStrict) && me.rendered) {
            me.el.repaint();
        }
        me.checkChangeDisabled = true;
    },

    
    enableCheckChange: function() {
        var me = this,
            iconEl = me.iconEl;
            
        if (iconEl) {
            iconEl.removeCls(me.disabledCls);
        }
        me.checkChangeDisabled = false;
    },

    onClick: function(e) {
        var me = this;
        if(!me.disabled && !me.checkChangeDisabled && !(me.checked && me.group)) {
            me.setChecked(!me.checked);
        }
        this.callParent([e]);
    },

    onDestroy: function() {
        Ext.menu.Manager.unregisterCheckable(this);
        this.callParent(arguments);
    },

    
    setChecked: function(checked, suppressEvents) {
        var me = this;
        if (me.checked !== checked && (suppressEvents || me.fireEvent('beforecheckchange', me, checked) !== false)) {
            if (me.el) {
                me.el[checked  ? 'addCls' : 'removeCls'](me.checkedCls)[!checked ? 'addCls' : 'removeCls'](me.uncheckedCls);
            }
            me.checked = checked;
            Ext.menu.Manager.onCheckChange(me, checked);
            if (!suppressEvents) {
                Ext.callback(me.checkHandler, me.scope, [me, checked]);
                me.fireEvent('checkchange', me, checked);
            }
        }
    }
});


Ext.define('Ext.menu.KeyNav', {
    extend: 'Ext.util.KeyNav',

    requires: ['Ext.FocusManager'],
    
    constructor: function(menu) {
        var me = this;

        me.menu = menu;
        me.callParent([menu.el, {
            down: me.down,
            enter: me.enter,
            esc: me.escape,
            left: me.left,
            right: me.right,
            space: me.enter,
            tab: me.tab,
            up: me.up
        }]);
    },

    down: function(e) {
        var me = this,
            fi = me.menu.focusedItem;

        if (fi && e.getKey() == Ext.EventObject.DOWN && me.isWhitelisted(fi)) {
            return true;
        }
        me.focusNextItem(1);
    },

    enter: function(e) {
        var menu = this.menu,
            focused = menu.focusedItem;
 
        if (menu.activeItem) {
            menu.onClick(e);
        } else if (focused && focused.isFormField) {
            
            return true;
        }
    },

    escape: function(e) {
        Ext.menu.Manager.hideAll();
    },

    focusNextItem: function(step) {
        var menu = this.menu,
            items = menu.items,
            focusedItem = menu.focusedItem,
            startIdx = focusedItem ? items.indexOf(focusedItem) : -1,
            idx = startIdx + step,
            item;

        while (idx != startIdx) {
            if (idx < 0) {
                idx = items.length - 1;
            } else if (idx >= items.length) {
                idx = 0;
            }

            item = items.getAt(idx);
            if (menu.canActivateItem(item)) {
                menu.setActiveItem(item);
                break;
            }
            idx += step;
        }
    },

    isWhitelisted: function(item) {
        return Ext.FocusManager.isWhitelisted(item);
    },

    left: function(e) {
        var menu = this.menu,
            fi = menu.focusedItem,
            ai = menu.activeItem;

        if (fi && this.isWhitelisted(fi)) {
            return true;
        }

        menu.hide();
        if (menu.parentMenu) {
            menu.parentMenu.focus();
        }
    },

    right: function(e) {
        var menu = this.menu,
            fi = menu.focusedItem,
            ai = menu.activeItem,
            am;

        if (fi && this.isWhitelisted(fi)) {
            return true;
        }

        if (ai) {
            am = menu.activeItem.menu;
            if (am) {
                ai.expandMenu(0);
                Ext.defer(function() {
                    am.setActiveItem(am.items.getAt(0));
                }, 25);
            }
        }
    },

    tab: function(e) {
        var me = this;

        if (e.shiftKey) {
            me.up(e);
        } else {
            me.down(e);
        }
    },

    up: function(e) {
        var me = this,
            fi = me.menu.focusedItem;

        if (fi && e.getKey() == Ext.EventObject.UP && me.isWhitelisted(fi)) {
            return true;
        }
        me.focusNextItem(-1);
    }
});

Ext.define('Ext.menu.Manager', {
    singleton: true,
    requires: [
        'Ext.util.MixedCollection',
        'Ext.util.KeyMap'
    ],
    alternateClassName: 'Ext.menu.MenuMgr',

    uses: ['Ext.menu.Menu'],

    menus: {},
    groups: {},
    attached: false,
    lastShow: new Date(),

    init: function() {
        var me = this;
        
        me.active = new Ext.util.MixedCollection();
        Ext.getDoc().addKeyListener(27, function() {
            if (me.active.length > 0) {
                me.hideAll();
            }
        }, me);
    },

    
    hideAll: function() {
        var active = this.active,
        clone, menus, m, mLen;

        if (active && active.length > 0) {
            clone = active.clone();
            menus = clone.items;
            mLen  = menus.length;

            for (m = 0; m < mLen; m++) {
                menus[m].hide();
            }

            return true;
        }
        return false;
    },

    onHide: function(m) {
        var me = this,
            active = me.active;
        active.remove(m);
        if (active.length < 1) {
            Ext.getDoc().un('mousedown', me.onMouseDown, me);
            me.attached = false;
        }
    },

    onShow: function(m) {
        var me = this,
            active   = me.active,
            last     = active.last(),
            attached = me.attached,
            menuEl   = m.getEl(),
            zIndex;

        me.lastShow = new Date();
        active.add(m);
        if (!attached) {
            Ext.getDoc().on('mousedown', me.onMouseDown, me, {
                
                
                buffer: Ext.isIE ? 10 : undefined
            });
            me.attached = true;
        }
        m.toFront();
    },

    onBeforeHide: function(m) {
        if (m.activeChild) {
            m.activeChild.hide();
        }
        if (m.autoHideTimer) {
            clearTimeout(m.autoHideTimer);
            delete m.autoHideTimer;
        }
    },

    onBeforeShow: function(m) {
        var active = this.active,
            parentMenu = m.parentMenu;
            
        active.remove(m);
        if (!parentMenu && !m.allowOtherMenus) {
            this.hideAll();
        }
        else if (parentMenu && parentMenu.activeChild && m != parentMenu.activeChild) {
            parentMenu.activeChild.hide();
        }
    },

    
    onMouseDown: function(e) {
        var me = this,
            active = me.active,
            lastShow = me.lastShow;

        if (Ext.Date.getElapsed(lastShow) > 50 && active.length > 0 && !e.getTarget('.' + Ext.baseCSSPrefix + 'menu')) {
            me.hideAll();
        }
    },

    
    register: function(menu) {
        var me = this;

        if (!me.active) {
            me.init();
        }

        if (menu.floating) {
            me.menus[menu.id] = menu;
            menu.on({
                beforehide: me.onBeforeHide,
                hide: me.onHide,
                beforeshow: me.onBeforeShow,
                show: me.onShow,
                scope: me
            });
        }
    },

    
    get: function(menu) {
        var menus = this.menus;
        
        if (typeof menu == 'string') { 
            if (!menus) {  
                return null;
            }
            return menus[menu];
        } else if (menu.isMenu) {  
            return menu;
        } else if (Ext.isArray(menu)) { 
            return new Ext.menu.Menu({items:menu});
        } else { 
            return Ext.ComponentManager.create(menu, 'menu');
        }
    },

    
    unregister: function(menu) {
        var me = this,
            menus = me.menus,
            active = me.active;

        delete menus[menu.id];
        active.remove(menu);
        menu.un({
            beforehide: me.onBeforeHide,
            hide: me.onHide,
            beforeshow: me.onBeforeShow,
            show: me.onShow,
            scope: me
        });
    },

    
    registerCheckable: function(menuItem) {
        var groups  = this.groups,
            groupId = menuItem.group;

        if (groupId) {
            if (!groups[groupId]) {
                groups[groupId] = [];
            }

            groups[groupId].push(menuItem);
        }
    },

    
    unregisterCheckable: function(menuItem) {
        var groups  = this.groups,
            groupId = menuItem.group;

        if (groupId) {
            Ext.Array.remove(groups[groupId], menuItem);
        }
    },

    onCheckChange: function(menuItem, state) {
        var groups  = this.groups,
            groupId = menuItem.group,
            i       = 0,
            group, ln, curr;

        if (groupId && state) {
            group = groups[groupId];
            ln = group.length;
            for (; i < ln; i++) {
                curr = group[i];
                if (curr != menuItem) {
                    curr.setChecked(false);
                }
            }
        }
    }
});

Ext.define('Ext.button.Button', {

    
    alias: 'widget.button',
    extend: 'Ext.Component',

    requires: [
        'Ext.menu.Manager',
        'Ext.util.ClickRepeater',
        'Ext.layout.component.Button',
        'Ext.util.TextMetrics',
        'Ext.util.KeyMap'
    ],

    alternateClassName: 'Ext.Button',
    

    
    isButton: true,
    componentLayout: 'button',

    
    hidden: false,

    
    disabled: false,

    
    pressed: false,

    

    

    

    

    

    

    

    

    

    

    

    

    
    enableToggle: false,

    

    

    
    menuAlign: 'tl-bl?',

    
    textAlign: 'center',

    

    

    
    type: 'button',

    
    clickEvent: 'click',

    
    preventDefault: true,

    
    handleMouseEvents: true,

    
    tooltipType: 'qtip',

    
    baseCls: Ext.baseCSSPrefix + 'btn',

    
    pressedCls: 'pressed',

    
    overCls: 'over',

    
    focusCls: 'focus',

    
    menuActiveCls: 'menu-active',

    
    
    
     hrefTarget: '_blank',
     
     border: true,

    

    

    childEls: [
        'btnEl', 'btnWrap', 'btnInnerEl', 'btnIconEl'
    ],

    renderTpl: [
        '<em id="{id}-btnWrap"<tpl if="splitCls"> class="{splitCls}"</tpl>>',
            '<tpl if="href">',
                '<a id="{id}-btnEl" href="{href}" class="{btnCls}" target="{hrefTarget}"',
                    '<tpl if="tabIndex"> tabIndex="{tabIndex}"</tpl>',
                    '<tpl if="disabled"> disabled="disabled"</tpl>',
                    ' role="link">',
                    '<span id="{id}-btnInnerEl" class="{baseCls}-inner">',
                        '{text}',
                    '</span>',
                    '<span id="{id}-btnIconEl" class="{baseCls}-icon {iconCls}"<tpl if="iconUrl"> style="background-image:url({iconUrl})"</tpl>></span>',
                '</a>',
            '<tpl else>',
                '<button id="{id}-btnEl" type="{type}" class="{btnCls}" hidefocus="true"',
                    
                    
                    '<tpl if="tabIndex"> tabIndex="{tabIndex}"</tpl>',
                    '<tpl if="disabled"> disabled="disabled"</tpl>',
                    ' role="button" autocomplete="off">',
                    '<span id="{id}-btnInnerEl" class="{baseCls}-inner" style="{innerSpanStyle}">',
                        '{text}',
                    '</span>',
                    '<span id="{id}-btnIconEl" class="{baseCls}-icon {iconCls}"<tpl if="iconUrl"> style="background-image:url({iconUrl})"</tpl>></span>',
                '</button>',
            '</tpl>',
        '</em>',
        '<tpl if="closable">',
            '<a id="{id}-closeEl" href="#" class="{baseCls}-close-btn" title="{closeText}"></a>',
        '</tpl>'
    ],

    
    scale: 'small',

    
    allowedScales: ['small', 'medium', 'large'],

    

    
    iconAlign: 'left',

    
    arrowAlign: 'right',

    
    arrowCls: 'arrow',

    

    

    

    maskOnDisable: false,
    
    
    persistentPadding: undefined,

    shrinkWrap: 3,

    frame: true,

    
    initComponent: function() {
        var me = this;
        me.callParent(arguments);

        me.addEvents(
            
            'click',

            
            'toggle',

            
            'mouseover',

            
            'mouseout',

            
            'menushow',

            
            'menuhide',

            
            'menutriggerover',

            
            'menutriggerout'
        );

        if (me.menu) {
            
            me.split = true;

            
            me.menu = Ext.menu.Manager.get(me.menu);
            me.menu.ownerButton = me;
        }

        
        if (me.url) {
            me.href = me.url;
        }

        
        if (me.href && !me.hasOwnProperty('preventDefault')) {
            me.preventDefault = false;
        }

        if (Ext.isString(me.toggleGroup) && me.toggleGroup !== '') {
            me.enableToggle = true;
        }
        
        if (me.html && !me.text) {
            me.text = me.html;
            delete me.html;
        }

    },

    
    getActionEl: function() {
        return this.btnEl;
    },

    
    getFocusEl: function() {
        return this.useElForFocus ? this.el : this.btnEl;
    },

    
    onFocus: function(e) {
        var me = this;

        
        
        me.useElForFocus = true;
        me.callParent(arguments);
        me.useElForFocus = false;
    },

    
    onBlur : function(e) {
        this.useElForFocus = true;
        this.callParent(arguments);
        this.useElForFocus = false;
    },
    
    
    onDisable: function(){
        this.useElForFocus = true;
        this.callParent(arguments);
        this.useElForFocus = false;
    },

    
    setComponentCls: function() {
        var me = this,
            cls = me.getComponentCls();

        if (!Ext.isEmpty(me.oldCls)) {
            me.removeClsWithUI(me.oldCls);
            me.removeClsWithUI(me.pressedCls);
        }

        me.oldCls = cls;
        me.addClsWithUI(cls);
    },

    getComponentCls: function() {
        var me = this,
            cls = [];

        
        if (me.iconCls || me.icon) {
            if (me.text) {
                cls.push('icon-text-' + me.iconAlign);
            } else {
                cls.push('icon');
            }
        } else if (me.text) {
            cls.push('noicon');
        }

        if (me.pressed) {
            cls.push(me.pressedCls);
        }
        return cls;
    },

    beforeRender: function () {
        var me = this;

        me.callParent();

        
        me.oldCls = me.getComponentCls();
        me.addClsWithUI(me.oldCls);

        
        Ext.applyIf(me.renderData, me.getTemplateArgs());

        if (me.scale) {
            me.setScale(me.scale);
        }
    },

    
    onRender: function() {
        var me = this,
            addOnclick,
            btn,
            btnListeners;

        me.doc = Ext.getDoc();
        me.callParent(arguments);

        
        if (me.split && me.arrowTooltip) {
            me.arrowEl.dom.setAttribute(me.getTipAttr(), me.arrowTooltip);
        }

        
        btn = me.el;

        if (me.tooltip) {
            me.setTooltip(me.tooltip, true);
        }

        
        if (me.handleMouseEvents) {
            btnListeners = {
                scope: me,
                mouseover: me.onMouseOver,
                mouseout: me.onMouseOut,
                mousedown: me.onMouseDown
            };
            if (me.split) {
                btnListeners.mousemove = me.onMouseMove;
            }
        } else {
            btnListeners = {
                scope: me
            };
        }

        
        if (me.menu) {
            me.mon(me.menu, {
                scope: me,
                show: me.onMenuShow,
                hide: me.onMenuHide
            });

            me.keyMap = new Ext.util.KeyMap({
                target: me.el,
                key: Ext.EventObject.DOWN,
                handler: me.onDownKey,
                scope: me
            });
        }

        
        if (me.repeat) {
            me.mon(new Ext.util.ClickRepeater(btn, Ext.isObject(me.repeat) ? me.repeat: {}), 'click', me.onRepeatClick, me);
        } else {

            
            if (btnListeners[me.clickEvent]) {
                addOnclick = true;
            } else {
                btnListeners[me.clickEvent] = me.onClick;
            }
        }

        
        me.mon(btn, btnListeners);

        
        if (addOnclick) {
            me.mon(btn, me.clickEvent, me.onClick, me);
        }

        
        Ext.ButtonToggleManager.register(me);
    },

    
    getTemplateArgs: function() {
        var me = this,
            persistentPadding = me.getPersistentPadding(),
            innerSpanStyle = '';

        
        if (Math.max.apply(Math, persistentPadding) > 0) {
            innerSpanStyle = 'margin:' + Ext.Array.map(persistentPadding, function(pad) {
                return -pad + 'px';
            }).join(' ');
        }

        return {
            href     : me.getHref(),
            disabled : me.disabled,
            hrefTarget: me.hrefTarget,
            type     : me.type,
            btnCls   : me.getBtnCls(),
            splitCls : me.getSplitCls(),
            iconUrl  : me.icon,
            iconCls  : me.iconCls,
            text     : me.text || '&#160;',
            tabIndex : me.tabIndex,
            innerSpanStyle: innerSpanStyle
        };
    },

    
    getHref: function() {
        var me = this,
            params = Ext.apply({}, me.baseParams);

        
        params = Ext.apply(params, me.params);
        return me.href ? Ext.urlAppend(me.href, Ext.Object.toQueryString(params)) : false;
    },

    
    setParams: function(params) {
        this.params = params;
        this.btnEl.dom.href = this.getHref();
    },

    getSplitCls: function() {
        var me = this;
        return me.split ? (me.baseCls + '-' + me.arrowCls) + ' ' + (me.baseCls + '-' + me.arrowCls + '-' + me.arrowAlign) : '';
    },

    getBtnCls: function() {
        return this.textAlign ? this.baseCls + '-' + this.textAlign : '';
    },

    
    setIconCls: function(cls) {
        var me = this,
            btnIconEl = me.btnIconEl,
            oldCls = me.iconCls;
            
        me.iconCls = cls;
        if (btnIconEl) {
            
            btnIconEl.removeCls(oldCls);
            btnIconEl.addCls(cls || '');
            me.setComponentCls();
            if (me.didIconStateChange(oldCls, cls)) {
                me.updateLayout();
            }
        }
        return me;
    },

    
    setTooltip: function(tooltip, initial) {
        var me = this;

        if (me.rendered) {
            if (!initial) {
                me.clearTip();
            }
            if (Ext.isObject(tooltip)) {
                Ext.tip.QuickTipManager.register(Ext.apply({
                    target: me.btnEl.id
                },
                tooltip));
                me.tooltip = tooltip;
            } else {
                me.btnEl.dom.setAttribute(me.getTipAttr(), tooltip);
            }
        } else {
            me.tooltip = tooltip;
        }
        return me;
    },

    
    setTextAlign: function(align) {
        var me = this,
            btnEl = me.btnEl;

        if (btnEl) {
            btnEl.removeCls(me.baseCls + '-' + me.textAlign);
            btnEl.addCls(me.baseCls + '-' + align);
        }
        me.textAlign = align;
        return me;
    },

    getTipAttr: function(){
        return this.tooltipType == 'qtip' ? 'data-qtip' : 'title';
    },

    
    getRefItems: function(deep){
        var menu = this.menu,
            items;
        
        if (menu) {
            items = menu.getRefItems(deep);
            items.unshift(menu);
        }
        return items || [];
    },

    
    clearTip: function() {
        if (Ext.isObject(this.tooltip)) {
            Ext.tip.QuickTipManager.unregister(this.btnEl);
        }
    },

    
    beforeDestroy: function() {
        var me = this;
        if (me.rendered) {
            me.clearTip();
        }
        if (me.menu && me.destroyMenu !== false) {
            Ext.destroy(me.menu);
        }
        Ext.destroy(me.btnInnerEl, me.repeater);
        me.callParent();
    },

    
    onDestroy: function() {
        var me = this;
        if (me.rendered) {
            me.doc.un('mouseover', me.monitorMouseOver, me);
            me.doc.un('mouseup', me.onMouseUp, me);
            delete me.doc;
            Ext.ButtonToggleManager.unregister(me);

            Ext.destroy(me.keyMap);
            delete me.keyMap;
        }
        me.callParent();
    },

    
    setHandler: function(handler, scope) {
        this.handler = handler;
        this.scope = scope;
        return this;
    },

    
    setText: function(text) {
        var me = this;
        me.text = text;
        if (me.rendered) {
            me.btnInnerEl.update(text || '&#160;');
            me.setComponentCls();
            if (Ext.isStrict && Ext.isIE8) {
                
                me.el.repaint();
            }
            me.updateLayout();
        }
        return me;
    },

    
    setIcon: function(icon) {
        var me = this,
            btnIconEl = me.btnIconEl,
            oldIcon = me.icon;
            
        me.icon = icon;
        if (btnIconEl) {
            btnIconEl.setStyle('background-image', icon ? 'url(' + icon + ')': '');
            me.setComponentCls();
            if (me.didIconStateChange(oldIcon, icon)) {
                me.updateLayout();
            }
        }
        return me;
    },
    
    
    didIconStateChange: function(old, current) {
        var currentEmpty = Ext.isEmpty(current);
        return Ext.isEmpty(old) ? !currentEmpty : currentEmpty;
    },

    
    getText: function() {
        return this.text;
    },

    
    toggle: function(state, suppressEvent) {
        var me = this;
        state = state === undefined ? !me.pressed: !!state;
        if (state !== me.pressed) {
            if (me.rendered) {
                me[state ? 'addClsWithUI': 'removeClsWithUI'](me.pressedCls);
            }
            me.pressed = state;
            if (!suppressEvent) {
                me.fireEvent('toggle', me, state);
                Ext.callback(me.toggleHandler, me.scope || me, [me, state]);
            }
        }
        return me;
    },
    
    maybeShowMenu: function(){
        var me = this;
        if (me.menu && !me.hasVisibleMenu() && !me.ignoreNextClick) {
            me.showMenu();
        }
    },

    
    showMenu: function() {
        var me = this;
        if (me.rendered && me.menu) {
            if (me.tooltip && me.getTipAttr() != 'title') {
                Ext.tip.QuickTipManager.getQuickTip().cancelShow(me.btnEl);
            }
            if (me.menu.isVisible()) {
                me.menu.hide();
            }

            me.menu.showBy(me.el, me.menuAlign, ((!Ext.isStrict && Ext.isIE) || Ext.isIE6) ? [-2, -2] : undefined);
        }
        return me;
    },

    
    hideMenu: function() {
        if (this.hasVisibleMenu()) {
            this.menu.hide();
        }
        return this;
    },

    
    hasVisibleMenu: function() {
        var menu = this.menu;
        return menu && menu.rendered && menu.isVisible();
    },

    
    onRepeatClick: function(repeat, e) {
        this.onClick(e);
    },

    
    onClick: function(e) {
        var me = this;
        if (me.preventDefault || (me.disabled && me.getHref()) && e) {
            e.preventDefault();
        }
        if (e.button !== 0) {
            return;
        }
        if (!me.disabled) {
            me.doToggle();
            me.maybeShowMenu();
            me.fireHandler(e);
        }
    },
    
    fireHandler: function(e){
        var me = this,
            handler = me.handler;
            
        if (me.fireEvent('click', me, e) !== false) {
            if (handler) {
                handler.call(me.scope || me, me, e);
            }
            me.blur();
        }
    },
    
    doToggle: function(){
        var me = this;    
        if (me.enableToggle && (me.allowDepress !== false || !me.pressed)) {
            me.toggle();
        }
    },

    
    onMouseOver: function(e) {
        var me = this;
        if (!me.disabled && !e.within(me.el, true, true)) {
            me.onMouseEnter(e);
        }
    },

    
    onMouseOut: function(e) {
        var me = this;
        if (!e.within(me.el, true, true)) {
            if (me.overMenuTrigger) {
                me.onMenuTriggerOut(e);
            }
            me.onMouseLeave(e);
        }
    },

    
    onMouseMove: function(e) {
        var me = this,
            el = me.el,
            over = me.overMenuTrigger,
            overlap, btnSize;

        if (me.split) {
            if (me.arrowAlign === 'right') {
                overlap = e.getX() - el.getX();
                btnSize = el.getWidth();
            } else {
                overlap = e.getY() - el.getY();
                btnSize = el.getHeight();
            }

            if (overlap > (btnSize - me.getTriggerSize())) {
                if (!over) {
                    me.onMenuTriggerOver(e);
                }
            } else {
                if (over) {
                    me.onMenuTriggerOut(e);
                }
            }
        }
    },

    
    getTriggerSize: function() {
        var me = this,
            size = me.triggerSize,
            side, sideFirstLetter, undef;

        if (size === undef) {
            side = me.arrowAlign;
            sideFirstLetter = side.charAt(0);
            size = me.triggerSize = me.el.getFrameWidth(sideFirstLetter) + me.btnWrap.getFrameWidth(sideFirstLetter) + me.frameSize[side];
        }
        return size;
    },

    
    onMouseEnter: function(e) {
        var me = this;
        me.addClsWithUI(me.overCls);
        me.fireEvent('mouseover', me, e);
    },

    
    onMouseLeave: function(e) {
        var me = this;
        me.removeClsWithUI(me.overCls);
        me.fireEvent('mouseout', me, e);
    },

    
    onMenuTriggerOver: function(e) {
        var me = this;
        me.overMenuTrigger = true;
        me.fireEvent('menutriggerover', me, me.menu, e);
    },

    
    onMenuTriggerOut: function(e) {
        var me = this;
        delete me.overMenuTrigger;
        me.fireEvent('menutriggerout', me, me.menu, e);
    },

    
    enable : function(silent) {
        var me = this;

        me.callParent(arguments);

        if (me.btnEl) {
            me.btnEl.dom.disabled = false;
        }
        me.removeClsWithUI('disabled');

        return me;
    },

    
    disable : function(silent) {
        var me = this;

        me.callParent(arguments);

        if (me.btnEl) {
            me.btnEl.dom.disabled = true;
        }
        me.addClsWithUI('disabled');
        me.removeClsWithUI(me.overCls);

        
        
        if (me.btnInnerEl && (Ext.isIE6 || Ext.isIE7)) {
            me.btnInnerEl.repaint();
        }

        return me;
    },

    
    setScale: function(scale) {
        var me = this,
            ui = me.ui.replace('-' + me.scale, '');

        
        if (!Ext.Array.contains(me.allowedScales, scale)) {
            throw('#setScale: scale must be an allowed scale (' + me.allowedScales.join(', ') + ')');
        }

        me.scale = scale;
        me.setUI(ui);
    },

    
    setUI: function(ui) {
        var me = this;

        
        if (me.scale && !ui.match(me.scale)) {
            ui = ui + '-' + me.scale;
        }

        me.callParent([ui]);

        
        
    },

    
    onMouseDown: function(e) {
        var me = this;
        if (!me.disabled && e.button === 0) {
            me.addClsWithUI(me.pressedCls);
            me.doc.on('mouseup', me.onMouseUp, me);
        }
    },
    
    onMouseUp: function(e) {
        var me = this;
        if (e.button === 0) {
            if (!me.pressed) {
                me.removeClsWithUI(me.pressedCls);
            }
            me.doc.un('mouseup', me.onMouseUp, me);
        }
    },
    
    onMenuShow: function(e) {
        var me = this;
        me.ignoreNextClick = 0;
        me.addClsWithUI(me.menuActiveCls);
        me.fireEvent('menushow', me, me.menu);
    },

    
    onMenuHide: function(e) {
        var me = this;
        me.removeClsWithUI(me.menuActiveCls);
        me.ignoreNextClick = Ext.defer(me.restoreClick, 250, me);
        me.fireEvent('menuhide', me, me.menu);
    },

    
    restoreClick: function() {
        this.ignoreNextClick = 0;
    },

    
    onDownKey: function() {
        var me = this;

        if (!me.disabled) {
            if (me.menu) {
                me.showMenu();
            }
        }
    },

    
    getPersistentPadding: function() {
        var me = this,
            reset = Ext.scopeResetCSS,
            padding = me.persistentPadding,
            btn, leftTop, btnEl, btnInnerEl, wrap;

        
        
        if (!padding) {
            padding = me.self.prototype.persistentPadding = [0, 0, 0, 0];
            if (!Ext.isIE) {
                btn = new Ext.button.Button({
                    text: 'test',
                    style: 'position:absolute;top:-999px;'
                });
                btn.el = Ext.DomHelper.append(Ext.resetElement, btn.getRenderTree(), true);
                btn.applyChildEls(btn.el);
                btnEl = btn.btnEl;
                btnInnerEl = btn.btnInnerEl;
                btnEl.setSize(null, null); 
                leftTop = btnInnerEl.getOffsetsTo(btnEl);
                padding[0] = leftTop[1];
                padding[1] = btnEl.getWidth() - btnInnerEl.getWidth() - leftTop[0];
                padding[2] = btnEl.getHeight() - btnInnerEl.getHeight() - leftTop[1];
                padding[3] = leftTop[0];
                
                btn.destroy();
                btn.el.remove();
            }
        }
        return padding;
    }
}, function() {
    var groups = {},
        toggleGroup = function(btn, state) {
            if (state) {
                var g = groups[btn.toggleGroup],
                    length = g.length,
                    i;

                for (i = 0; i < length; i++) {
                    if (g[i] !== btn) {
                        g[i].toggle(false);
                    }
                }
            }
        };

    
    Ext.ButtonToggleManager = {
        register: function(btn) {
            if (!btn.toggleGroup) {
                return;
            }
            var group = groups[btn.toggleGroup];
            if (!group) {
                group = groups[btn.toggleGroup] = [];
            }
            group.push(btn);
            btn.on('toggle', toggleGroup);
        },

        unregister: function(btn) {
            if (!btn.toggleGroup) {
                return;
            }
            var group = groups[btn.toggleGroup];
            if (group) {
                Ext.Array.remove(group, btn);
                btn.un('toggle', toggleGroup);
            }
        },

        
        
        
        getPressed: function(group) {
            var g = groups[group],
                i = 0,
                len;
            if (g) {
                for (len = g.length; i < len; i++) {
                    if (g[i].pressed === true) {
                        return g[i];
                    }
                }
            }
            return null;
        }
    };
});


Ext.define('Ext.button.Split', {

    
    alias: 'widget.splitbutton',

    extend: 'Ext.button.Button',
    alternateClassName: 'Ext.SplitButton',
    
    
    
    

    
    arrowCls      : 'split',
    split         : true,

    
    initComponent : function(){
        this.callParent();
        
        this.addEvents("arrowclick");
    },

    
    setArrowHandler : function(handler, scope){
        this.arrowHandler = handler;
        this.scope = scope;
    },

    
    onClick : function(e, t) {
        var me = this;
        
        e.preventDefault();
        if (!me.disabled) {
            if (me.overMenuTrigger) {
                me.maybeShowMenu();
                me.fireEvent("arrowclick", me, e);
                if (me.arrowHandler) {
                    me.arrowHandler.call(me.scope || me, me, e);
                }
            } else {
                me.doToggle();
                me.fireHandler(e);
            }
        }
    }
});

Ext.define('Ext.button.Cycle', {

    

    alias: 'widget.cycle',

    extend: 'Ext.button.Split',
    alternateClassName: 'Ext.CycleButton',

    

    
    
    
    
    
    

    
    getButtonText: function(item) {
        var me = this,
            text = '';

        if (item && me.showText === true) {
            if (me.prependText) {
                text += me.prependText;
            }
            text += item.text;
            return text;
        }
        return me.text;
    },

    
    setActiveItem: function(item, suppressEvent) {
        var me = this;

        if (!Ext.isObject(item)) {
            item = me.menu.getComponent(item);
        }
        if (item) {
            if (!me.rendered) {
                me.text = me.getButtonText(item);
                me.iconCls = item.iconCls;
            } else {
                me.setText(me.getButtonText(item));
                me.setIconCls(item.iconCls);
            }
            me.activeItem = item;
            if (!item.checked) {
                item.setChecked(true, false);
            }
            if (me.forceIcon) {
                me.setIconCls(me.forceIcon);
            }
            if (!suppressEvent) {
                me.fireEvent('change', me, item);
            }
        }
    },

    
    getActiveItem: function() {
        return this.activeItem;
    },

    
    initComponent: function() {
        var me      = this,
            checked = 0,
            items,
            i, iLen, item;

        me.addEvents(
            
            "change"
        );

        if (me.changeHandler) {
            me.on('change', me.changeHandler, me.scope || me);
            delete me.changeHandler;
        }

        
        
        items = (me.menu.items || []).concat(me.items || []);
        me.menu = Ext.applyIf({
            cls: Ext.baseCSSPrefix + 'cycle-menu',
            items: []
        }, me.menu);

        iLen = items.length;

        
        for (i = 0; i < iLen; i++) {
            item = items[i];

            item = Ext.applyIf({
                group        : me.id,
                itemIndex    : i,
                checkHandler : me.checkHandler,
                scope        : me,
                checked      : item.checked || false
            }, item);

            me.menu.items.push(item);

            if (item.checked) {
                checked = i;
            }
        }

        me.itemCount = me.menu.items.length;
        me.callParent(arguments);
        me.on('click', me.toggleSelected, me);
        me.setActiveItem(checked, me);

        
        if (me.width && me.showText) {
            me.addCls(Ext.baseCSSPrefix + 'cycle-fixed-width');
        }
    },

    
    checkHandler: function(item, pressed) {
        if (pressed) {
            this.setActiveItem(item);
        }
    },

    
    toggleSelected: function() {
        var me = this,
            m = me.menu,
            checkItem;

        checkItem = me.activeItem.next(':not([disabled])') || m.items.getAt(0);
        checkItem.setChecked(true);
    }
});

Ext.define('Ext.menu.Separator', {
    extend: 'Ext.menu.Item',
    alias: 'widget.menuseparator',

    

    
    canActivate: false,

    

    

    

    focusable: false,

    

    

    
    hideOnClick: false,

    

    

    

    

    

    

    
    plain: true,

    
    separatorCls: Ext.baseCSSPrefix + 'menu-item-separator',

    
    text: '&#160;',

    beforeRender: function(ct, pos) {
        var me = this;

        me.callParent();

        me.addCls(me.separatorCls);
    }
});

Ext.define('Ext.panel.DD', {
    extend: 'Ext.dd.DragSource',
    requires: ['Ext.panel.Proxy'],

    constructor : function(panel, cfg){
        var me = this;
        
        me.panel = panel;
        me.dragData = {panel: panel};
        me.panelProxy = new Ext.panel.Proxy(panel, cfg);
        me.proxy = me.panelProxy.proxy;

        me.callParent([panel.el, cfg]);
        me.setupEl(panel);
    },
    
    setupEl: function(panel){
        var me = this,
            header = panel.header,
            el = panel.body;
            
        if (header) {
            me.setHandleElId(header.id);
            el = header.el;
        }
        if (el) {
            el.setStyle('cursor', 'move');
            me.scroll = false;
        } else {
            
            panel.on('boxready', me.setupEl, me, {single: true});
        }
    },

    showFrame: Ext.emptyFn,
    startDrag: Ext.emptyFn,
    
    b4StartDrag: function(x, y) {
        this.panelProxy.show();
    },
    
    b4MouseDown: function(e) {
        var x = e.getPageX(),
            y = e.getPageY();
            
        this.autoOffset(x, y);
    },
    
    onInitDrag : function(x, y){
        this.onStartDrag(x, y);
        return true;
    },
    
    createFrame : Ext.emptyFn,
    
    getDragEl : function(e){
        return this.panelProxy.ghost.el.dom;
    },
    
    endDrag : function(e){
        this.panelProxy.hide();
        this.panel.saveState();
    },

    autoOffset : function(x, y) {
        x -= this.startPageX;
        y -= this.startPageY;
        this.setDelta(x, y);
    },
    
    
    
    onInvalidDrop: function(target, e, id) {
        var me = this;
        
        me.beforeInvalidDrop(target, e, id);
        if (me.cachedTarget) {
            if(me.cachedTarget.isNotifyTarget){
                me.cachedTarget.notifyOut(me, e, me.dragData);
            }
            me.cacheTarget = null;
        }

        if (me.afterInvalidDrop) {
            
            me.afterInvalidDrop(e, id);
        }
    }
});

Ext.define('Ext.panel.Header', {
    extend: 'Ext.container.Container',
    uses: ['Ext.panel.Tool', 'Ext.draw.Component', 'Ext.util.CSS', 'Ext.layout.component.Body', 'Ext.Img'],
    alias: 'widget.header',

    
    isHeader       : true,
    defaultType    : 'tool',
    indicateDrag   : false,
    weight         : -1,
    componentLayout: 'body',

    
    titleAlign: 'left',

    childEls: [
        'body'
    ],

    renderTpl: [
        '<div id="{id}-body" class="{baseCls}-body {bodyCls}',
        '<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl>"',
        '<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',
            '{%this.renderContainer(out,values)%}',
        '</div>'
    ],

    headingTpl: '<span id="{id}-textEl" class="{cls}-text {cls}-text-{ui}">{title}</span>',

    shrinkWrap: 3,

    

    
    
    

    initComponent: function() {
        var me = this,
            ruleStyle,
            rule,
            style,
            ui,
            tempEl;
            
        me.addEvents(
            
            'click',
            
            
            'dblclick'
        );

        me.indicateDragCls = me.baseCls + '-draggable';
        me.title = me.title || '&#160;';
        me.tools = me.tools || [];
        me.items = me.items || [];
        me.orientation = me.orientation || 'horizontal';
        me.dock = (me.dock) ? me.dock : (me.orientation == 'horizontal') ? 'top' : 'left';

        
        
        me.addClsWithUI([me.orientation, me.dock]);

        if (me.indicateDrag) {
            me.addCls(me.indicateDragCls);
        }

        
        if (!Ext.isEmpty(me.iconCls) || !Ext.isEmpty(me.icon)) {
            me.initIconCmp();
            me.items.push(me.iconCmp);
        }

        
        if (me.orientation == 'vertical') {
            me.layout = {
                type : 'vbox',
                align: 'center'
            };
            me.textConfig = {
                width: 16,
                cls: me.baseCls + '-text',
                type: 'text',
                text: me.title,
                rotate: {
                    degrees: 90
                }
            };
            ui = me.ui;
            if (Ext.isArray(ui)) {
                ui = ui[0];
            }
            ruleStyle = '.' + me.baseCls + '-text-' + ui;
            if (Ext.scopeResetCSS) {
                ruleStyle = '.' + Ext.baseCSSPrefix + 'reset ' + ruleStyle;
            }
            rule = Ext.util.CSS.getRule(ruleStyle);

            
            if (rule) {
                style = rule.style;
            } else {
                style = (tempEl = Ext.resetElement.createChild({style: 'position:absolute', cls: me.baseCls + '-text-' + ui})).getStyles('fontFamily', 'fontWeight', 'fontSize', 'color');
                tempEl.remove();
            }
            if (style) {
                Ext.apply(me.textConfig, {
                    'font-family': style.fontFamily,
                    'font-weight': style.fontWeight,
                    'font-size': style.fontSize,
                    fill: style.color
                });
            }
            me.titleCmp = new Ext.draw.Component({
                width     : 16,
                ariaRole  : 'heading',
                focusable : false,
                viewBox   : false,
                flex      : 1,
                id        : me.id + '_hd',
                autoSize  : true,
                items     : me.textConfig,
                xhooks: {
                    setSize: function (width) {
                        
                        this.callParent([width]);
                    }
                },
                
                
                childEls  : [
                    { name: 'textEl', select: '.' + me.baseCls + '-text' }
                ]
            });
        } else {
            me.layout = {
                type : 'hbox',
                align: 'middle'
            };
            me.titleCmp = new Ext.Component({
                ariaRole  : 'heading',
                focusable : false,
                noWrap    : true,
                flex      : 1,
                id        : me.id + '_hd',
                style     : 'text-align:' + me.titleAlign,
                cls       : me.baseCls + '-text-container',
                renderTpl : me.getTpl('headingTpl'),
                renderData: {
                    title: me.title,
                    cls  : me.baseCls,
                    ui   : me.ui
                },
                childEls  : ['textEl']
            });
        }
        me.items.push(me.titleCmp);

        
        me.items = me.items.concat(me.tools);
        me.callParent();
        
        me.on({
            dblclick: me.onDblClick,
            click: me.onClick,
            element: 'el',
            scope: me
        });
    },

    initIconCmp: function() {
        var me = this,
            cfg = {
                focusable: false,
                src: Ext.BLANK_IMAGE_URL,
                cls: [me.baseCls + '-icon', me.iconCls],
                id: me.id + '-iconEl',
                iconCls: me.iconCls
            };
            
        if (!Ext.isEmpty(me.icon)) {
            delete cfg.iconCls;
            cfg.src = me.icon;
        }
        
        me.iconCmp = new Ext.Img(cfg);
    },

    afterRender: function() {
        this.el.unselectable();
        this.callParent();
    },

    
    addUIClsToElement: function(cls) {
        var me = this,
            result = me.callParent(arguments),
            classes = [me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls],
            array, i;

        if (me.bodyCls) {
            array = me.bodyCls.split(' ');

            for (i = 0; i < classes.length; i++) {
                if (!Ext.Array.contains(array, classes[i])) {
                    array.push(classes[i]);
                }
            }

            me.bodyCls = array.join(' ');
        } else {
            me.bodyCls = classes.join(' ');
        }

        return result;
    },

    
    removeUIClsFromElement: function(cls) {
        var me = this,
            result = me.callParent(arguments),
            classes = [me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls],
            array, i;

        if (me.bodyCls) {
            array = me.bodyCls.split(' ');

            for (i = 0; i < classes.length; i++) {
                Ext.Array.remove(array, classes[i]);
            }

            me.bodyCls = array.join(' ');
        }

        return result;
    },

    
    addUIToElement: function() {
        var me = this,
            array, cls;

        me.callParent(arguments);

        cls = me.baseCls + '-body-' + me.ui;
        if (me.rendered) {
            if (me.bodyCls) {
                me.body.addCls(me.bodyCls);
            } else {
                me.body.addCls(cls);
            }
        } else {
            if (me.bodyCls) {
                array = me.bodyCls.split(' ');

                if (!Ext.Array.contains(array, cls)) {
                    array.push(cls);
                }

                me.bodyCls = array.join(' ');
            } else {
                me.bodyCls = cls;
            }
        }

        if (me.titleCmp && me.titleCmp.rendered && me.titleCmp.textEl) {
            me.titleCmp.textEl.addCls(me.baseCls + '-text-' + me.ui);
        }
    },

    
    removeUIFromElement: function() {
        var me = this,
            array, cls;

        me.callParent(arguments);

        cls = me.baseCls + '-body-' + me.ui;
        if (me.rendered) {
            if (me.bodyCls) {
                me.body.removeCls(me.bodyCls);
            } else {
                me.body.removeCls(cls);
            }
        } else {
            if (me.bodyCls) {
                array = me.bodyCls.split(' ');
                Ext.Array.remove(array, cls);
                me.bodyCls = array.join(' ');
            } else {
                me.bodyCls = cls;
            }
        }

        if (me.titleCmp && me.titleCmp.rendered && me.titleCmp.textEl) {
            me.titleCmp.textEl.removeCls(me.baseCls + '-text-' + me.ui);
        }
    },

    onClick: function(e) {
        this.fireClickEvent('click', e);
    },
    
    onDblClick: function(e){
        this.fireClickEvent('dblclick', e);
    },
    
    fireClickEvent: function(type, e){
        var toolCls = '.' + Ext.panel.Tool.prototype.baseCls;
        if (!e.getTarget(toolCls)) {
            this.fireEvent(type, this, e);
        }    
    },

    getFocusEl: function() {
        return this.el;
    },

    getTargetEl: function() {
        return this.body || this.frameBody || this.el;
    },

    
    setTitle: function(title) {
        var me = this,
            sprite,
            surface;
        if (me.rendered) {
            if (me.titleCmp.rendered) {
                if (me.titleCmp.surface) {
                    me.title = title || '';
                    sprite = me.titleCmp.surface.items.items[0];
                    surface = me.titleCmp.surface;

                    surface.remove(sprite);
                    me.textConfig.type = 'text';
                    me.textConfig.text = title;
                    sprite = surface.add(me.textConfig);
                    sprite.setAttributes({
                        rotate: {
                            degrees: 90
                        }
                    }, true);
                    me.titleCmp.autoSizeSurface();
                } else {
                    me.title = title;
                    me.titleCmp.textEl.update(me.title || '&#160;');
                }
                me.titleCmp.updateLayout();
            } else {
                me.titleCmp.on({
                    render: function() {
                        me.setTitle(title);
                    },
                    single: true
                });
            }
        } else {
            me.title = title;
        }
    },

    
    getMinWidth: function() {
        var me = this,
            textEl = me.titleCmp.textEl.dom,
            result,
            tools = me.tools,
            l, i;

        
        textEl.style.display = 'inline';
        result = textEl.offsetWidth;
        textEl.style.display = '';

        
        if (tools && (l = tools.length)) {
            for (i = 0; i < l; i++) {
                if (tools[i].el) {
                    result += tools[i].el.dom.offsetWidth;
                }
            }
        }

        
        if (me.iconCmp) {
            result += me.iconCmp.el.dom.offsetWidth;
        }

        
        return result + 10;
    },

    
    setIconCls: function(cls) {
        var me = this,
            isEmpty = !cls || !cls.length,
            iconCmp = me.iconCmp;
        
        me.iconCls = cls;
        if (!me.iconCmp && !isEmpty) {
            me.initIconCmp();
            me.insert(0, me.iconCmp);
        } else if (iconCmp) {
            if (isEmpty) {
                me.iconCmp.destroy();
                delete me.iconCmp;
            } else {
                iconCmp.removeCls(iconCmp.iconCls);
                iconCmp.addCls(cls);
                iconCmp.iconCls = cls;
            }
        }
    },
    
    
    setIcon: function(icon) {
        var me = this,
            isEmpty = !icon || !icon.length,
            iconCmp = me.iconCmp;
        
        me.icon = icon;
        if (!me.iconCmp && !isEmpty) {
            me.initIconCmp();
            me.insert(0, me.iconCmp);
        } else if (iconCmp) {
            if (isEmpty) {
                me.iconCmp.destroy();
                delete me.iconCmp;
            } else {
                iconCmp.setSrc(me.icon);
            }
        }
    },

    
    addTool: function(tool) {
        this.tools.push(this.add(tool));
    },

    
    onAdd: function(component, index) {
        this.callParent(arguments);
        if (component instanceof Ext.panel.Tool) {
            component.bindTo(this.ownerCt);
            this.tools[component.type] = component;
        }
    },

    
    initRenderData: function() {
        return Ext.applyIf(this.callParent(), {
            bodyCls: this.bodyCls
        });
    }
});


Ext.define('Ext.picker.Color', {
    extend: 'Ext.Component',
    requires: 'Ext.XTemplate',
    alias: 'widget.colorpicker',
    alternateClassName: 'Ext.ColorPalette',

    
    componentCls : Ext.baseCSSPrefix + 'color-picker',

    
    selectedCls: Ext.baseCSSPrefix + 'color-picker-selected',

    
    value : null,

    
    clickEvent :'click',

    
    allowReselect : false,

    
    colors : [
        '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
        '800000', 'FF6600', '808000', '008000', '008080', '0000FF', '666699', '808080',
        'FF0000', 'FF9900', '99CC00', '339966', '33CCCC', '3366FF', '800080', '969696',
        'FF00FF', 'FFCC00', 'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0',
        'FF99CC', 'FFCC99', 'FFFF99', 'CCFFCC', 'CCFFFF', '99CCFF', 'CC99FF', 'FFFFFF'
    ],

    

    

    colorRe: /(?:^|\s)color-(.{6})(?:\s|$)/,
    
    renderTpl: [
        '<tpl for="colors">',
            '<a href="#" class="color-{.}" hidefocus="on">',
                '<em><span style="background:#{.}" unselectable="on">&#160;</span></em>',
            '</a>',
        '</tpl>'
    ],

    
    initComponent : function(){
        var me = this;

        me.callParent(arguments);
        me.addEvents(
            
            'select'
        );

        if (me.handler) {
            me.on('select', me.handler, me.scope, true);
        }
    },


    
    initRenderData : function(){
        var me = this;
        return Ext.apply(me.callParent(), {
            itemCls: me.itemCls,
            colors: me.colors
        });
    },

    onRender : function(){
        var me = this,
            clickEvent = me.clickEvent;

        me.callParent(arguments);

        me.mon(me.el, clickEvent, me.handleClick, me, {delegate: 'a'});
        
        if(clickEvent != 'click'){
            me.mon(me.el, 'click', Ext.emptyFn, me, {delegate: 'a', stopEvent: true});
        }
    },

    
    afterRender : function(){
        var me = this,
            value;

        me.callParent(arguments);
        if (me.value) {
            value = me.value;
            me.value = null;
            me.select(value, true);
        }
    },

    
    handleClick : function(event, target){
        var me = this,
            color;

        event.stopEvent();
        if (!me.disabled) {
            color = target.className.match(me.colorRe)[1];
            me.select(color.toUpperCase());
        }
    },

    
    select : function(color, suppressEvent){

        var me = this,
            selectedCls = me.selectedCls,
            value = me.value,
            el;

        color = color.replace('#', '');
        if (!me.rendered) {
            me.value = color;
            return;
        }


        if (color != value || me.allowReselect) {
            el = me.el;

            if (me.value) {
                el.down('a.color-' + value).removeCls(selectedCls);
            }
            el.down('a.color-' + color).addCls(selectedCls);
            me.value = color;
            if (suppressEvent !== true) {
                me.fireEvent('select', me, color);
            }
        }
    },

    
    getValue: function(){
        return this.value || null;
    }
});


Ext.define('Ext.picker.Month', {
    extend: 'Ext.Component',
    requires: [
        'Ext.XTemplate', 
        'Ext.util.ClickRepeater', 
        'Ext.Date', 
        'Ext.button.Button'
    ],
    alias: 'widget.monthpicker',
    alternateClassName: 'Ext.MonthPicker',

    childEls: [
        'bodyEl', 'prevEl', 'nextEl', 'buttonsEl', 'monthEl', 'yearEl'
    ],

    renderTpl: [
        '<div id="{id}-bodyEl" class="{baseCls}-body">',
          '<div id="{id}-monthEl" class="{baseCls}-months">',
              '<tpl for="months">',
                  '<div class="{parent.baseCls}-item {parent.baseCls}-month"><a style="{parent.monthStyle}" href="#" hidefocus="on">{.}</a></div>',
              '</tpl>',
          '</div>',
          '<div id="{id}-yearEl" class="{baseCls}-years">',
              '<div class="{baseCls}-yearnav">',
                  '<button id="{id}-prevEl" class="{baseCls}-yearnav-prev"></button>',
                  '<button id="{id}-nextEl" class="{baseCls}-yearnav-next"></button>',
              '</div>',
              '<tpl for="years">',
                  '<div class="{parent.baseCls}-item {parent.baseCls}-year"><a href="#" hidefocus="on">{.}</a></div>',
              '</tpl>',
          '</div>',
          '<div class="' + Ext.baseCSSPrefix + 'clear"></div>',
        '</div>',
        '<tpl if="showButtons">',
            '<div id="{id}-buttonsEl" class="{baseCls}-buttons">{%',
                'var me=values.$comp, okBtn=me.okBtn, cancelBtn=me.cancelBtn;',
                'okBtn.ownerLayout = cancelBtn.ownerLayout = me.componentLayout;',
                'okBtn.ownerCt = cancelBtn.ownerCt = me;',
                'Ext.DomHelper.generateMarkup(okBtn.getRenderTree(), out);',
                'Ext.DomHelper.generateMarkup(cancelBtn.getRenderTree(), out);',
            '%}</div>',
        '</tpl>'
    ],

    
    
    okText: 'OK',
    

    
    
    cancelText: 'Cancel',
    

    
    baseCls: Ext.baseCSSPrefix + 'monthpicker',

    
    showButtons: true,

    

    
    
    
    width: 178,
    measureWidth: 35,
    measureMaxHeight: 20,

    
    smallCls: Ext.baseCSSPrefix + 'monthpicker-small',

    
    totalYears: 10,
    yearOffset: 5, 
    monthOffset: 6, 

    
    initComponent: function(){
        var me = this;

        me.selectedCls = me.baseCls + '-selected';
        me.addEvents(
            
            'cancelclick',

            
            'monthclick',

            
            'monthdblclick',

            
            'okclick',

            
            'select',

            
            'yearclick',

            
            'yeardblclick'
        );
        if (me.small) {
            me.addCls(me.smallCls);
        }
        me.setValue(me.value);
        me.activeYear = me.getYear(new Date().getFullYear() - 4, -4);

        if (me.showButtons) {
            me.okBtn = new Ext.button.Button({
                text: me.okText,
                handler: me.onOkClick,
                scope: me
            });
            me.cancelBtn = new Ext.button.Button({
                text: me.cancelText,
                handler: me.onCancelClick,
                scope: me
            });
        }

        this.callParent();
    },

    
    beforeRender: function(){
        var me = this,
            i = 0,
            months = [],
            shortName = Ext.Date.getShortMonthName,
            monthLen = me.monthOffset,
            margin = me.monthMargin,
            style = '';

        me.callParent();

        for (; i < monthLen; ++i) {
            months.push(shortName(i), shortName(i + monthLen));
        }
        
        if (Ext.isDefined(margin)) {
            style = 'margin: 0 ' + margin + 'px;';
        }

        Ext.apply(me.renderData, {
            months: months,
            years: me.getYears(),
            showButtons: me.showButtons,
            monthStyle: style
        });
    },

    
    afterRender: function(){
        var me = this,
            body = me.bodyEl,
            buttonsEl = me.buttonsEl;

        me.callParent();

        me.mon(body, 'click', me.onBodyClick, me);
        me.mon(body, 'dblclick', me.onBodyClick, me);

        
        me.years = body.select('.' + me.baseCls + '-year a');
        me.months = body.select('.' + me.baseCls + '-month a');

        me.backRepeater = new Ext.util.ClickRepeater(me.prevEl, {
            handler: Ext.Function.bind(me.adjustYear, me, [-me.totalYears])
        });

        me.prevEl.addClsOnOver(me.baseCls + '-yearnav-prev-over');
        me.nextRepeater = new Ext.util.ClickRepeater(me.nextEl, {
            handler: Ext.Function.bind(me.adjustYear, me, [me.totalYears])
        });
        me.nextEl.addClsOnOver(me.baseCls + '-yearnav-next-over');
        me.updateBody();
        
        if (!Ext.isDefined(me.monthMargin)) {
            Ext.picker.Month.prototype.monthMargin = me.calculateMonthMargin();
        }
    },
    
    calculateMonthMargin: function(){
        
        
        
        
        var me = this,
            monthEl = me.monthEl,
            months = me.months,
            first = months.first(),
            itemMargin = first.getMargin('l');
            
        while (itemMargin && me.getLargest() > me.measureMaxHeight) {
            --itemMargin;
            months.setStyle('margin', '0 ' + itemMargin + 'px');
        }
        return itemMargin;
    },
    
    getLargest: function(months){
        var largest = 0;
        this.months.each(function(item){
            var h = item.getHeight();
            if (h > largest) {
                largest = h;
            }
        });
        return largest;
        
    },

    
    setValue: function(value){
        var me = this,
            active = me.activeYear,
            offset = me.monthOffset,
            year,
            index;

        if (!value) {
            me.value = [null, null];
        } else if (Ext.isDate(value)) {
            me.value = [value.getMonth(), value.getFullYear()];
        } else {
            me.value = [value[0], value[1]];
        }

        if (me.rendered) {
            year = me.value[1];
            if (year !== null) {
                if ((year < active || year > active + me.yearOffset)) {
                    me.activeYear = year - me.yearOffset + 1;
                }
            }
            me.updateBody();
        }

        return me;
    },

    
    getValue: function(){
        return this.value;
    },

    
    hasSelection: function(){
        var value = this.value;
        return value[0] !== null && value[1] !== null;
    },

    
    getYears: function(){
        var me = this,
            offset = me.yearOffset,
            start = me.activeYear, 
            end = start + offset,
            i = start,
            years = [];

        for (; i < end; ++i) {
            years.push(i, i + offset);
        }

        return years;
    },

    
    updateBody: function(){
        var me = this,
            years = me.years,
            months = me.months,
            yearNumbers = me.getYears(),
            cls = me.selectedCls,
            value = me.getYear(null),
            month = me.value[0],
            monthOffset = me.monthOffset,
            year,
            yearItems, y, yLen, el;

        if (me.rendered) {
            years.removeCls(cls);
            months.removeCls(cls);

            yearItems = years.elements;
            yLen      = yearItems.length;

            for (y = 0; y < yLen; y++) {
                el = Ext.fly(yearItems[y]);

                year = yearNumbers[y];
                el.dom.innerHTML = year;
                if (year == value) {
                    el.dom.className = cls;
                }
            }
            if (month !== null) {
                if (month < monthOffset) {
                    month = month * 2;
                } else {
                    month = (month - monthOffset) * 2 + 1;
                }
                months.item(month).addCls(cls);
            }
        }
    },

    
    getYear: function(defaultValue, offset) {
        var year = this.value[1];
        offset = offset || 0;
        return year === null ? defaultValue : year + offset;
    },

    
    onBodyClick: function(e, t) {
        var me = this,
            isDouble = e.type == 'dblclick';

        if (e.getTarget('.' + me.baseCls + '-month')) {
            e.stopEvent();
            me.onMonthClick(t, isDouble);
        } else if (e.getTarget('.' + me.baseCls + '-year')) {
            e.stopEvent();
            me.onYearClick(t, isDouble);
        }
    },

    
    adjustYear: function(offset){
        if (typeof offset != 'number') {
            offset = this.totalYears;
        }
        this.activeYear += offset;
        this.updateBody();
    },

    
    onOkClick: function(){
        this.fireEvent('okclick', this, this.value);
    },

    
    onCancelClick: function(){
        this.fireEvent('cancelclick', this);
    },

    
    onMonthClick: function(target, isDouble){
        var me = this;
        me.value[0] = me.resolveOffset(me.months.indexOf(target), me.monthOffset);
        me.updateBody();
        me.fireEvent('month' + (isDouble ? 'dbl' : '') + 'click', me, me.value);
        me.fireEvent('select', me, me.value);
    },

    
    onYearClick: function(target, isDouble){
        var me = this;
        me.value[1] = me.activeYear + me.resolveOffset(me.years.indexOf(target), me.yearOffset);
        me.updateBody();
        me.fireEvent('year' + (isDouble ? 'dbl' : '') + 'click', me, me.value);
        me.fireEvent('select', me, me.value);

    },

    
    resolveOffset: function(index, offset){
        if (index % 2 === 0) {
            return (index / 2);
        } else {
            return offset + Math.floor(index / 2);
        }
    },

    
    beforeDestroy: function(){
        var me = this;
        me.years = me.months = null;
        Ext.destroyMembers(me, 'backRepeater', 'nextRepeater', 'okBtn', 'cancelBtn');
        me.callParent();
    },

    
    
    finishRenderChildren: function () {
        var me = this;

        this.callParent(arguments);

        if (this.showButtons) {
            me.okBtn.finishRender();
            me.cancelBtn.finishRender();
        }
    },

    onDestroy: function() {
        Ext.destroyMembers(this, 'okBtn', 'cancelBtn');
        this.callParent();
    }
    
});


Ext.define('Ext.picker.Date', {
    extend: 'Ext.Component',
    requires: [
        'Ext.XTemplate',
        'Ext.button.Button',
        'Ext.button.Split',
        'Ext.util.ClickRepeater',
        'Ext.util.KeyNav',
        'Ext.EventObject',
        'Ext.fx.Manager',
        'Ext.picker.Month'
    ],
    alias: 'widget.datepicker',
    alternateClassName: 'Ext.DatePicker',

    childEls: [
        'innerEl', 'eventEl', 'prevEl', 'nextEl', 'middleBtnEl', 'footerEl'
    ],
    
    border: true,

    renderTpl: [
        '<div id="{id}-innerEl" role="grid">',
            '<div role="presentation" class="{baseCls}-header">',
                '<div class="{baseCls}-prev"><a id="{id}-prevEl" href="#" role="button" title="{prevText}"></a></div>',
                '<div class="{baseCls}-month" id="{id}-middleBtnEl">{%this.renderMonthBtn(values, out)%}</div>',
                '<div class="{baseCls}-next"><a id="{id}-nextEl" href="#" role="button" title="{nextText}"></a></div>',
            '</div>',
            '<table id="{id}-eventEl" class="{baseCls}-inner" cellspacing="0" role="presentation">',
                '<thead role="presentation"><tr role="presentation">',
                    '<tpl for="dayNames">',
                        '<th role="columnheader" title="{.}"><span>{.:this.firstInitial}</span></th>',
                    '</tpl>',
                '</tr></thead>',
                '<tbody role="presentation"><tr role="presentation">',
                    '<tpl for="days">',
                        '{#:this.isEndOfWeek}',
                        '<td role="gridcell" id="{[Ext.id()]}">',
                            '<a role="presentation" href="#" hidefocus="on" class="{parent.baseCls}-date" tabIndex="1">',
                                '<em role="presentation"><span role="presentation"></span></em>',
                            '</a>',
                        '</td>',
                    '</tpl>',
                '</tr></tbody>',
            '</table>',
            '<tpl if="showToday">',
                '<div id="{id}-footerEl" role="presentation" class="{baseCls}-footer">{%this.renderTodayBtn(values, out)%}</div>',
            '</tpl>',
        '</div>',
        {
            firstInitial: function(value) {
                return Ext.picker.Date.prototype.getDayInitial(value);
            },
            isEndOfWeek: function(value) {
                
                
                value--;
                var end = value % 7 === 0 && value !== 0;
                return end ? '</tr><tr role="row">' : '';
            },
            renderTodayBtn: function(values, out) {
                Ext.DomHelper.generateMarkup(values.$comp.todayBtn.getRenderTree(), out);
            },
            renderMonthBtn: function(values, out) {
                Ext.DomHelper.generateMarkup(values.$comp.monthBtn.getRenderTree(), out);
            }
        }
    ],

    
    
    todayText : 'Today',
    
    
    
    
    ariaTitle: 'Date Picker: {0}',
    
    
    
    
    ariaTitleDateFormat: 'F d, Y',
    

    

    

    
    
    todayTip : '{0} (Spacebar)',
    

    
    
    minText : 'This date is before the minimum date',
    

    
    
    maxText : 'This date is after the maximum date',
    

    

    
    
    disabledDaysText : 'Disabled',
    

    
    
    disabledDatesText : 'Disabled',
    

    

    

    
    
    nextText : 'Next Month (Control+Right)',
    

    
    
    prevText : 'Previous Month (Control+Left)',
    

    
    
    monthYearText : 'Choose a month (Control+Up/Down to move years)',
    
    
    
    
    monthYearFormat: 'F Y',
    

    
    
    startDay : 0,
    

    
    
    showToday : true,
    

    

    

    

    

    

    
    disableAnim: false,

    
    baseCls: Ext.baseCSSPrefix + 'datepicker',

    

    

    
    
    longDayFormat: 'F d, Y',
    

    

    
    focusOnShow: false,

    
    
    focusOnSelect: true,

    width: 178,

    
    
    initHour: 12, 

    numDays: 42,

    
    initComponent : function() {
        var me = this,
            clearTime = Ext.Date.clearTime;

        me.selectedCls = me.baseCls + '-selected';
        me.disabledCellCls = me.baseCls + '-disabled';
        me.prevCls = me.baseCls + '-prevday';
        me.activeCls = me.baseCls + '-active';
        me.nextCls = me.baseCls + '-prevday';
        me.todayCls = me.baseCls + '-today';
        me.dayNames = me.dayNames.slice(me.startDay).concat(me.dayNames.slice(0, me.startDay));

        me.listeners = Ext.apply(me.listeners||{}, {
            mousewheel: {
                element: 'eventEl',
                fn: me.handleMouseWheel,
                scope: me
            },
            click: {
                element: 'eventEl',
                fn: me.handleDateClick, 
                scope: me,
                delegate: 'a.' + me.baseCls + '-date'
            }
        });
        this.callParent();

        me.value = me.value ?
                 clearTime(me.value, true) : clearTime(new Date());

        me.addEvents(
            
            'select'
        );

        me.initDisabledDays();
    },

    beforeRender: function () {
        
        var me = this,
            days = new Array(me.numDays),
            today = Ext.Date.format(new Date(), me.format);

        
        
        if (me.up('menu')) {
            me.addCls(Ext.baseCSSPrefix + 'menu');
        }

        me.monthBtn = new Ext.button.Split({
            ownerCt: me,
            ownerLayout: me.getComponentLayout(),
            text: '',
            tooltip: me.monthYearText,
            listeners: {
                click: me.showMonthPicker,
                arrowclick: me.showMonthPicker,
                scope: me
            }
        });

        if (this.showToday) {
            me.todayBtn = new Ext.button.Button({
                ownerCt: me,
                ownerLayout: me.getComponentLayout(),
                text: Ext.String.format(me.todayText, today),
                tooltip: Ext.String.format(me.todayTip, today),
                tooltipType: 'title',
                handler: me.selectToday,
                scope: me
            });
        }

        me.callParent();

        Ext.applyIf(me, {
            renderData: {}
        });

        Ext.apply(me.renderData, {
            dayNames: me.dayNames,
            showToday: me.showToday,
            prevText: me.prevText,
            nextText: me.nextText,
            days: days
        });
    },

    
    
    finishRenderChildren: function () {
        var me = this;
        
        me.callParent();
        me.monthBtn.finishRender();
        if (me.showToday) {
            me.todayBtn.finishRender();
        }
    },

    
    onRender : function(container, position){
        var me = this;

        me.callParent(arguments);
        me.el.unselectable();
        me.cells = me.eventEl.select('tbody td');
        me.textNodes = me.eventEl.query('tbody td span');
    },

    
    initEvents: function(){
        var me = this,
            eDate = Ext.Date,
            day = eDate.DAY;

        me.callParent();

        me.prevRepeater = new Ext.util.ClickRepeater(me.prevEl, {
            handler: me.showPrevMonth,
            scope: me,
            preventDefault: true,
            stopDefault: true
        });

        me.nextRepeater = new Ext.util.ClickRepeater(me.nextEl, {
            handler: me.showNextMonth,
            scope: me,
            preventDefault:true,
            stopDefault:true
        });

        me.keyNav = new Ext.util.KeyNav(me.eventEl, Ext.apply({
            scope: me,
            left : function(e){
                if(e.ctrlKey){
                    me.showPrevMonth();
                }else{
                    me.update(eDate.add(me.activeDate, day, -1));
                }
            },

            right : function(e){
                if(e.ctrlKey){
                    me.showNextMonth();
                }else{
                    me.update(eDate.add(me.activeDate, day, 1));
                }
            },

            up : function(e){
                if(e.ctrlKey){
                    me.showNextYear();
                }else{
                    me.update(eDate.add(me.activeDate, day, -7));
                }
            },

            down : function(e){
                if(e.ctrlKey){
                    me.showPrevYear();
                }else{
                    me.update(eDate.add(me.activeDate, day, 7));
                }
            },
            pageUp : me.showNextMonth,
            pageDown : me.showPrevMonth,
            enter : function(e){
                e.stopPropagation();
                return true;
            }
        }, me.keyNavConfig));

        if (me.showToday) {
            me.todayKeyListener = me.eventEl.addKeyListener(Ext.EventObject.SPACE, me.selectToday,  me);
        }
        me.update(me.value);
    },

    
    initDisabledDays : function(){
        var me = this,
            dd = me.disabledDates,
            re = '(?:',
            len,
            d, dLen, dI;

        if(!me.disabledDatesRE && dd){
                len = dd.length - 1;

            dLen = dd.length;

            for (d = 0; d < dLen; d++) {
                dI = dd[d];

                re += Ext.isDate(dI) ? '^' + Ext.String.escapeRegex(Ext.Date.dateFormat(dI, me.format)) + '$' : dI;
                if (d != len) {
                    re += '|';
                }
            }

            me.disabledDatesRE = new RegExp(re + ')');
        }
    },

    
    setDisabledDates : function(dd){
        var me = this;

        if(Ext.isArray(dd)){
            me.disabledDates = dd;
            me.disabledDatesRE = null;
        }else{
            me.disabledDatesRE = dd;
        }
        me.initDisabledDays();
        me.update(me.value, true);
        return me;
    },

    
    setDisabledDays : function(dd){
        this.disabledDays = dd;
        return this.update(this.value, true);
    },

    
    setMinDate : function(dt){
        this.minDate = dt;
        return this.update(this.value, true);
    },

    
    setMaxDate : function(dt){
        this.maxDate = dt;
        return this.update(this.value, true);
    },

    
    setValue : function(value){
        this.value = Ext.Date.clearTime(value, true);
        return this.update(this.value);
    },

    
    getValue : function(){
        return this.value;
    },

    
    
    getDayInitial: function(value){
        return value.substr(0,1);
    },
    

    
    focus : function(){
        this.update(this.activeDate);
    },

    
    onEnable: function(){
        this.callParent();
        this.setDisabledStatus(false);
        this.update(this.activeDate);

    },

    
    onDisable : function(){
        this.callParent();
        this.setDisabledStatus(true);
    },

    
    setDisabledStatus : function(disabled){
        var me = this;

        me.keyNav.setDisabled(disabled);
        me.prevRepeater.setDisabled(disabled);
        me.nextRepeater.setDisabled(disabled);
        if (me.showToday) {
            me.todayKeyListener.setDisabled(disabled);
            me.todayBtn.setDisabled(disabled);
        }
    },

    
    getActive: function(){
        return this.activeDate || this.value;
    },

    
    runAnimation: function(isHide){
        var picker = this.monthPicker,
            options = {
                duration: 200,
                callback: function(){
                    if (isHide) {
                        picker.hide();
                    } else {
                        picker.show();
                    }
                }
            };

        if (isHide) {
            picker.el.slideOut('t', options);
        } else {
            picker.el.slideIn('t', options);
        }
    },

    
    hideMonthPicker : function(animate){
        var me = this,
            picker = me.monthPicker;

        if (picker) {
            if (me.shouldAnimate(animate)) {
                me.runAnimation(true);
            } else {
                picker.hide();
            }
        }
        return me;
    },

    
    showMonthPicker : function(animate){
        var me = this,
            picker;
        
        if (me.rendered && !me.disabled) {
            picker = me.createMonthPicker();
            picker.setValue(me.getActive());
            picker.setSize(me.getSize());
            picker.setPosition(-1, -1);
            if (me.shouldAnimate(animate)) {
                me.runAnimation(false);
            } else {
                picker.show();
            }
        }
        return me;
    },
    
    
    shouldAnimate: function(animate){
        return Ext.isDefined(animate) ? animate : !this.disableAnim;
    },

    
    createMonthPicker: function(){
        var me = this,
            picker = me.monthPicker;

        if (!picker) {
            me.monthPicker = picker = new Ext.picker.Month({
                renderTo: me.el,
                floating: true,
                shadow: false,
                small: me.showToday === false,
                listeners: {
                    scope: me,
                    cancelclick: me.onCancelClick,
                    okclick: me.onOkClick,
                    yeardblclick: me.onOkClick,
                    monthdblclick: me.onOkClick
                }
            });
            if (!me.disableAnim) {
                
                picker.el.setStyle('display', 'none');
            }
            me.on('beforehide', Ext.Function.bind(me.hideMonthPicker, me, [false]));
        }
        return picker;
    },

    
    onOkClick: function(picker, value){
        var me = this,
            month = value[0],
            year = value[1],
            date = new Date(year, month, me.getActive().getDate());

        if (date.getMonth() !== month) {
            
            date = Ext.Date.getLastDateOfMonth(new Date(year, month, 1));
        }
        me.update(date);
        me.hideMonthPicker();
    },

    
    onCancelClick: function(){
        
        this.selectedUpdate(this.activeDate);
        this.hideMonthPicker();
    },

    
    showPrevMonth : function(e){
        return this.update(Ext.Date.add(this.activeDate, Ext.Date.MONTH, -1));
    },

    
    showNextMonth : function(e){
        return this.update(Ext.Date.add(this.activeDate, Ext.Date.MONTH, 1));
    },

    
    showPrevYear : function(){
        this.update(Ext.Date.add(this.activeDate, Ext.Date.YEAR, -1));
    },

    
    showNextYear : function(){
        this.update(Ext.Date.add(this.activeDate, Ext.Date.YEAR, 1));
    },

    
    handleMouseWheel : function(e){
        e.stopEvent();
        if(!this.disabled){
            var delta = e.getWheelDelta();
            if(delta > 0){
                this.showPrevMonth();
            } else if(delta < 0){
                this.showNextMonth();
            }
        }
    },

    
    handleDateClick : function(e, t){
        var me = this,
            handler = me.handler;

        e.stopEvent();
        if(!me.disabled && t.dateValue && !Ext.fly(t.parentNode).hasCls(me.disabledCellCls)){
            me.doCancelFocus = me.focusOnSelect === false;
            me.setValue(new Date(t.dateValue));
            delete me.doCancelFocus;
            me.fireEvent('select', me, me.value);
            if (handler) {
                handler.call(me.scope || me, me, me.value);
            }
            
            
            
            
            me.onSelect();
        }
    },

    
    onSelect: function() {
        if (this.hideOnSelect) {
             this.hide();
         }
    },

    
    selectToday : function(){
        var me = this,
            btn = me.todayBtn,
            handler = me.handler;

        if(btn && !btn.disabled){
            me.setValue(Ext.Date.clearTime(new Date()));
            me.fireEvent('select', me, me.value);
            if (handler) {
                handler.call(me.scope || me, me, me.value);
            }
            me.onSelect();
        }
        return me;
    },

    
    selectedUpdate: function(date){
        var me        = this,
            t         = date.getTime(),
            cells     = me.cells,
            cls       = me.selectedCls,
            cellItems = cells.elements,
            c,
            cLen      = cellItems.length,
            cell;

        cells.removeCls(cls);

        for (c = 0; c < cLen; c++) {
            cell = Ext.fly(cellItems[c]);

            if (cell.dom.firstChild.dateValue == t) {
                me.fireEvent('highlightitem', me, cell);
                cell.addCls(cls);

                if(me.isVisible() && !me.doCancelFocus){
                    Ext.fly(cell.dom.firstChild).focus(50);
                }

                break;
            }
        }
    },

    
    fullUpdate: function(date){
        var me = this,
            cells = me.cells.elements,
            textNodes = me.textNodes,
            disabledCls = me.disabledCellCls,
            eDate = Ext.Date,
            i = 0,
            extraDays = 0,
            visible = me.isVisible(),
            sel = +eDate.clearTime(date, true),
            today = +eDate.clearTime(new Date()),
            min = me.minDate ? eDate.clearTime(me.minDate, true) : Number.NEGATIVE_INFINITY,
            max = me.maxDate ? eDate.clearTime(me.maxDate, true) : Number.POSITIVE_INFINITY,
            ddMatch = me.disabledDatesRE,
            ddText = me.disabledDatesText,
            ddays = me.disabledDays ? me.disabledDays.join('') : false,
            ddaysText = me.disabledDaysText,
            format = me.format,
            days = eDate.getDaysInMonth(date),
            firstOfMonth = eDate.getFirstDateOfMonth(date),
            startingPos = firstOfMonth.getDay() - me.startDay,
            previousMonth = eDate.add(date, eDate.MONTH, -1),
            longDayFormat = me.longDayFormat,
            prevStart,
            current,
            disableToday,
            tempDate,
            setCellClass,
            html,
            cls,
            formatValue,
            value;

        if (startingPos < 0) {
            startingPos += 7;
        }

        days += startingPos;
        prevStart = eDate.getDaysInMonth(previousMonth) - startingPos;
        current = new Date(previousMonth.getFullYear(), previousMonth.getMonth(), prevStart, me.initHour);

        if (me.showToday) {
            tempDate = eDate.clearTime(new Date());
            disableToday = (tempDate < min || tempDate > max ||
                (ddMatch && format && ddMatch.test(eDate.dateFormat(tempDate, format))) ||
                (ddays && ddays.indexOf(tempDate.getDay()) != -1));

            if (!me.disabled) {
                me.todayBtn.setDisabled(disableToday);
                me.todayKeyListener.setDisabled(disableToday);
            }
        }

        setCellClass = function(cell){
            value = +eDate.clearTime(current, true);
            cell.title = eDate.format(current, longDayFormat);
            
            cell.firstChild.dateValue = value;
            if(value == today){
                cell.className += ' ' + me.todayCls;
                cell.title = me.todayText;
            }
            if(value == sel){
                cell.className += ' ' + me.selectedCls;
                me.fireEvent('highlightitem', me, cell);
                if (visible && me.floating) {
                    Ext.fly(cell.firstChild).focus(50);
                }
            }
            
            if(value < min) {
                cell.className = disabledCls;
                cell.title = me.minText;
                return;
            }
            if(value > max) {
                cell.className = disabledCls;
                cell.title = me.maxText;
                return;
            }
            if(ddays){
                if(ddays.indexOf(current.getDay()) != -1){
                    cell.title = ddaysText;
                    cell.className = disabledCls;
                }
            }
            if(ddMatch && format){
                formatValue = eDate.dateFormat(current, format);
                if(ddMatch.test(formatValue)){
                    cell.title = ddText.replace('%0', formatValue);
                    cell.className = disabledCls;
                }
            }
        };

        for(; i < me.numDays; ++i) {
            if (i < startingPos) {
                html = (++prevStart);
                cls = me.prevCls;
            } else if (i >= days) {
                html = (++extraDays);
                cls = me.nextCls;
            } else {
                html = i - startingPos + 1;
                cls = me.activeCls;
            }
            textNodes[i].innerHTML = html;
            cells[i].className = cls;
            current.setDate(current.getDate() + 1);
            setCellClass(cells[i]);
        }

        me.monthBtn.setText(Ext.Date.format(date, me.monthYearFormat));
    },

    
    update : function(date, forceRefresh){
        var me = this,
            active = me.activeDate;

        if (me.rendered) {
            me.activeDate = date;
            if(!forceRefresh && active && me.el && active.getMonth() == date.getMonth() && active.getFullYear() == date.getFullYear()){
                me.selectedUpdate(date, active);
            } else {
                me.fullUpdate(date, active);
            }
            me.innerEl.dom.title = Ext.String.format(me.ariaTitle, Ext.Date.format(me.activeDate, me.ariaTitleDateFormat));
        }
        return me;
    },

    
    beforeDestroy : function() {
        var me = this;

        if (me.rendered) {
            Ext.destroy(
                me.todayKeyListener,
                me.keyNav,
                me.monthPicker,
                me.monthBtn,
                me.nextRepeater,
                me.prevRepeater,
                me.todayBtn
            );
            delete me.textNodes;
            delete me.cells.elements;
        }
        me.callParent();
    },

    
    onShow: function() {
        this.callParent(arguments);
        if (this.focusOnShow) {
            this.focus();
        }
    }
},


function() {
    var proto = this.prototype,
        date = Ext.Date;

    proto.monthNames = date.monthNames;
    proto.dayNames   = date.dayNames;
    proto.format     = date.defaultFormat;
});


Ext.define('Ext.form.field.Date', {
    extend:'Ext.form.field.Picker',
    alias: 'widget.datefield',
    requires: ['Ext.picker.Date'],
    alternateClassName: ['Ext.form.DateField', 'Ext.form.Date'],

    
    
    format : "m/d/Y",
    
    
    
    altFormats : "m/d/Y|n/j/Y|n/j/y|m/j/y|n/d/y|m/j/Y|n/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d|Y-m-d|n-j|n/j",
    
    
    
    disabledDaysText : "Disabled",
    
    
    
    disabledDatesText : "Disabled",
    
    
    
    minText : "The date in this field must be equal to or after {0}",
    
    
    
    maxText : "The date in this field must be equal to or before {0}",
    
    
    
    invalidText : "{0} is not a valid date - it must be in the format {1}",
    
    
    triggerCls : Ext.baseCSSPrefix + 'form-date-trigger',
    
    showToday : true,
    
    
    
    

    
    
    
    useStrict: undefined,

    
    
    initTime: '12', 

    initTimeFormat: 'H',

    matchFieldWidth: false,
    
    
    startDay: 0,
    

    initComponent : function(){
        var me = this,
            isString = Ext.isString,
            min, max;

        min = me.minValue;
        max = me.maxValue;
        if(isString(min)){
            me.minValue = me.parseDate(min);
        }
        if(isString(max)){
            me.maxValue = me.parseDate(max);
        }
        me.disabledDatesRE = null;
        me.initDisabledDays();

        me.callParent();
    },

    initValue: function() {
        var me = this,
            value = me.value;

        
        if (Ext.isString(value)) {
            me.value = me.rawToValue(value);
        }

        me.callParent();
    },

    
    initDisabledDays : function(){
        if(this.disabledDates){
            var dd   = this.disabledDates,
                len  = dd.length - 1,
                re   = "(?:",
                d,
                dLen = dd.length,
                date;

            for (d = 0; d < dLen; d++) {
                date = dd[d];

                re += Ext.isDate(date) ? '^' + Ext.String.escapeRegex(date.dateFormat(this.format)) + '$' : date;
                if (d !== len) {
                    re += '|';
                }
            }

            this.disabledDatesRE = new RegExp(re + ')');
        }
    },

    
    setDisabledDates : function(dd){
        var me = this,
            picker = me.picker;

        me.disabledDates = dd;
        me.initDisabledDays();
        if (picker) {
            picker.setDisabledDates(me.disabledDatesRE);
        }
    },

    
    setDisabledDays : function(dd){
        var picker = this.picker;

        this.disabledDays = dd;
        if (picker) {
            picker.setDisabledDays(dd);
        }
    },

    
    setMinValue : function(dt){
        var me = this,
            picker = me.picker,
            minValue = (Ext.isString(dt) ? me.parseDate(dt) : dt);

        me.minValue = minValue;
        if (picker) {
            picker.minText = Ext.String.format(me.minText, me.formatDate(me.minValue));
            picker.setMinDate(minValue);
        }
    },

    
    setMaxValue : function(dt){
        var me = this,
            picker = me.picker,
            maxValue = (Ext.isString(dt) ? me.parseDate(dt) : dt);

        me.maxValue = maxValue;
        if (picker) {
            picker.maxText = Ext.String.format(me.maxText, me.formatDate(me.maxValue));
            picker.setMaxDate(maxValue);
        }
    },

    
    getErrors: function(value) {
        var me = this,
            format = Ext.String.format,
            clearTime = Ext.Date.clearTime,
            errors = me.callParent(arguments),
            disabledDays = me.disabledDays,
            disabledDatesRE = me.disabledDatesRE,
            minValue = me.minValue,
            maxValue = me.maxValue,
            len = disabledDays ? disabledDays.length : 0,
            i = 0,
            svalue,
            fvalue,
            day,
            time;

        value = me.formatDate(value || me.processRawValue(me.getRawValue()));

        if (value === null || value.length < 1) { 
             return errors;
        }

        svalue = value;
        value = me.parseDate(value);
        if (!value) {
            errors.push(format(me.invalidText, svalue, Ext.Date.unescapeFormat(me.format)));
            return errors;
        }

        time = value.getTime();
        if (minValue && time < clearTime(minValue).getTime()) {
            errors.push(format(me.minText, me.formatDate(minValue)));
        }

        if (maxValue && time > clearTime(maxValue).getTime()) {
            errors.push(format(me.maxText, me.formatDate(maxValue)));
        }

        if (disabledDays) {
            day = value.getDay();

            for(; i < len; i++) {
                if (day === disabledDays[i]) {
                    errors.push(me.disabledDaysText);
                    break;
                }
            }
        }

        fvalue = me.formatDate(value);
        if (disabledDatesRE && disabledDatesRE.test(fvalue)) {
            errors.push(format(me.disabledDatesText, fvalue));
        }

        return errors;
    },

    rawToValue: function(rawValue) {
        return this.parseDate(rawValue) || rawValue || null;
    },

    valueToRaw: function(value) {
        return this.formatDate(this.parseDate(value));
    },

    

    
    safeParse : function(value, format) {
        var me = this,
            utilDate = Ext.Date,
            result = null,
            strict = me.useStrict,
            parsedDate;

        if (utilDate.formatContainsHourInfo(format)) {
            
            result = utilDate.parse(value, format, strict);
        } else {
            
            parsedDate = utilDate.parse(value + ' ' + me.initTime, format + ' ' + me.initTimeFormat, strict);
            if (parsedDate) {
                result = utilDate.clearTime(parsedDate);
            }
        }
        return result;
    },

    
    getSubmitValue: function() {
        var format = this.submitFormat || this.format,
            value = this.getValue();

        return value ? Ext.Date.format(value, format) : '';
    },

    
    parseDate : function(value) {
        if(!value || Ext.isDate(value)){
            return value;
        }

        var me = this,
            val = me.safeParse(value, me.format),
            altFormats = me.altFormats,
            altFormatsArray = me.altFormatsArray,
            i = 0,
            len;

        if (!val && altFormats) {
            altFormatsArray = altFormatsArray || altFormats.split('|');
            len = altFormatsArray.length;
            for (; i < len && !val; ++i) {
                val = me.safeParse(value, altFormatsArray[i]);
            }
        }
        return val;
    },

    
    formatDate : function(date){
        return Ext.isDate(date) ? Ext.Date.dateFormat(date, this.format) : date;
    },

    createPicker: function() {
        var me = this,
            format = Ext.String.format;

        return new Ext.picker.Date({
            pickerField: me,
            ownerCt: me.ownerCt,
            renderTo: document.body,
            floating: true,
            hidden: true,
            focusOnShow: true,
            minDate: me.minValue,
            maxDate: me.maxValue,
            disabledDatesRE: me.disabledDatesRE,
            disabledDatesText: me.disabledDatesText,
            disabledDays: me.disabledDays,
            disabledDaysText: me.disabledDaysText,
            format: me.format,
            showToday: me.showToday,
            startDay: me.startDay,
            minText: format(me.minText, me.formatDate(me.minValue)),
            maxText: format(me.maxText, me.formatDate(me.maxValue)),
            listeners: {
                scope: me,
                select: me.onSelect
            },
            keyNavConfig: {
                esc: function() {
                    me.collapse();
                }
            }
        });
    },

    onSelect: function(m, d) {
        var me = this;

        me.setValue(d);
        me.fireEvent('select', me, d);
        me.collapse();
    },

    
    onExpand: function() {
        var value = this.getValue();
        this.picker.setValue(Ext.isDate(value) ? value : new Date());
    },

    
    onCollapse: function() {
        this.focus(false, 60);
    },

    
    beforeBlur : function(){
        var me = this,
            v = me.parseDate(me.getRawValue()),
            focusTask = me.focusTask;

        if (focusTask) {
            focusTask.cancel();
        }

        if (v) {
            me.setValue(v);
        }
    }

    
    
    
    
});


Ext.define('Ext.resizer.BorderSplitterTracker', {
    extend: 'Ext.resizer.SplitterTracker',
    requires: ['Ext.util.Region'],

    getPrevCmp: null,
    getNextCmp: null,

    
    calculateConstrainRegion: function() {
        var me = this,
            splitter = me.splitter,
            collapseTarget = splitter.collapseTarget,
            defaultSplitMin = splitter.defaultSplitMin,
            sizePropCap = splitter.vertical ? 'Width' : 'Height',
            minSizeProp = 'min' + sizePropCap,
            maxSizeProp = 'max' + sizePropCap,
            getSizeMethod = 'get' + sizePropCap,
            neighbors = splitter.neighbors,
            length = neighbors.length,
            box = collapseTarget.el.getBox(),
            left = box.x,
            top = box.y,
            right = box.right,
            bottom = box.bottom,
            size = splitter.vertical ? (right - left) : (bottom - top),
            
            i, neighbor, minRange, maxRange, maxGrowth, maxShrink, targetSize;

        
        minRange = (collapseTarget[minSizeProp] || Math.min(size,defaultSplitMin)) - size;

        
        maxRange = collapseTarget[maxSizeProp];
        if (!maxRange) {
            maxRange = 1e9;
        } else {
            maxRange -= size;
        }
        targetSize = size;

        for (i = 0; i < length; ++i) {
            neighbor = neighbors[i];
            size = neighbor[getSizeMethod]();
            

            maxGrowth = size - neighbor[maxSizeProp]; 
            maxShrink = size - (neighbor[minSizeProp] || Math.min(size,defaultSplitMin));

            if (!isNaN(maxGrowth)) {
                
                
                if (minRange < maxGrowth) {
                    minRange = maxGrowth;
                }
            }

            
            
            if (maxRange > maxShrink) {
                maxRange = maxShrink;
            }
        }

        if (maxRange - minRange < 2) {
            return null;
        }

        box = new Ext.util.Region(top, right, bottom, left);

        me.constraintAdjusters[splitter.collapseDirection](box, minRange, maxRange, splitter);

        me.dragInfo = {
            minRange: minRange,
            maxRange: maxRange,
            
            targetSize: targetSize
        };

        return box;
    },

    constraintAdjusters: {
        
        left: function (box, minRange, maxRange, splitter) {
            box[0] = box.x = box.left = box.right + minRange;
            box.right += maxRange + splitter.getWidth();
        },

        
        top: function (box, minRange, maxRange, splitter) {
            box[1] = box.y = box.top = box.bottom + minRange;
            box.bottom += maxRange + splitter.getHeight();
        },

        
        bottom: function (box, minRange, maxRange, splitter) {
            box.bottom = box.top - minRange;
            box.top -= maxRange + splitter.getHeight();
        },

        
        right: function (box, minRange, maxRange, splitter) {
            box.right = box.left - minRange;
            box.left -= maxRange + splitter.getWidth();
        }
    },

    onBeforeStart: function(e) {
        var me = this,
            splitter = me.splitter,
            collapseTarget = splitter.collapseTarget,
            neighbors = splitter.neighbors,
            collapseEl = me.getSplitter().collapseEl,
            target = e.getTarget(),
            length = neighbors.length,
            i, neighbor;
            
        if (collapseEl && target === splitter.collapseEl.dom) {
            return false;
        }

        if (collapseTarget.collapsed) {
            return false;
        }

        
        for (i = 0; i < length; ++i) {
            neighbor = neighbors[i];

            if (neighbor.collapsed && neighbor.isHorz === collapseTarget.isHorz) {
                return false;
            }
        }

        if (!(me.constrainTo = me.calculateConstrainRegion())) {
            return false;
        }

        me.createDragOverlay();
        return true;
    },

    performResize: function(e, offset) {
        var me = this,
            splitter = me.splitter,
            collapseDirection = splitter.collapseDirection,
            collapseTarget = splitter.collapseTarget,
            
            adjusters = me.splitAdjusters[splitter.vertical ? 'horz' : 'vert'],
            delta = offset[adjusters.index],
            dragInfo = me.dragInfo,
            
            
            
            
            
            owner;

        if (collapseDirection == 'right' || collapseDirection == 'bottom') {
            
            delta = -delta;
        }

        
        delta = Math.min(Math.max(dragInfo.minRange, delta), dragInfo.maxRange);

        if (delta) {
            (owner = splitter.ownerCt).suspendLayouts();

            adjusters.adjustTarget(collapseTarget, dragInfo.targetSize, delta);

            
            
            
            
            
            
            

            owner.resumeLayouts(true);
        }
    },

    splitAdjusters: {
        horz: {
            index: 0,
            
            
            
            adjustTarget: function (target, size, delta) {
                target.flex = null;
                target.setSize(size + delta);
            }
        },
        vert: {
            index: 1,
            
            
            
            adjustTarget: function (target, targetSize, delta) {
                target.flex = null;
                target.setSize(undefined, targetSize + delta);
            }
        }
    }
});


Ext.define('Ext.resizer.Handle', {
    extend: 'Ext.Component',
    handleCls: '',
    baseHandleCls: Ext.baseCSSPrefix + 'resizable-handle',
    
    
    region: '',

    beforeRender: function() {
        var me = this;

        me.callParent();

        me.addCls(
            me.baseHandleCls,
            me.baseHandleCls + '-' + me.region,
            me.handleCls
        );
    },

    onRender: function() {
        this.callParent(arguments);

        this.el.unselectable();
    }
});


Ext.define('Ext.resizer.Splitter', {
    extend: 'Ext.Component',
    requires: ['Ext.XTemplate'],
    uses: ['Ext.resizer.SplitterTracker'],
    alias: 'widget.splitter',

    childEls: [
        'collapseEl'
    ],

    renderTpl: [
        '<tpl if="collapsible===true">',
            '<div id="{id}-collapseEl" class="', Ext.baseCSSPrefix, 'collapse-el ',
                Ext.baseCSSPrefix, 'layout-split-{collapseDir}">&#160;</div>',
        '</tpl>'
    ],

    baseCls: Ext.baseCSSPrefix + 'splitter',
    collapsedClsInternal: Ext.baseCSSPrefix + 'splitter-collapsed',
    
    
    canResize: true,

    
    collapsible: false,

    

    
    collapseOnDblClick: true,

    
    defaultSplitMin: 40,

    
    defaultSplitMax: 1000,

    

    
    collapseTarget: 'next',

    

    horizontal: false,
    vertical: false,

    
    getTrackerConfig: function () {
        return {
            xclass: 'Ext.resizer.SplitterTracker',
            el: this.el,
            splitter: this
        };
    },

    beforeRender: function() {
        var me = this,
            target = me.getCollapseTarget(),
            collapseDir = me.getCollapseDirection(),
            vertical = me.vertical,
            fixedSizeProp = vertical ? 'width' : 'height',
            stretchSizeProp = vertical ? 'height' : 'width',
            cls;

        me.callParent();

        if (!me.hasOwnProperty(stretchSizeProp)) {
            me[stretchSizeProp] = '100%';
        }
        if (!me.hasOwnProperty(fixedSizeProp)) {
            me[fixedSizeProp] = 5;
        }

        if (target.collapsed) {
            me.addCls(me.collapsedClsInternal);
        }
        
        cls = me.baseCls + '-' + me.orientation;
        me.addCls(cls);
        if (!me.canResize) {
            me.addCls(cls + '-noresize');
        }
        
        Ext.applyIf(me.renderData, {
            collapseDir: collapseDir,
            collapsible: me.collapsible || target.collapsible
        });
    },

    onRender: function() {
        var me = this;

        me.callParent(arguments);

        
        if (me.performCollapse !== false) {
            if (me.renderData.collapsible) {
                me.mon(me.collapseEl, 'click', me.toggleTargetCmp, me);
            }
            if (me.collapseOnDblClick) {
                me.mon(me.el, 'dblclick', me.toggleTargetCmp, me);
            }
        }

        
        me.mon(me.getCollapseTarget(), {
            collapse: me.onTargetCollapse,
            expand: me.onTargetExpand,
            scope: me
        });

        me.el.unselectable();
        if (me.canResize) {
            me.tracker = Ext.create(me.getTrackerConfig());
            
            me.relayEvents(me.tracker, [ 'beforedragstart', 'dragstart', 'dragend' ]);
        }
    },

    getCollapseDirection: function() {
        var me = this,
            dir = me.collapseDirection,
            collapseTarget, idx, items, type;

        if (!dir) {
            collapseTarget = me.collapseTarget;
            if (collapseTarget.isComponent) {
                dir = collapseTarget.collapseDirection;
            }

            if (!dir) {
                
                
                
                
                
                
                
                type = me.ownerCt.layout.type;
                if (collapseTarget.isComponent) {
                    items = me.ownerCt.items;
                    idx = Number(items.indexOf(collapseTarget) == items.indexOf(me) - 1) << 1 | Number(type == 'hbox');
                } else {
                    idx = Number(me.collapseTarget == 'prev') << 1 | Number(type == 'hbox');
                }

                
                dir = ['bottom', 'right', 'top', 'left'][idx];
            }

            me.collapseDirection = dir;
        }

        me.orientation = (dir == 'top' || dir == 'bottom') ? 'horizontal' : 'vertical';
        me[me.orientation] = true;

        return dir;
    },

    getCollapseTarget: function() {
        var me = this;

        return me.collapseTarget.isComponent ? me.collapseTarget : me.collapseTarget == 'prev' ? me.previousSibling() : me.nextSibling();
    },

    onTargetCollapse: function(target) {
        this.el.addCls([this.collapsedClsInternal, this.collapsedCls]);
    },

    onTargetExpand: function(target) {
        this.el.removeCls([this.collapsedClsInternal, this.collapsedCls]);
    },

    toggleTargetCmp: function(e, t) {
        var cmp = this.getCollapseTarget(),
            placeholder = cmp.placeholder,
            toggle;

        if (placeholder && !placeholder.hidden) {
            toggle = true;
        } else {
            toggle = !cmp.hidden;
        }

        if (toggle) {
            if (cmp.collapsed) {
                cmp.expand();
            } else if (cmp.collapseDirection) {
                cmp.collapse();
            } else {
                cmp.collapse(this.renderData.collapseDir);
            }
        }
    },

    
    setSize: function() {
        var me = this;
        me.callParent(arguments);
        if (Ext.isIE && me.el) {
            me.el.repaint();
        }
    },
    
    beforeDestroy: function(){
        Ext.destroy(this.tracker);
        this.callParent();
    }
});


Ext.define('Ext.resizer.BorderSplitter', {
    extend: 'Ext.resizer.Splitter',

    uses: ['Ext.resizer.BorderSplitterTracker'],

    alias: 'widget.bordersplitter',

    
    collapseTarget: null,

    getTrackerConfig: function () {
        var trackerConfig = this.callParent();

        trackerConfig.xclass = 'Ext.resizer.BorderSplitterTracker';

        return trackerConfig;
    }
});


Ext.define('Ext.layout.container.Border', {

    alias: 'layout.border',

    extend: 'Ext.layout.container.Container',

    requires: ['Ext.resizer.BorderSplitter', 'Ext.Component', 'Ext.fx.Anim'],

    alternateClassName: 'Ext.layout.BorderLayout',


    targetCls: Ext.baseCSSPrefix + 'border-layout-ct',

    itemCls: [Ext.baseCSSPrefix + 'border-item', Ext.baseCSSPrefix + 'box-item'],

    type: 'border',

    
    
    

    
    padding: undefined,

    percentageRe: /(\d+)%/,

    
    axisProps: {
        horz: {
            borderBegin: 'west',
            borderEnd: 'east',
            horizontal: true,
            posProp: 'x',
            sizeProp: 'width',
            sizePropCap: 'Width'
        },
        vert: {
            borderBegin: 'north',
            borderEnd: 'south',
            horizontal: false,
            posProp: 'y',
            sizeProp: 'height',
            sizePropCap: 'Height'
        }
    },

    
    centerRegion: null,

    
    collapseDirections: {
        north: 'top',
        south: 'bottom',
        east: 'right',
        west: 'left'
    },

    manageMargins: true,

    panelCollapseAnimate: true,

    panelCollapseMode: 'placeholder',

    
    regionWeights: {
        north: 20,
        south: 10,
        center: 0,
        west: -10,
        east: -20
    },

    
    

    
    beginAxis: function (ownerContext, regions, name) {
        var me = this,
            props = me.axisProps[name],
            isVert = !props.horizontal,
            sizeProp = props.sizeProp,
            totalFlex = 0,
            childItems = ownerContext.childItems,
            length = childItems.length,
            center, i, childContext, centerFlex, comp, region, match, size, type, target, placeholder;

        for (i = 0; i < length; ++i) {
            childContext = childItems[i];
            comp = childContext.target;

            childContext.layoutPos = {};

            if (comp.region) {
                childContext.region = region = comp.region;

                childContext.isCenter = comp.isCenter;
                childContext.isHorz = comp.isHorz;
                childContext.isVert = comp.isVert;

                childContext.weight = comp.weight || me.regionWeights[region] || 0;
                regions[comp.id] = childContext;

                if (comp.isCenter) {
                    center = childContext;
                    centerFlex = comp.flex;
                    ownerContext.centerRegion = center;

                    continue;
                }

                if (isVert !== childContext.isVert) {
                    continue;
                }

                

                childContext.reverseWeighting = (region == props.borderEnd);

                size = comp[sizeProp];
                type = typeof size;

                if (!comp.collapsed) {
                    if (type == 'string' && (match = me.percentageRe.exec(size))) {
                        childContext.percentage = parseInt(match[1], 10);
                    } else if (comp.flex) {
                        totalFlex += childContext.flex = comp.flex;
                    }
                }
            }
        }

        
        if (center) {
            target = center.target;

            if (placeholder = target.placeholderFor) {
                if (!centerFlex && isVert === placeholder.collapsedVertical()) {
                    
                    centerFlex = 0;
                    center.collapseAxis = name;
                }
            } else if (target.collapsed && (isVert === target.collapsedVertical())) {
                
                centerFlex = 0;
                center.collapseAxis = name;
            }
        }

        if (centerFlex == null) {
            
            centerFlex = 1;
        }

        totalFlex += centerFlex;

        return Ext.apply({
            before         : isVert ? 'top' : 'left',
            totalFlex      : totalFlex
        }, props);
    },

    beginLayout: function (ownerContext) {
        var me = this,
            items = me.getLayoutItems(),
            pad = me.padding,
            type = typeof pad,
            padOnContainer = false,
            childContext, item, length, i, regions, collapseTarget,
            doShow, hidden, region;

        
        if (pad) {
            if (type == 'string' || type == 'number') {
                pad = Ext.util.Format.parseBox(pad);
            }
        } else {
            pad = ownerContext.getEl('getTargetEl').getPaddingInfo();
            padOnContainer = true;
        }
        ownerContext.outerPad = pad;
        ownerContext.padOnContainer = padOnContainer;

        for (i = 0, length = items.length; i < length; ++i) {
            item = items[i];
            collapseTarget = me.getSplitterTarget(item);
            if (collapseTarget) {
                hidden = !!item.hidden;
                if (!collapseTarget.split) {
                    if (collapseTarget.isCollapsingOrExpanding) {
                        doShow = !!collapseTarget.collapsed;
                    }
                } else if (hidden !== collapseTarget.hidden) {
                    doShow = !collapseTarget.hidden;
                }
                
                if (doShow === true) {
                    item.show();
                } else if (doShow === false) {
                    item.hide();
                }
            }
        }

        
        
        
        me.callParent(arguments);

        items = ownerContext.childItems;
        length = items.length;
        regions = {};

        ownerContext.borderAxisHorz = me.beginAxis(ownerContext, regions, 'horz');
        ownerContext.borderAxisVert = me.beginAxis(ownerContext, regions, 'vert');

        
        
        
        for (i = 0; i < length; ++i) {
            childContext = items[i];
            collapseTarget = me.getSplitterTarget(childContext.target);

            if (collapseTarget) { 
                region = regions[collapseTarget.id]
                if (!region) {
                        
                        
                        
                        region = ownerContext.getEl(collapseTarget.el, me);
                        region.region = collapseTarget.region;
                }
                childContext.collapseTarget = collapseTarget = region;
                childContext.weight = collapseTarget.weight;
                childContext.reverseWeighting = collapseTarget.reverseWeighting;
                collapseTarget.splitter = childContext;
                childContext.isHorz = collapseTarget.isHorz;
                childContext.isVert = collapseTarget.isVert;
            }
        }

        
        me.sortWeightedItems(items, 'reverseWeighting');
        me.setupSplitterNeighbors(items);
    },

    calculate: function (ownerContext) {
        var me = this,
            containerSize = me.getContainerSize(ownerContext),
            childItems = ownerContext.childItems,
            length = childItems.length,
            horz = ownerContext.borderAxisHorz,
            vert = ownerContext.borderAxisVert,
            pad = ownerContext.outerPad,
            padOnContainer = ownerContext.padOnContainer,
            i, childContext, childMargins, size, horzPercentTotal, vertPercentTotal;

        horz.begin = pad.left;
        vert.begin = pad.top;
        
        
        horzPercentTotal = horz.end = horz.flexSpace = containerSize.width + (padOnContainer ? pad.left : -pad.right);
        vertPercentTotal = vert.end = vert.flexSpace = containerSize.height + (padOnContainer ? pad.top : -pad.bottom);

        
        
        for (i = 0; i < length; ++i) {
            childContext = childItems[i];
            childMargins = childContext.getMarginInfo();

            
            if (childContext.isHorz || childContext.isCenter) {
                horz.addUnflexed(childMargins.width);
                horzPercentTotal -= childMargins.width;
            }

            if (childContext.isVert || childContext.isCenter) {
                vert.addUnflexed(childMargins.height);
                vertPercentTotal -= childMargins.height;
            }

            
            if (!childContext.flex && !childContext.percentage) {
                if (childContext.isHorz || (childContext.isCenter && childContext.collapseAxis === 'horz')) {
                    size = childContext.getProp('width');

                    horz.addUnflexed(size);

                    
                    if (childContext.collapseTarget) {
                        horzPercentTotal -= size;
                    }
                } else if (childContext.isVert || (childContext.isCenter && childContext.collapseAxis === 'vert')) {
                    size = childContext.getProp('height');

                    vert.addUnflexed(size);

                    
                    if (childContext.collapseTarget) {
                        vertPercentTotal -= size;
                    }
                }
                
            }
        }

        for (i = 0; i < length; ++i) {
            childContext = childItems[i];
            childMargins = childContext.getMarginInfo();

            
            if (childContext.percentage) {
                if (childContext.isHorz) {
                    size = Math.ceil(horzPercentTotal * childContext.percentage / 100);
                    size = childContext.setWidth(size);
                    horz.addUnflexed(size);
                } else if (childContext.isVert) {
                    size = Math.ceil(vertPercentTotal * childContext.percentage / 100);
                    size = childContext.setHeight(size);
                    vert.addUnflexed(size);
                }
                
            }
        }


        
        

        for (i = 0; i < length; ++i) {
            childContext = childItems[i];

            if (!childContext.isCenter) {
                me.calculateChildAxis(childContext, horz);
                me.calculateChildAxis(childContext, vert);
            }
        }

        
        
        
        if (me.finishAxis(ownerContext, vert) + me.finishAxis(ownerContext, horz) < 2) {
            me.done = false;
        } else {
            
            
            
            me.finishPositions(childItems);
        }
    },

    
    calculateChildAxis: function (childContext, axis) {
        var collapseTarget = childContext.collapseTarget,
            setSizeMethod = 'set' + axis.sizePropCap,
            sizeProp = axis.sizeProp,
            childMarginSize = childContext.getMarginInfo()[sizeProp],
            region, isBegin, flex, pos, size;

        if (collapseTarget) { 
            region = collapseTarget.region;
        } else {
            region = childContext.region;
            flex = childContext.flex;
        }

        isBegin = region == axis.borderBegin;

        if (!isBegin && region != axis.borderEnd) {
            
            
            childContext[setSizeMethod](axis.end - axis.begin - childMarginSize);
            pos = axis.begin;
        } else {
            if (flex) {
                size = Math.ceil(axis.flexSpace * (flex / axis.totalFlex));
                size = childContext[setSizeMethod](size);
            } else if (childContext.percentage) {
                
                size = childContext.peek(sizeProp);
            } else {
                size = childContext.getProp(sizeProp);
            }

            size += childMarginSize;

            if (isBegin) {
                pos = axis.begin;
                axis.begin += size;
            } else {
                axis.end = pos = axis.end - size;
            }
        }

        childContext.layoutPos[axis.posProp] = pos;
    },

    
    finishAxis: function (ownerContext, axis) {
        var size = axis.end - axis.begin,
            center = ownerContext.centerRegion;

        if (center) {
            center['set' + axis.sizePropCap](size - center.getMarginInfo()[axis.sizeProp]);
            center.layoutPos[axis.posProp] = axis.begin;
        }

        return Ext.isNumber(size) ? 1 : 0;
    },

    
    finishPositions: function (childItems) {
        var length = childItems.length,
            index, childContext;

        for (index = 0; index < length; ++index) {
            childContext = childItems[index];

            childContext.setProp('x', childContext.layoutPos.x + childContext.marginInfo.left);
            childContext.setProp('y', childContext.layoutPos.y + childContext.marginInfo.top);
        }
    },

    getPlaceholder: function (comp) {
        return comp.getPlaceholder && comp.getPlaceholder();
    },

    getSplitterTarget: function (splitter) {
        var collapseTarget = splitter.collapseTarget;

        if (collapseTarget && collapseTarget.collapsed) {
            return collapseTarget.placeholder || collapseTarget;
        }

        return collapseTarget;
    },

    isItemBoxParent: function (itemContext) {
        return true;
    },

    isItemShrinkWrap: function (item) {
        return true;
    },

    
    

    
    insertSplitter: function (item, index, hidden) {
        var region = item.region,
            splitter = {
                xtype: 'bordersplitter',
                collapseTarget: item,
                id: item.id + '-splitter',
                hidden: hidden,
                canResize: item.splitterResize !== false
            },
            at = index + ((region == 'south' || region == 'east') ? 0 : 1);

        
        if (item.isHorz) {
            splitter.height = null;
        } else {
            splitter.width = null;
        }

        if (item.collapseMode == 'mini') {
            splitter.collapsedCls = item.collapsedCls;
        }

        item.splitter = this.owner.add(at, splitter);
    },

    
    onAdd: function (item, index) {
        var me = this,
            placeholderFor = item.placeholderFor,
            region = item.region,
            split,
            hidden;

        me.callParent(arguments);

        if (region) {
            Ext.apply(item, me.regionFlags[region]);

            if (region == 'center') {
                me.centerRegion = item;
            } else {
                item.collapseDirection = this.collapseDirections[region];
                split = item.split;
                hidden = !!item.hidden;
                if ((item.isHorz || item.isVert) && (split || item.collapseMode == 'mini')) {
                    me.insertSplitter(item, index, hidden || !split);
                }
            }

            if (!item.hasOwnProperty('collapseMode')) {
                item.collapseMode = me.panelCollapseMode;
            }

            if (!item.hasOwnProperty('animCollapse')) {
                if (item.collapseMode != 'placeholder') {
                    
                    
                    item.animCollapse = false;
                } else {
                    item.animCollapse = me.panelCollapseAnimate;
                }
            }
        } else if (placeholderFor) {
            Ext.apply(item, me.regionFlags[placeholderFor.region]);
            item.region = placeholderFor.region;
            item.weight = placeholderFor.weight;
        }
    },

    onDestroy: function() {
        this.centerRegion = null;
        this.callParent();
    },

    onRemove: function (item) {
        var me = this,
            region = item.region,
            splitter = item.splitter;

        if (region) {
            if (item.isCenter) {
                me.centerRegion = null;
            }

            delete item.isCenter;
            delete item.isHorz;
            delete item.isVert;

            if (splitter) {
                me.owner.doRemove(splitter, true); 
                delete item.splitter;
            }
        }

        me.callParent(arguments);
    },

    
    

    regionFlags: {
        center: { isCenter: true, isHorz: false, isVert: false },

        north: { isCenter: false, isHorz: false, isVert: true },
        south: { isCenter: false, isHorz: false, isVert: true },

        west: { isCenter: false, isHorz: true, isVert: false },
        east: { isCenter: false, isHorz: true, isVert: false }
    },

    setupSplitterNeighbors: function (items) {
        var edgeRegions = {
                
                
                
                
            },
            length = items.length,
            touchedRegions = this.touchedRegions,
            i, j, center, count, edge, comp, region, splitter, touched;

        for (i = 0; i < length; ++i) {
            comp = items[i].target;
            region = comp.region;

            if (comp.isCenter) {
                center = comp;
            } else if (region) {
                touched = touchedRegions[region];

                for (j = 0, count = touched.length; j < count; ++j) {
                    edge = edgeRegions[touched[j]];
                    if (edge) {
                        edge.neighbors.push(comp);
                    }
                }
                
                if (comp.placeholderFor) {
                    
                    splitter = comp.placeholderFor.splitter;
                } else {
                    splitter = comp.splitter;
                }
                if (splitter) {
                    splitter.neighbors = [];
                }

                edgeRegions[region] = splitter;
            }
        }

        if (center) {
            touched = touchedRegions.center;

            for (j = 0, count = touched.length; j < count; ++j) {
                edge = edgeRegions[touched[j]];
                if (edge) {
                    edge.neighbors.push(center);
                }
            }
        }
    },

    
    touchedRegions: {
        center: [ 'north', 'south', 'east',  'west' ],

        north:  [ 'north', 'east',  'west'  ],
        south:  [ 'south', 'east',  'west'  ],
        east:   [ 'east',  'north', 'south' ],
        west:   [ 'west',  'north', 'south' ]
    },

    sizePolicies: {
        vert: {
            setsWidth: 1,
            setsHeight: 0
        },
        horz: {
            setsWidth: 0,
            setsHeight: 1
        },
        flexAll: {
            setsWidth: 1,
            setsHeight: 1
        }
    },

    getItemSizePolicy: function (item) {
        var me = this,
            policies = this.sizePolicies,
            collapseTarget, size, policy, placeholderFor;

        if (item.isCenter) {
            placeholderFor = item.placeholderFor;

            if (placeholderFor) {
                if (placeholderFor.collapsedVertical()) {
                    return policies.vert;
                }
                return policies.horz;
            }
            if (item.collapsed) {
                if (item.collapsedVertical()) {
                    return policies.vert;
                }
                return policies.horz;
            }
            return policies.flexAll;
        }

        collapseTarget = item.collapseTarget;

        if (collapseTarget) {
            return collapseTarget.isVert ? policies.vert : policies.horz;
        }

        if (item.region) {
            if (item.isVert) {
                size = item.height;
                policy = policies.vert;
            } else {
                size = item.width;
                policy = policies.horz;
            }

            if (item.flex || (typeof size == 'string' && me.percentageRe.test(size))) {
                return policies.flexAll;
            }

            return policy;
        }

        return me.autoSizePolicy;
    }
}, function () {
    var methods = {
        addUnflexed: function (px) {
            this.flexSpace = Math.max(this.flexSpace - px, 0);
        }
    },
    props = this.prototype.axisProps;

    Ext.apply(props.horz, methods);
    Ext.apply(props.vert, methods);
});


Ext.define('Ext.selection.CellModel', {
    extend: 'Ext.selection.Model',
    alias: 'selection.cellmodel',
    requires: ['Ext.util.KeyNav'],

    isCellModel: true,

    
    enableKeyNav: true,

    
    preventWrap: false,

    
    noSelection: {
        row: -1,
        column: -1
    },

    constructor: function() {
        this.addEvents(
            
            'deselect',

            
            'select'
        );
        this.callParent(arguments);
    },

    bindComponent: function(view) {
        var me = this,
            grid = view.ownerCt;
        me.primaryView = view;
        me.views = me.views || [];
        me.views.push(view);
        me.bindStore(view.getStore(), true);

        view.on({
            cellmousedown: me.onMouseDown,
            refresh: me.onViewRefresh,
            scope: me
        });
        if (grid.optimizedColumnMove !== false) {
            grid.on('columnmove', me.onColumnMove, me);
        }

        if (me.enableKeyNav) {
            me.initKeyNav(view);
        }
    },

    initKeyNav: function(view) {
        var me = this;

        if (!view.rendered) {
            view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true});
            return;
        }

        view.el.set({
            tabIndex: -1
        });

        
        
        me.keyNav = new Ext.util.KeyNav({
            target: view.el,
            ignoreInputFields: true,
            up: me.onKeyUp,
            down: me.onKeyDown,
            right: me.onKeyRight,
            left: me.onKeyLeft,
            tab: me.onKeyTab,
            scope: me
        });
    },

    getHeaderCt: function() {
        var selection = this.getCurrentPosition(),
            view = selection ? selection.view : this.primaryView;

        return view.headerCt;
    },

    onKeyUp: function(e, t) {
        this.keyNavigation = true;
        this.move('up', e);
        this.keyNavigation = false;
    },

    onKeyDown: function(e, t) {
        this.keyNavigation = true;
        this.move('down', e);
        this.keyNavigation = false;
    },

    onKeyLeft: function(e, t) {
        this.keyNavigation = true;
        this.move('left', e);
        this.keyNavigation = false;
    },

    onKeyRight: function(e, t) {
        this.keyNavigation = true;
        this.move('right', e);
        this.keyNavigation = false;
    },

    move: function(dir, e) {
        var me = this,
            pos = me.getCurrentPosition(),
            
            
            newPos = pos.view.walkCells(pos, dir, e, me.preventWrap);

        
        if (newPos) {
            newPos.view = pos.view;
            return me.setCurrentPosition(newPos);
        }
    },

    
    getCurrentPosition: function() {
        return this.selection;
    },

    
    setCurrentPosition: function(pos) {
        var me = this;

        
        me.lastSelection = me.selection;
        if (me.selection) {
            me.onCellDeselect(me.selection);
        }

        if (pos) {
            me.nextSelection = new me.Selection(me);
            me.nextSelection.setPosition(pos);
            me.onCellSelect(me.nextSelection);

            
            return me.selection = me.nextSelection;
        }
    },

    
    onStoreRemove: function(store, record, index) {
        var me = this,
            pos = me.getCurrentPosition();

        me.callParent(arguments);
        if (pos) {
            
            
            if (pos.row == index) {
                if (index < store.getCount() - 1) {
                    pos.setPosition(index, pos.column);
                    me.setCurrentPosition(pos);
                } else {
                    delete me.selection;
                }
            }
            
            
            else if (index < pos.row) {
                pos.setPosition(pos.row - 1, pos.column);
                me.setCurrentPosition(pos);
            }
        }
    },

    
    onMouseDown: function(view, cell, cellIndex, record, row, rowIndex, e) {
        this.setCurrentPosition({
            view: view,
            row: rowIndex,
            column: cellIndex
        });
    },

    
    
    onCellSelect: function(position, supressEvent) {
        if (position && position.row !== undefined && position.row > -1) {
            this.doSelect(position.view.getStore().getAt(position.row), false, supressEvent);
        }
    },

    
    
    onCellDeselect: function(position, supressEvent) {
        if (position && position.row !== undefined) {
            this.doDeselect(position.view.getStore().getAt(position.row), supressEvent);
        }
    },

    onSelectChange: function(record, isSelected, suppressEvent, commitFn) {
        var me = this,
            pos,
            eventName,
            view;

        if (isSelected) {
            pos = me.nextSelection;
            eventName = 'select';
        } else {
            pos = me.lastSelection || me.noSelection;
            eventName = 'deselect';
        }

        
        
        
        view = pos.view || me.primaryView;

        if ((suppressEvent || me.fireEvent('before' + eventName, me, record, pos.row, pos.column)) !== false &&
                commitFn() !== false) {

            if (isSelected) {
                view.onCellSelect(pos);
                view.onCellFocus(pos);
            } else {
                view.onCellDeselect(pos);
                delete me.selection;
            }

            if (!suppressEvent) {
                me.fireEvent(eventName, me, record, pos.row, pos.column);
            }
        }
    },

    
    onKeyTab: function(e, t) {
        var me = this,
            editingPlugin = me.getCurrentPosition().view.editingPlugin;

        
        if (editingPlugin && me.wasEditing) {
            me.onEditorTab(editingPlugin, e)
        } else {
            me.move(e.shiftKey ? 'left' : 'right', e);
        }
    },

    onEditorTab: function(editingPlugin, e) {
        var me = this,
            direction = e.shiftKey ? 'left' : 'right',
            position  = me.move(direction, e);

        
        if (position) {
            
            if (editingPlugin.startEditByPosition(position)) {
                me.wasEditing = false;
            }
            
            
            else {
                me.wasEditing = true;
                if (!position.columnHeader.dataIndex) {
                    me.onEditorTab(editingPlugin, e);
                }
            }
        }
    },

    refresh: function() {
        var pos = this.getCurrentPosition(),
            selRowIdx;

        
        if (pos && (selRowIdx = this.store.indexOf(this.selected.last())) !== -1) {
            pos.row = selRowIdx;
        }
    },

    
    onColumnMove: function(headerCt, header, fromIdx, toIdx) {
        var grid = headerCt.up('tablepanel');
        if (grid) {
            this.onViewRefresh(grid.view);
        }
    },

    onViewRefresh: function(view) {
        var me = this,
            pos = me.getCurrentPosition(),
            headerCt = view.headerCt,
            record, columnHeader;

        
        
        if (pos && pos.view === view) {
            record = pos.record;
            columnHeader = pos.columnHeader;

            
            if (!columnHeader.isDescendantOf(headerCt)) {
                
                
                
                columnHeader = headerCt.queryById(columnHeader.id) || 
                               headerCt.down('[text="' + columnHeader.text + '"]') ||
                               headerCt.down('[dataIndex="' + columnHeader.dataIndex + '"]');
            }

            
            
            
            
            if (columnHeader && (view.store.indexOfId(record.getId()) !== -1)) {
                me.setCurrentPosition({
                    row: record,
                    column: columnHeader,
                    view: view
                });
            }
        }
    },

    selectByPosition: function(position) {
        this.setCurrentPosition(position);
    }
}, function() {
    
    
    
    var Selection = this.prototype.Selection = function(model) {
        this.model = model;
    };
    
    Selection.prototype.setPosition = function(row, col) {
        var me = this,
            view;

        
        if (arguments.length === 1) {
            
            
            
            if (row.view) {
                me.view = view = row.view;
            }
            col = row.column;
            row = row.row;
        }
        
        
        
        if (!view) {
            me.view = view = me.model.primaryView;
        }

        
        if (typeof row === 'number') {
            me.row = row;
            me.record = view.store.getAt(row);
        }
        
        else if (row.isModel) {
            me.record = row;
            me.row = view.indexOf(row);
        }
        
        else if (row.tagName) {
            me.record = view.getRecord(row);
            me.row = view.indexOf(me.record);
        }
        
        
        if (typeof col === 'number') {
            me.column = col;
            me.columnHeader = view.getHeaderAtIndex(col);
        }
        
        else {
            me.columnHeader = col;
            me.column = col.getIndex();
        }
        return me;
    }
});

Ext.define('Ext.selection.RowModel', {
    extend: 'Ext.selection.Model',
    alias: 'selection.rowmodel',
    requires: ['Ext.util.KeyNav'],

    
    deltaScroll: 5,

    
    enableKeyNav: true,
    
    
    ignoreRightMouseSelection: false,

    constructor: function() {
        this.addEvents(
            
            'beforedeselect',

            
            'beforeselect',

            
            'deselect',

            
            'select'
        );
        this.views = [];
        this.callParent(arguments);
    },

    bindComponent: function(view) {
        var me = this;

        me.views = me.views || [];
        me.views.push(view);
        me.bindStore(view.getStore(), true);

        view.on({
            itemmousedown: me.onRowMouseDown,
            scope: me
        });

        if (me.enableKeyNav) {
            me.initKeyNav(view);
        }
    },

    initKeyNav: function(view) {
        var me = this;

        if (!view.rendered) {
            view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true});
            return;
        }

        
        
        view.el.set({
            tabIndex: -1
        });

        
        me.keyNav = new Ext.util.KeyNav({
            target: view,
            ignoreInputFields: true,
            eventName: 'itemkeydown',
            processEvent: function(view, record, node, index, event) {
                event.record = record;
                event.recordIndex = index;
                return event;
            },
            up: me.onKeyUp,
            down: me.onKeyDown,
            right: me.onKeyRight,
            left: me.onKeyLeft,
            pageDown: me.onKeyPageDown,
            pageUp: me.onKeyPageUp,
            home: me.onKeyHome,
            end: me.onKeyEnd,
            space: me.onKeySpace,
            enter: me.onKeyEnter,
            scope: me
        });
    },

    
    
    
    getRowsVisible: function() {
        var rowsVisible = false,
            view = this.views[0],
            row = view.getNode(0),
            rowHeight, gridViewHeight;

        if (row) {
            rowHeight = Ext.fly(row).getHeight();
            gridViewHeight = view.el.getHeight();
            rowsVisible = Math.floor(gridViewHeight / rowHeight);
        }

        return rowsVisible;
    },

    
    onKeyEnd: function(e) {
        var me = this,
            last = me.store.getAt(me.store.getCount() - 1);

        if (last) {
            if (e.shiftKey) {
                me.selectRange(last, me.lastFocused || 0);
                me.setLastFocused(last);
            } else if (e.ctrlKey) {
                me.setLastFocused(last);
            } else {
                me.doSelect(last);
            }
        }
    },

    
    onKeyHome: function(e) {
        var me = this,
            first = me.store.getAt(0);

        if (first) {
            if (e.shiftKey) {
                me.selectRange(first, me.lastFocused || 0);
                me.setLastFocused(first);
            } else if (e.ctrlKey) {
                me.setLastFocused(first);
            } else {
                me.doSelect(first, false);
            }
        }
    },

    
    onKeyPageUp: function(e) {
        var me = this,
            rowsVisible = me.getRowsVisible(),
            selIdx,
            prevIdx,
            prevRecord;

        if (rowsVisible) {
            selIdx = e.recordIndex;
            prevIdx = selIdx - rowsVisible;
            if (prevIdx < 0) {
                prevIdx = 0;
            }
            prevRecord = me.store.getAt(prevIdx);
            if (e.shiftKey) {
                me.selectRange(prevRecord, e.record, e.ctrlKey, 'up');
                me.setLastFocused(prevRecord);
            } else if (e.ctrlKey) {
                e.preventDefault();
                me.setLastFocused(prevRecord);
            } else {
                me.doSelect(prevRecord);
            }

        }
    },

    
    onKeyPageDown: function(e) {
        var me = this,
            rowsVisible = me.getRowsVisible(),
            selIdx,
            nextIdx,
            nextRecord;

        if (rowsVisible) {
            selIdx = e.recordIndex;
            nextIdx = selIdx + rowsVisible;
            if (nextIdx >= me.store.getCount()) {
                nextIdx = me.store.getCount() - 1;
            }
            nextRecord = me.store.getAt(nextIdx);
            if (e.shiftKey) {
                me.selectRange(nextRecord, e.record, e.ctrlKey, 'down');
                me.setLastFocused(nextRecord);
            } else if (e.ctrlKey) {
                
                
                e.preventDefault();
                me.setLastFocused(nextRecord);
            } else {
                me.doSelect(nextRecord);
            }
        }
    },

    
    
    onKeySpace: function(e) {
        var me = this,
            record = me.lastFocused;

        if (record) {
            if (me.isSelected(record)) {
                me.doDeselect(record, false);
            } else {
                me.doSelect(record, true);
            }
        }
    },
    
    onKeyEnter: Ext.emptyFn,

    
    
    
    onKeyUp: function(e) {
        var me = this,
            idx  = me.store.indexOf(me.lastFocused),
            record;

        if (idx > 0) {
            
            
            record = me.store.getAt(idx - 1);
            if (e.shiftKey && me.lastFocused) {
                if (me.isSelected(me.lastFocused) && me.isSelected(record)) {
                    me.doDeselect(me.lastFocused, true);
                    me.setLastFocused(record);
                } else if (!me.isSelected(me.lastFocused)) {
                    me.doSelect(me.lastFocused, true);
                    me.doSelect(record, true);
                } else {
                    me.doSelect(record, true);
                }
            } else if (e.ctrlKey) {
                me.setLastFocused(record);
            } else {
                me.doSelect(record);
                
            }
        }
        
        
        
        
        
        
        
    },

    
    
    
    onKeyDown: function(e) {
        var me = this,
            idx  = me.store.indexOf(me.lastFocused),
            record;

        
        
        if (idx + 1 < me.store.getCount()) {
            record = me.store.getAt(idx + 1);
            if (me.selected.getCount() === 0) {
                if (!e.ctrlKey) {
                    me.doSelect(record);
                } else {
                    me.setLastFocused(record);
                }
                
            } else if (e.shiftKey && me.lastFocused) {
                if (me.isSelected(me.lastFocused) && me.isSelected(record)) {
                    me.doDeselect(me.lastFocused, true);
                    me.setLastFocused(record);
                } else if (!me.isSelected(me.lastFocused)) {
                    me.doSelect(me.lastFocused, true);
                    me.doSelect(record, true);
                } else {
                    me.doSelect(record, true);
                }
            } else if (e.ctrlKey) {
                me.setLastFocused(record);
            } else {
                me.doSelect(record);
                
            }
        }
    },

    scrollByDeltaX: function(delta) {
        var view    = this.views[0],
            section = view.up(),
            hScroll = section.horizontalScroller;

        if (hScroll) {
            hScroll.scrollByDeltaX(delta);
        }
    },

    onKeyLeft: function(e) {
        this.scrollByDeltaX(-this.deltaScroll);
    },

    onKeyRight: function(e) {
        this.scrollByDeltaX(this.deltaScroll);
    },

    
    
    onRowMouseDown: function(view, record, item, index, e) {
        if (!this.allowRightMouseSelection(e)) {
            return;
        }

        if (e.button === 0 || !this.isSelected(record)) {
            this.selectWithEvent(record, e);
        }
    },
    
    
    allowRightMouseSelection: function(e) {
        var disallow = this.ignoreRightMouseSelection && e.button !== 0;
        if (disallow) {
            disallow = this.hasSelection();
        }
        return !disallow;
    },

    
    
    onSelectChange: function(record, isSelected, suppressEvent, commitFn) {
        var me      = this,
            views   = me.views,
            viewsLn = views.length,
            store   = me.store,
            rowIdx  = store.indexOf(record),
            eventName = isSelected ? 'select' : 'deselect',
            i = 0;

        if ((suppressEvent || me.fireEvent('before' + eventName, me, record, rowIdx)) !== false &&
                commitFn() !== false) {

            for (; i < viewsLn; i++) {
                if (isSelected) {
                    views[i].onRowSelect(rowIdx, suppressEvent);
                } else {
                    views[i].onRowDeselect(rowIdx, suppressEvent);
                }
            }

            if (!suppressEvent) {
                me.fireEvent(eventName, me, record, rowIdx);
            }
        }
    },

    
    
    onLastFocusChanged: function(oldFocused, newFocused, supressFocus) {
        var views   = this.views,
            viewsLn = views.length,
            store   = this.store,
            rowIdx,
            i = 0;

        if (oldFocused) {
            rowIdx = store.indexOf(oldFocused);
            if (rowIdx != -1) {
                for (; i < viewsLn; i++) {
                    views[i].onRowFocus(rowIdx, false);
                }
            }
        }

        if (newFocused) {
            rowIdx = store.indexOf(newFocused);
            if (rowIdx != -1) {
                for (i = 0; i < viewsLn; i++) {
                    views[i].onRowFocus(rowIdx, true, supressFocus);
                }
            }
        }
        this.callParent();
    },

    onEditorTab: function(editingPlugin, e) {
        var me = this,
            view = me.views[0],
            record = editingPlugin.getActiveRecord(),
            header = editingPlugin.getActiveColumn(),
            position = view.getPosition(record, header),
            direction = e.shiftKey ? 'left' : 'right';

        do {
            position  = view.walkCells(position, direction, e, me.preventWrap);
        } while(position && !view.headerCt.getHeaderAtIndex(position.column).getEditor());

        if (position) {
            editingPlugin.startEditByPosition(position);
        }
    },


    
    getCurrentPosition: function() {
        var firstSelection = this.selected.items[0];
        if (firstSelection) {
            return {
                row: this.store.indexOf(firstSelection),
                column: 0
            };
        }
    },

    selectByPosition: function(position) {
        var record = this.store.getAt(position.row);
        this.select(record);
    },


    
    selectNext: function(keepExisting, suppressEvent) {
        var me = this,
            store = me.store,
            selection = me.getSelection(),
            record = selection[selection.length - 1],
            index = store.indexOf(record) + 1,
            success;

        if(index === store.getCount() || index === 0) {
            success = false;
        } else {
            me.doSelect(index, keepExisting, suppressEvent);
            success = true;
        }
        return success;
    },

    
    selectPrevious: function(keepExisting, suppressEvent) {
        var me = this,
            selection = me.getSelection(),
            record = selection[0],
            index = me.store.indexOf(record) - 1,
            success;

        if (index < 0) {
            success = false;
        } else {
            me.doSelect(index, keepExisting, suppressEvent);
            success = true;
        }
        return success;
    }
});

Ext.define('Ext.selection.CheckboxModel', {
    alias: 'selection.checkboxmodel',
    extend: 'Ext.selection.RowModel',

    
    mode: 'MULTI',

    
    injectCheckbox: 0,

    
    checkOnly: false,
    
    
    showHeaderCheckbox: true,

    headerWidth: 24,

    
    checkerOnCls: Ext.baseCSSPrefix + 'grid-hd-checker-on',

    
    refreshOnRemove: true,

    beforeViewRender: function(view) {
        var me = this;
        me.callParent(arguments);

        
        if (!me.hasLockedHeader() || view.headerCt.lockedCt) {
            if (me.showHeaderCheckbox !== false) {
                view.headerCt.on('headerclick', me.onHeaderClick, me);
            }
            me.addCheckbox(view, true);
            me.mon(view.ownerCt, 'reconfigure', me.onReconfigure, me);
        }
    },

    bindComponent: function(view) {
        var me = this;
        me.sortable = false;
        me.callParent(arguments);
    },

    hasLockedHeader: function(){
        var views     = this.views,
            vLen      = views.length,
            v;

        for (v = 0; v < vLen; v++) {
            if (views[v].headerCt.lockedCt) {
                return true;
            }
        }
        return false;
    },

    
    addCheckbox: function(view, initial){
        var me = this,
            checkbox = me.injectCheckbox,
            headerCt = view.headerCt;

        
        if (checkbox !== false) {
            if (checkbox == 'first') {
                checkbox = 0;
            } else if (checkbox == 'last') {
                checkbox = headerCt.getColumnCount();
            }
            Ext.suspendLayouts();
            headerCt.add(checkbox,  me.getHeaderConfig());
            Ext.resumeLayouts();
        }

        if (initial !== true) {
            view.refresh();
        }
    },

    
    onReconfigure: function(grid, store, columns) {
        if(columns) {
            this.addCheckbox(this.views[0]);
        }
    },

    
    toggleUiHeader: function(isChecked) {
        var view     = this.views[0],
            headerCt = view.headerCt,
            checkHd  = headerCt.child('gridcolumn[isCheckerHd]');

        if (checkHd) {
            if (isChecked) {
                checkHd.el.addCls(this.checkerOnCls);
            } else {
                checkHd.el.removeCls(this.checkerOnCls);
            }
        }
    },

    
    onHeaderClick: function(headerCt, header, e) {
        if (header.isCheckerHd) {
            e.stopEvent();
            var me = this,
                isChecked = header.el.hasCls(Ext.baseCSSPrefix + 'grid-hd-checker-on');
                
            
            me.preventFocus = true;
            if (isChecked) {
                me.deselectAll();
            } else {
                me.selectAll();
            }
            delete me.preventFocus;
        }
    },

    
    getHeaderConfig: function() {
        var me = this,
            showCheck = me.showHeaderCheckbox !== false;

        return {
            isCheckerHd: showCheck,
            text : '&#160;',
            width: me.headerWidth,
            sortable: false,
            draggable: false,
            resizable: false,
            hideable: false,
            menuDisabled: true,
            dataIndex: '',
            cls: showCheck ? Ext.baseCSSPrefix + 'column-header-checkbox ' : '',
            renderer: Ext.Function.bind(me.renderer, me),
            editRenderer: me.editRenderer || me.renderEmpty,
            locked: me.hasLockedHeader()
        };
    },
    
    renderEmpty: function(){
        return '&#160;';    
    },

    
    renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
        var baseCSSPrefix = Ext.baseCSSPrefix;
        metaData.tdCls = baseCSSPrefix + 'grid-cell-special ' + baseCSSPrefix + 'grid-cell-row-checker';
        return '<div class="' + baseCSSPrefix + 'grid-row-checker">&#160;</div>';
    },

    
    onRowMouseDown: function(view, record, item, index, e) {
        view.el.focus();
        var me = this,
            checker = e.getTarget('.' + Ext.baseCSSPrefix + 'grid-row-checker'),
            mode;
            
        if (!me.allowRightMouseSelection(e)) {
            return;
        }

        
        if (me.checkOnly && !checker) {
            return;
        }

        if (checker) {
            mode = me.getSelectionMode();
            
            
            if (mode !== 'SINGLE') {
                me.setSelectionMode('SIMPLE');
            }
            me.selectWithEvent(record, e);
            me.setSelectionMode(mode);
        } else {
            me.selectWithEvent(record, e);
        }
    },

    
    onSelectChange: function() {
        var me = this;
        me.callParent(arguments);
        me.updateHeaderState();
    },

    
    onStoreLoad: function() {
        var me = this;
        me.callParent(arguments);
        me.updateHeaderState();
    },

    
    updateHeaderState: function() {
        
        var hdSelectStatus = this.selected.getCount() === this.store.getCount();
        this.toggleUiHeader(hdSelectStatus);
    }
});


Ext.define('Ext.selection.TreeModel', {
    extend: 'Ext.selection.RowModel',
    alias: 'selection.treemodel',
    
    
    
    
    pruneRemoved: false,
    
    onKeyRight: function(e, t) {
        var focused = this.getLastFocused(),
            view    = this.view;
            
        if (focused) {
            
            
            
            if (focused.isExpanded()) {
                this.onKeyDown(e, t);
            
            } else if (focused.isExpandable()) {
                view.expand(focused);
            }
        }
    },
    
    onKeyLeft: function(e, t) {
        var focused = this.getLastFocused(),
            view    = this.view,
            viewSm  = view.getSelectionModel(),
            parentNode, parentRecord;

        if (focused) {
            parentNode = focused.parentNode;
            
            if (focused.isExpanded()) {
                view.collapse(focused);
            
            
            } else if (parentNode && !parentNode.isRoot()) {
                
                if (e.shiftKey) {
                    viewSm.selectRange(parentNode, focused, e.ctrlKey, 'up');
                    viewSm.setLastFocused(parentNode);
                
                } else if (e.ctrlKey) {
                    viewSm.setLastFocused(parentNode);
                
                } else {
                    viewSm.select(parentNode);
                }
            }
        }
    },
    
    onKeySpace: function(e, t) {
        this.toggleCheck(e);
    },
    
    onKeyEnter: function(e, t) {
        this.toggleCheck(e);
    },
    
    toggleCheck: function(e){
        e.stopEvent();
        var selected = this.getLastSelected();
        if (selected) {
            this.view.onCheckChange(selected);
        }
    }
});


Ext.define('Ext.tab.Tab', {
    extend: 'Ext.button.Button',
    alias: 'widget.tab',

    requires: [
        'Ext.layout.component.Tab',
        'Ext.util.KeyNav'
    ],

    componentLayout: 'tab',

    
    isTab: true,

    baseCls: Ext.baseCSSPrefix + 'tab',

    
    activeCls: 'active',

    

    
    closableCls: 'closable',

    
    closable: true,

    
    
    closeText: 'Close Tab',
    

    
    active: false,

    

    childEls: [
        'closeEl'
    ],

    scale: false,

    position: 'top',

    initComponent: function() {
        var me = this;

        me.addEvents(
            
            'activate',

            
            'deactivate',

            
            'beforeclose',

            
            'close'
        );

        me.callParent(arguments);

        if (me.card) {
            me.setCard(me.card);
        }
    },

    getTemplateArgs: function() {
        var me = this,
            result = me.callParent();

        result.closable = me.closable;
        result.closeText = me.closeText;

        return result;
    },

    beforeRender: function() {
        var me = this,
            tabBar = me.up('tabbar'),
            tabPanel = me.up('tabpanel');
        
        me.callParent();
        
        me.addClsWithUI(me.position);

        
        

        me.syncClosableUI();

        
        if (!me.minWidth) {
            me.minWidth = (tabBar) ? tabBar.minTabWidth : me.minWidth;
            if (!me.minWidth && tabPanel) {
                me.minWidth = tabPanel.minTabWidth;
            }
            if (me.minWidth && me.iconCls) {
                me.minWidth += 25;
            }
        }
        if (!me.maxWidth) {
            me.maxWidth = (tabBar) ? tabBar.maxTabWidth : me.maxWidth;
            if (!me.maxWidth && tabPanel) {
                me.maxWidth = tabPanel.maxTabWidth;
            }
        }
    },

    onRender: function() {
        var me = this;

        me.callParent(arguments);

        me.keyNav = new Ext.util.KeyNav(me.el, {
            enter: me.onEnterKey,
            del: me.onDeleteKey,
            scope: me
        });
    },

    
    enable : function(silent) {
        var me = this;

        me.callParent(arguments);

        me.removeClsWithUI(me.position + '-disabled');

        return me;
    },

    
    disable : function(silent) {
        var me = this;

        me.callParent(arguments);

        me.addClsWithUI(me.position + '-disabled');

        return me;
    },

    onDestroy: function() {
        var me = this;

        Ext.destroy(me.keyNav);
        delete me.keyNav;

        me.callParent(arguments);
    },

    
    setClosable: function(closable) {
        var me = this;

        
        closable = (!arguments.length || !!closable);

        if (me.closable != closable) {
            me.closable = closable;

            
            if (me.card) {
                me.card.closable = closable;
            }

            me.syncClosableUI();

            if (me.rendered) {
                me.syncClosableElements();

                
                me.updateLayout();
            }
        }
    },

    
    syncClosableElements: function () {
        var me = this,
            closeEl = me.closeEl;

        if (me.closable) {
            if (!closeEl) {
                me.closeEl = me.btnWrap.insertSibling({
                    tag: 'a',
                    cls: me.baseCls + '-close-btn',
                    href: '#',
                    title: me.closeText
                }, 'after');
            }
        } else if (closeEl) {
            closeEl.remove();
            delete me.closeEl;
        }
    },

    
    syncClosableUI: function () {
        var me = this,
            classes = [me.closableCls, me.closableCls + '-' + me.position];

        if (me.closable) {
            me.addClsWithUI(classes);
        } else {
            me.removeClsWithUI(classes);
        }
    },

    
    setCard: function(card) {
        var me = this;

        me.card = card;
        me.setText(me.title || card.title);
        me.setIconCls(me.iconCls || card.iconCls);
        me.setIcon(me.icon || card.icon);
    },

    
    onCloseClick: function() {
        var me = this;

        if (me.fireEvent('beforeclose', me) !== false) {
            if (me.tabBar) {
                if (me.tabBar.closeTab(me) === false) {
                    
                    return;
                }
            } else {
                
                me.fireClose();
            }
        }
    },

    
    fireClose: function(){
        this.fireEvent('close', this);
    },

    
    onEnterKey: function(e) {
        var me = this;

        if (me.tabBar) {
            me.tabBar.onClick(e, me.el);
        }
    },

   
    onDeleteKey: function(e) {
        if (this.closable) {
            this.onCloseClick();
        }
    },

    
    activate : function(supressEvent) {
        var me = this;

        me.active = true;
        me.addClsWithUI([me.activeCls, me.position + '-' + me.activeCls]);

        if (supressEvent !== true) {
            me.fireEvent('activate', me);
        }
    },

    
    deactivate : function(supressEvent) {
        var me = this;

        me.active = false;
        me.removeClsWithUI([me.activeCls, me.position + '-' + me.activeCls]);

        if (supressEvent !== true) {
            me.fireEvent('deactivate', me);
        }
    }
});


Ext.define('Ext.tab.Bar', {
    extend: 'Ext.panel.Header',
    alias: 'widget.tabbar',
    baseCls: Ext.baseCSSPrefix + 'tab-bar',

    requires: ['Ext.tab.Tab'],

    
    isTabBar: true,
    
    
    
    

    
    defaultType: 'tab',

    
    plain: false,

    childEls: [
        'body', 'strip'
    ],

    
    renderTpl: [
        '<div id="{id}-body" class="{baseCls}-body {bodyCls}<tpl if="ui"> {baseCls}-body-{ui}<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',
            '{%this.renderContainer(out,values)%}',
        '</div>',
        '<div id="{id}-strip" class="{baseCls}-strip<tpl if="ui"> {baseCls}-strip-{ui}<tpl for="uiCls"> {parent.baseCls}-strip-{parent.ui}-{.}</tpl></tpl>"></div>'
    ],

    

    

    
    initComponent: function() {
        var me = this;

        if (me.plain) {
            me.setUI(me.ui + '-plain');
        }

        me.addClsWithUI(me.dock);

        me.addEvents(
            
            'change'
        );

        
        me.callParent(arguments);

        
        me.layout.align = (me.orientation == 'vertical') ? 'left' : 'top';
        me.layout.overflowHandler = new Ext.layout.container.boxOverflow.Scroller(me.layout);

        me.remove(me.titleCmp);
        delete me.titleCmp;

        Ext.apply(me.renderData, {
            bodyCls: me.bodyCls
        });
    },

    getLayout: function() {
        var me = this;
        me.layout.type = (me.dock === 'top' || me.dock === 'bottom') ? 'hbox' : 'vbox';
        return me.callParent(arguments);
    },

    
    onAdd: function(tab) {
        tab.position = this.dock;
        this.callParent(arguments);
    },
    
    onRemove: function(tab) {
        var me = this;
        
        if (tab === me.previousTab) {
            me.previousTab = null;
        }
        me.callParent(arguments);    
    },

    afterComponentLayout : function(width) {
        this.callParent(arguments);
        this.strip.setWidth(width);
    },

    
    onClick: function(e, target) {
        
        var me = this,
            tabEl = e.getTarget('.' + Ext.tab.Tab.prototype.baseCls),
            tab = tabEl && Ext.getCmp(tabEl.id),
            tabPanel = me.tabPanel,
            isCloseClick = tab && tab.closeEl && (target === tab.closeEl.dom);

        if (isCloseClick) {
            e.preventDefault();
        }
        if (tab && tab.isDisabled && !tab.isDisabled()) {
            if (tab.closable && isCloseClick) {
                tab.onCloseClick();
            } else {
                if (tabPanel) {
                    
                    tabPanel.setActiveTab(tab.card);
                } else {
                    me.setActiveTab(tab);
                }
                tab.focus();
            }
        }
    },

    
    closeTab: function(toClose) {
        var me = this,
            card = toClose.card,
            tabPanel = me.tabPanel,
            toActivate;

        if (card && card.fireEvent('beforeclose', card) === false) {
            return false;
        }
        
        
        
        
        toActivate = me.findNextActivatable(toClose);

        
        
        Ext.suspendLayouts();

        if (tabPanel && card) {
            
            
            delete toClose.ownerCt;
            
            
            
            card.fireEvent('close', card);
            tabPanel.remove(card);
            
            
            if (!tabPanel.getComponent(card)) {
                
                toClose.fireClose();
                me.remove(toClose);
            } else {
                
                toClose.ownerCt = me;
                Ext.resumeLayouts(true);
                return false;
            }
        }

        
        if (toActivate) {
            
            
            if (tabPanel) {
                tabPanel.setActiveTab(toActivate.card);
            } else {
                me.setActiveTab(toActivate);
            }
            toActivate.focus();
        }
        Ext.resumeLayouts(true);
    },

    
    
    findNextActivatable: function(toClose) {
        var me = this;
        if (toClose.active && me.items.getCount() > 1) {
            return (me.previousTab && me.previousTab !== toClose && !me.previousTab.disabled) ? me.previousTab : (toClose.next('tab[disabled=false]') || toClose.prev('tab[disabled=false]'));
        }
    },

    
    setActiveTab: function(tab) {
        var me = this;

        if (!tab.disabled && tab !== me.activeTab) {
            if (me.activeTab) {
                if (me.activeTab.isDestroyed) {
                    me.previousTab = null;
                } else {
                    me.previousTab = me.activeTab;
                    me.activeTab.deactivate();
                }
            }
            tab.activate();

            me.activeTab = tab;
            me.fireEvent('change', me, tab, tab.card);

            
            me.on({
                afterlayout: me.afterTabActivate,
                scope: me,
                single: true
            });
            me.updateLayout();
        }
    },

    afterTabActivate: function() {
        this.layout.overflowHandler.scrollToItem(this.activeTab);
    }
});


Ext.define('Ext.toolbar.Fill', {
    extend: 'Ext.Component',
    alias: 'widget.tbfill',
    alternateClassName: 'Ext.Toolbar.Fill',
    
    isFill : true,
    flex: 1
});

Ext.define('Ext.toolbar.Item', {
    extend: 'Ext.Component',
    alias: 'widget.tbitem',
    alternateClassName: 'Ext.Toolbar.Item',
    enable:Ext.emptyFn,
    disable:Ext.emptyFn,
    focus:Ext.emptyFn
    
});

Ext.define('Ext.toolbar.Separator', {
    extend: 'Ext.toolbar.Item',
    alias: 'widget.tbseparator',
    alternateClassName: 'Ext.Toolbar.Separator',
    baseCls: Ext.baseCSSPrefix + 'toolbar-separator',
    focusable: false,
    
    border: true
});

Ext.define('Ext.layout.container.boxOverflow.Menu', {

    

    extend: 'Ext.layout.container.boxOverflow.None',
    requires: ['Ext.toolbar.Separator', 'Ext.button.Button'],
    alternateClassName: 'Ext.layout.boxOverflow.Menu',
    
    

    

    
    noItemsMenuText : '<div class="' + Ext.baseCSSPrefix + 'toolbar-no-items">(None)</div>',

    constructor: function(layout) {
        var me = this;

        me.callParent(arguments);

        me.triggerButtonCls = me.triggerButtonCls || Ext.baseCSSPrefix + 'box-menu-' + layout.getNames().right;
        
        me.menuItems = [];
    },

    beginLayout: function (ownerContext) {
        this.callParent(arguments);

        
        
        this.clearOverflow(ownerContext);
    },

    beginLayoutCycle: function (ownerContext, firstCycle) {
        this.callParent(arguments);

        if (!firstCycle) {
            
            
            this.clearOverflow(ownerContext);

            this.layout.cacheChildItems(ownerContext);
        }
    },

    onRemove: function(comp){
        Ext.Array.remove(this.menuItems, comp);
    },

    
    getSuffixConfig: function() {
        var me = this,
            layout = me.layout,
            oid = layout.owner.id;

        
        me.menu = new Ext.menu.Menu({
            listeners: {
                scope: me,
                beforeshow: me.beforeMenuShow
            }
        });

        
        me.menuTrigger = new Ext.button.Button({
            id      : oid + '-menu-trigger',
            cls     : Ext.layout.container.Box.prototype.innerCls + ' ' + me.triggerButtonCls,
            hidden  : true,
            ownerCt : layout.owner, 
            ownerLayout: layout,
            iconCls : Ext.baseCSSPrefix + me.getOwnerType(layout.owner) + '-more-icon',
            ui      : layout.owner instanceof Ext.toolbar.Toolbar ? 'default-toolbar' : 'default',
            menu    : me.menu,
            getSplitCls: function() { return '';}
        });

        return me.menuTrigger.getRenderTree();
    },
    
    getOverflowCls: function() {
        return Ext.baseCSSPrefix + this.layout.direction + '-box-overflow-body';
    },

    handleOverflow: function(ownerContext) {
        var me = this,
            layout = me.layout,
            names = layout.getNames(),
            plan = ownerContext.state.boxPlan,
            posArgs = [null, null];

        me.showTrigger(ownerContext);

        
        
        posArgs[names.heightIndex] = (plan.maxSize - me.menuTrigger[names.getHeight]()) / 2;
        me.menuTrigger.setPosition.apply(me.menuTrigger, posArgs);

        return {
            reservedSpace: me.menuTrigger[names.getWidth]()
        };
    },

    
    captureChildElements: function() {
        var menuTrigger = this.menuTrigger;
        if (menuTrigger.rendering) {
            menuTrigger.finishRender();
        }
    },

    _asLayoutRoot: { isRoot: true },

    
    clearOverflow: function(ownerContext) {
        var me = this,
            items = me.menuItems,
            item,
            i = 0,
            length = items.length,
            owner = me.layout.owner,
            asLayoutRoot = me._asLayoutRoot;

        owner.suspendLayouts();
        me.captureChildElements();
        me.hideTrigger();
        owner.resumeLayouts();

        for (; i < length; i++) {
            item = items[i];

            
            
            item.suspendLayouts();
            item.show();
            item.resumeLayouts(asLayoutRoot);
        }

        items.length = 0;
    },

    
    showTrigger: function(ownerContext) {
        var me = this,
            layout = me.layout,
            owner = layout.owner,
            names = layout.getNames(),
            startProp = names.x,
            sizeProp = names.width,
            plan = ownerContext.state.boxPlan,
            available = plan.targetSize[sizeProp],
            childItems = ownerContext.childItems,
            len = childItems.length,
            menuTrigger = me.menuTrigger,
            childContext,
            comp, i, props;

        
        
        menuTrigger.suspendLayouts();
        menuTrigger.show();
        menuTrigger.resumeLayouts(me._asLayoutRoot);

        available -= me.menuTrigger.getWidth();

        owner.suspendLayouts();

        
        
        me.menuItems.length = 0;
        for (i = 0; i < len; i++) {
            childContext = childItems[i];
            props = childContext.props;
            if (props[startProp] + props[sizeProp] > available) {
                comp = childContext.target;
                me.menuItems.push(comp);
                comp.hide();
            }
        }

        owner.resumeLayouts();
    },

    
    hideTrigger: function() {
        var menuTrigger = this.menuTrigger;
        if (menuTrigger) {
            menuTrigger.hide();
        }
    },

    
    beforeMenuShow: function(menu) {
        var me = this,
            items = me.menuItems,
            i = 0,
            len   = items.length,
            item,
            prev,
            needsSep = function(group, prev){
                return group.isXType('buttongroup') && !(prev instanceof Ext.toolbar.Separator);
            };

        menu.suspendLayouts();
        me.clearMenu();
        menu.removeAll();

        for (; i < len; i++) {
            item = items[i];

            
            if (!i && (item instanceof Ext.toolbar.Separator)) {
                continue;
            }
            if (prev && (needsSep(item, prev) || needsSep(prev, item))) {
                menu.add('-');
            }

            me.addComponentToMenu(menu, item);
            prev = item;
        }

        
        if (menu.items.length < 1) {
            menu.add(me.noItemsMenuText);
        }
        menu.resumeLayouts();
    },
    
    
    createMenuConfig : function(component, hideOnClick) {
        var config = Ext.apply({}, component.initialConfig),
            group  = component.toggleGroup;

        Ext.copyTo(config, component, [
            'iconCls', 'icon', 'itemId', 'disabled', 'handler', 'scope', 'menu'
        ]);

        Ext.apply(config, {
            text       : component.overflowText || component.text,
            hideOnClick: hideOnClick,
            destroyMenu: false
        });

        
        if (component.isFormField) {
            config.value = component.getValue();

            
            if (!config.listeners) {
                config.listeners = {};
            }

            
            
            
            
            
            config.listeners.change = function(c, newVal, oldVal) {                            
                component.setValue(newVal);
            }
        }

        
        else if (group || component.enableToggle) {
            Ext.apply(config, {
                iconAlign: 'right',
                hideOnClick: false,
                group  : group,
                checked: component.pressed,
                listeners: {
                    checkchange: function(item, checked) {
                        component.toggle(checked);
                    }
                }
            });
        }

        delete config.ownerCt;
        delete config.xtype;
        delete config.id;
        return config;
    },

    
    addComponentToMenu : function(menu, component) {
        var me = this,
        i, items, iLen;

        if (component instanceof Ext.toolbar.Separator) {
            menu.add('-');
        } else if (component.isComponent) {
            if (component.isXType('splitbutton')) {
                menu.add(me.createMenuConfig(component, true));

            } else if (component.isXType('button')) {
                menu.add(me.createMenuConfig(component, !component.menu));

            } else if (component.isXType('buttongroup')) {
                items = component.items.items;
                iLen  = items.length;

                for (i = 0; i < iLen; i++) {
                    me.addComponentToMenu(menu, items[i]);
                }
            } else {
                menu.add(Ext.create(Ext.getClassName(component), me.createMenuConfig(component)));
            }
        }
    },

    
    clearMenu : function() {
        var menu = this.menu,
            items, i, iLen, item;
        
        if (menu && menu.items) {
            items = menu.items.items;
            iLen  = items.length;
            
            for (i = 0; i < iLen; i++) {
                item = items[i];
                if (item.setMenu) {
                    item.setMenu(null);
                }
            }
        }
    },

    
    destroy: function() {
        var trigger = this.menuTrigger;
            
        if (trigger && !this.layout.owner.items.contains(trigger)) {
            
            
            delete trigger.ownerCt;
        }
        Ext.destroy(this.menu, trigger);
    }
});


Ext.define('Ext.layout.container.Box', {

    

    alias: ['layout.box'],
    extend: 'Ext.layout.container.Container',
    alternateClassName: 'Ext.layout.BoxLayout',

    requires: [
        'Ext.layout.container.boxOverflow.None',
        'Ext.layout.container.boxOverflow.Menu',
        'Ext.layout.container.boxOverflow.Scroller',
        'Ext.util.Format',
        'Ext.dd.DragDropManager'
    ],

    

    
    defaultMargins: {
        top: 0,
        right: 0,
        bottom: 0,
        left: 0
    },

    
    padding: 0,

    
    pack: 'start',

    
    flex: undefined,

    
    stretchMaxPartner: undefined,

    type: 'box',
    scrollOffset: 0,
    itemCls: Ext.baseCSSPrefix + 'box-item',
    targetCls: Ext.baseCSSPrefix + 'box-layout-ct',
    innerCls: Ext.baseCSSPrefix + 'box-inner',

    
    
    availableSpaceOffset: 0,

    
    reserveOffset: true,

    manageMargins: true,

    childEls: [
        'innerCt',
        'targetEl'
    ],

    renderTpl: [
        '{%var oc,l=values.$comp.layout,oh=l.overflowHandler;',
        'if (oh.getPrefixConfig!==Ext.emptyFn) {',
            'if(oc=oh.getPrefixConfig())dh.generateMarkup(oc, out)',
        '}%}',
        '<div id="{ownerId}-innerCt" class="{[l.innerCls]} {[oh.getOverflowCls()]}" role="presentation">',
            '<div id="{ownerId}-targetEl" style="position:absolute;',
                    
                    
                    
                    
                    
                    'width:20000px;',
                    
                    
                    
                    
                    
                    'left:0px;top:0px;',
                    
                    
                    'height:1px">',
                '{%this.renderBody(out, values)%}',
            '</div>',
        '</div>',
        '{%if (oh.getSuffixConfig!==Ext.emptyFn) {',
            'if(oc=oh.getSuffixConfig())dh.generateMarkup(oc, out)',
        '}%}',
        {
            disableFormats: true,
            definitions: 'var dh=Ext.DomHelper;'
        }
    ],

    constructor: function(config) {
        var me = this,
            type;

        me.callParent(arguments);

        
        me.flexSortFn = Ext.Function.bind(me.flexSort, me);

        me.initOverflowHandler();

        type = typeof me.padding;
        if (type == 'string' || type == 'number') {
            me.padding = Ext.util.Format.parseBox(me.padding);
            me.padding.height = me.padding.top  + me.padding.bottom;
            me.padding.width  = me.padding.left + me.padding.right;
        }
    },

    getNames: function () {
        return this.names;
    },

    
    
    _percentageRe: /^\s*(\d+(?:\.\d*)?)\s*[%]\s*$/,

    getItemSizePolicy: function (item, ownerSizeModel) {
        var me = this,
            policy = me.sizePolicy,
            align = me.align,
            flex = item.flex,
            key = align,
            names = me.names,
            width = item[names.width],
            height = item[names.height],
            percentageRe = me._percentageRe,
            percentageWidth = percentageRe.test(width),
            isStretch = (align == 'stretch');
            
        if ((isStretch || flex || percentageWidth) && !ownerSizeModel) {
            ownerSizeModel = me.owner.getSizeModel();
        }

        if (isStretch) {
            
            
            if (!percentageRe.test(height) && ownerSizeModel[names.height].shrinkWrap) {
                key = 'stretchmax';
                
                
                
            }
        } else if (align != 'stretchmax') {
            if (percentageRe.test(height)) {
                
                
                key = 'stretch';
            } else {
                key = '';
            }
        }

        if (flex || percentageWidth) {
            
            
            if (!ownerSizeModel[names.width].shrinkWrap) {
                policy = policy.flex; 
            }
        }

        return policy[key];
    },

    flexSort: function (a, b) {
        var maxWidthName = this.getNames().maxWidth,
            infiniteValue = Infinity;

        a = a.target[maxWidthName] || infiniteValue;
        b = b.target[maxWidthName] || infiniteValue;

        
        if (!isFinite(a) && !isFinite(b)) {
            return 0;
        }

        return a - b;
    },

    isItemBoxParent: function (itemContext) {
        return true;
    },

    isItemShrinkWrap: function (item) {
        return true;
    },

    
    minSizeSortFn: function(a, b) {
        return b.available - a.available;
    },

    roundFlex: function(width) {
        return Math.ceil(width);
    },

    
    beginCollapse: function(child) {
        var me = this;

        if (me.direction === 'vertical' && child.collapsedVertical()) {
            child.collapseMemento.capture(['flex']);
            delete child.flex;
        } else if (me.direction === 'horizontal' && child.collapsedHorizontal()) {
            child.collapseMemento.capture(['flex']);
            delete child.flex;
        }
    },

    
    beginExpand: function(child) {

        
        child.collapseMemento.restore(['flex']);
    },

    beginLayout: function (ownerContext) {
        var me = this,
            smp = me.owner.stretchMaxPartner,
            style = me.innerCt.dom.style,
            names = me.getNames();

        ownerContext.boxNames = names;

        
        
        me.overflowHandler.beginLayout(ownerContext);

        
        if (typeof smp === 'string') {
            smp = Ext.getCmp(smp) || me.owner.query(smp)[0];
        }

        ownerContext.stretchMaxPartner = smp && ownerContext.context.getCmp(smp);

        me.callParent(arguments);

        ownerContext.innerCtContext = ownerContext.getEl('innerCt', me);

        
        me.scrollParallel = !!(me.owner.autoScroll || me.owner[names.overflowX]);

        
        me.scrollPerpendicular = !!(me.owner.autoScroll || me.owner[names.overflowY]);

        
        if (me.scrollParallel) {
            me.scrollPos = me.owner.getTargetEl().dom[names.scrollLeft];
        }

        
        style.width = '';
        style.height = '';
    },

    beginLayoutCycle: function (ownerContext, firstCycle) {
        var me = this,
            align = me.align,
            names = ownerContext.boxNames,
            pack = me.pack,
            heightModelName = names.heightModel;

        
        
        me.overflowHandler.beginLayoutCycle(ownerContext, firstCycle);

        me.callParent(arguments);

        
        

        ownerContext.parallelSizeModel      = ownerContext[names.widthModel];
        ownerContext.perpendicularSizeModel = ownerContext[heightModelName];

        ownerContext.boxOptions = {
            align: align = {
                stretch:    align == 'stretch',
                stretchmax: align == 'stretchmax',
                center:     align == names.center
            },
            pack: pack = {
                center: pack == 'center',
                end:    pack == 'end'
            }
        };

        
        
        
        
        

        if (align.stretch && ownerContext.perpendicularSizeModel.shrinkWrap) {
            align.stretchmax = true;
            align.stretch = false;
        }

        
        align.nostretch = !(align.stretch || align.stretchmax);

        
        
        

        if (ownerContext.parallelSizeModel.shrinkWrap) {
            pack.center = pack.end = false;
        }

        me.cacheFlexes(ownerContext);

        
        
        
        if (Ext.isWebKit) {
            me.targetEl.setWidth(20000);
        }
    },

    
    cacheFlexes: function (ownerContext) {
        var me = this,
            names = ownerContext.boxNames,
            widthModelName = names.widthModel,
            heightModelName = names.heightModel,
            nostretch = ownerContext.boxOptions.align.nostretch,
            totalFlex = 0,
            childItems = ownerContext.childItems,
            i = childItems.length,
            flexedItems = [],
            minWidth = 0,
            minWidthName = names.minWidth,
            percentageRe = me._percentageRe,
            percentageWidths = 0,
            percentageHeights = 0,
            child, childContext, flex, match;

        while (i--) {
            childContext = childItems[i];
            child = childContext.target;

            
            
            
            if (childContext[widthModelName].calculated) {
                childContext.flex = flex = child.flex;
                if (flex) {
                    totalFlex += flex;
                    flexedItems.push(childContext);
                    minWidth += child[minWidthName] || 0;
                } else { 
                    match = percentageRe.exec(child[names.width]);
                    childContext.percentageParallel = parseFloat(match[1]) / 100;
                    ++percentageWidths;
                }
            }
            
            

            if (nostretch && childContext[heightModelName].calculated) {
                
                
                match = percentageRe.exec(child[names.height]);
                childContext.percentagePerpendicular = parseFloat(match[1]) / 100;
                ++percentageHeights;
            }
        }

        ownerContext.flexedItems = flexedItems;
        ownerContext.flexedMinSize = minWidth;
        ownerContext.totalFlex = totalFlex;
        ownerContext.percentageWidths = percentageWidths;
        ownerContext.percentageHeights = percentageHeights;

        
        
        
        Ext.Array.sort(flexedItems, me.flexSortFn);
    },

    calculate: function(ownerContext) {
        var me = this,
            targetSize = me.getContainerSize(ownerContext),
            names = ownerContext.boxNames,
            state = ownerContext.state,
            plan = state.boxPlan || (state.boxPlan = {});

        plan.targetSize = targetSize;

        
        if (!ownerContext.parallelSizeModel.shrinkWrap && !targetSize[names.gotWidth]) {
            me.done = false;
            return;
        }

        if (!state.parallelDone) {
            state.parallelDone = me.calculateParallel(ownerContext, names, plan);
        }

        if (!state.perpendicularDone) {
            state.perpendicularDone = me.calculatePerpendicular(ownerContext, names, plan);
        }

        if (state.parallelDone && state.perpendicularDone) {
            
            
            
            
            if (me.owner.dock && (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) && !me.owner.width && !me.horizontal) {
                plan.isIEVerticalDock = true;
                plan.calculatedWidth = plan.maxSize + ownerContext.getPaddingInfo().width + ownerContext.getFrameInfo().width;
            }

            me.publishInnerCtSize(ownerContext, me.reserveOffset ? me.availableSpaceOffset : 0);

            
            if (me.done && ownerContext.childItems.length > 1 && ownerContext.boxOptions.align.stretchmax && !state.stretchMaxDone) {
                me.calculateStretchMax(ownerContext, names, plan);
                state.stretchMaxDone = true;
            }
        } else {
            me.done = false;
        }
    },

    calculateParallel: function(ownerContext, names, plan) {
        var me = this,
            widthName = names.width,
            childItems = ownerContext.childItems,
            leftName = names.left,
            rightName = names.right,
            setWidthName = names.setWidth,
            childItemsLength = childItems.length,
            flexedItems = ownerContext.flexedItems,
            flexedItemsLength = flexedItems.length,
            pack = ownerContext.boxOptions.pack,
            padding = me.padding,
            containerWidth = plan.targetSize[widthName],
            totalMargin = 0,
            left = padding[leftName],
            nonFlexWidth = left + padding[rightName] + me.scrollOffset +
                                    (me.reserveOffset ? me.availableSpaceOffset : 0),
            scrollbarWidth = Ext.getScrollbarSize()[names.width],
            i, childMargins, remainingWidth, remainingFlex, childContext, flex, flexedWidth,
            contentWidth, mayNeedScrollbarAdjust, childWidth, percentageSpace;

        
        
        
        
        
        
        if (scrollbarWidth &&
            me.scrollPerpendicular &&
            ownerContext.parallelSizeModel.shrinkWrap &&
            !ownerContext.boxOptions.align.stretch &&
            !ownerContext.perpendicularSizeModel.shrinkWrap) {

            
            
            
            if (!ownerContext.state.perpendicularDone) {
                return false;
            }
            mayNeedScrollbarAdjust = true;
        }

        
        for (i = 0; i < childItemsLength; ++i) {
            childContext = childItems[i];
            childMargins = childContext.marginInfo || childContext.getMarginInfo();

            totalMargin += childMargins[widthName];

            if (!childContext[names.widthModel].calculated) {
                childWidth = childContext.getProp(widthName);
                nonFlexWidth += childWidth; 
                if (isNaN(nonFlexWidth)) {
                    return false;
                }
            }
        }

        nonFlexWidth += totalMargin;
        if (ownerContext.percentageWidths) {
            percentageSpace = containerWidth - totalMargin;
            if (isNaN(percentageSpace)) {
                return false;
            }

            for (i = 0; i < childItemsLength; ++i) {
                childContext = childItems[i];
                if (childContext.percentageParallel) {
                    childWidth = Math.ceil(percentageSpace * childContext.percentageParallel);
                    childWidth = childContext.setWidth(childWidth);
                    nonFlexWidth += childWidth;
                }
            }
        }

        

        if (ownerContext.parallelSizeModel.shrinkWrap) {
            plan.availableSpace = 0;
            plan.tooNarrow = false;
        } else {
            plan.availableSpace = containerWidth - nonFlexWidth;

            
            plan.tooNarrow = plan.availableSpace < ownerContext.flexedMinSize;
            if (plan.tooNarrow && Ext.getScrollbarSize()[names.height] && me.scrollParallel && ownerContext.state.perpendicularDone) {
                ownerContext.state.perpendicularDone = false;
                for (i = 0; i < childItemsLength; ++i) {
                    childItems[i].invalidate();
                }
            }
        }

        contentWidth = nonFlexWidth;
        remainingWidth = plan.availableSpace;
        remainingFlex = ownerContext.totalFlex;

        
        for (i = 0; i < flexedItemsLength; i++) {
            childContext = flexedItems[i];
            flex         = childContext.flex;
            flexedWidth  = me.roundFlex((flex / remainingFlex) * remainingWidth);
            flexedWidth  = childContext[setWidthName](flexedWidth); 

            

            contentWidth   += flexedWidth;
            
            remainingWidth  = Math.max(0, remainingWidth - flexedWidth); 
            remainingFlex  -= flex;
        }

        if (pack.center) {
            left += remainingWidth / 2;

            
            if (left < 0) {
                left = 0;
            }
        } else if (pack.end) {
            left += remainingWidth;
        }

        
        for (i = 0; i < childItemsLength; ++i) {
            childContext = childItems[i];
            childMargins = childContext.marginInfo; 

            left += childMargins[leftName];

            childContext.setProp(names.x, left);

            
            
            
            
            left += childMargins[rightName] + childContext.props[widthName];
        }

        contentWidth += ownerContext.targetContext.getPaddingInfo()[widthName];

        
        ownerContext.state.contentWidth = contentWidth; 

        
        
        if (mayNeedScrollbarAdjust &&
            (ownerContext.peek(names.contentHeight) > plan.targetSize[names.height])) {
            contentWidth += scrollbarWidth;
            ownerContext[names.hasOverflowY] = true;

            
            ownerContext.target.componentLayout[names.setWidthInDom] = true;

            
            
            
            
            ownerContext[names.invalidateScrollY] = (Ext.isStrict && Ext.isIE8);
        }
        ownerContext[names.setContentWidth](contentWidth);

        return true;
    },

    calculatePerpendicular: function(ownerContext, names, plan) {
        var me = this,
            heightShrinkWrap = ownerContext.perpendicularSizeModel.shrinkWrap,
            targetSize = plan.targetSize,
            childItems = ownerContext.childItems,
            childItemsLength = childItems.length,
            mmax = Math.max,
            heightName = names.height,
            setHeightName = names.setHeight,
            topName = names.top,
            topPositionName = names.y,
            padding = me.padding,
            top = padding[topName],
            availHeight = targetSize[heightName] - top - padding[names.bottom],
            align = ownerContext.boxOptions.align,
            isStretch    = align.stretch, 
            isStretchMax = align.stretchmax,
            isCenter     = align.center,
            maxHeight = 0,
            hasPercentageSizes = 0,
            scrollbarHeight = Ext.getScrollbarSize().height,
            childTop, i, childHeight, childMargins, diff, height, childContext,
            stretchMaxPartner, stretchMaxChildren, shrinkWrapParallelOverflow, 
            percentagePerpendicular;

        if (isStretch || (isCenter && !heightShrinkWrap)) {
            if (isNaN(availHeight)) {
                return false;
            }
        }

        
        
        
        
        
        
        if (me.scrollParallel && plan.tooNarrow) {
            if (heightShrinkWrap) {
                shrinkWrapParallelOverflow = true;
            } else {
                availHeight -= scrollbarHeight;
                plan.targetSize[heightName] -= scrollbarHeight;
            }
        }

        if (isStretch) {
            height = availHeight; 
        } else {
            for (i = 0; i < childItemsLength; i++) {
                childContext = childItems[i];
                childMargins = (childContext.marginInfo || childContext.getMarginInfo())[heightName];

                if (!(percentagePerpendicular = childContext.percentagePerpendicular)) {
                    childHeight = childContext.getProp(heightName);
                } else {
                    ++hasPercentageSizes;
                    if (heightShrinkWrap) {
                        
                        
                        continue;
                    } else {
                        childHeight = percentagePerpendicular * availHeight - childMargins;
                        childHeight = childContext[names.setHeight](childHeight);
                    }
                }

                
                if (isNaN(maxHeight = mmax(maxHeight, childHeight + childMargins,
                                           childContext.target[names.minHeight] || 0))) {
                    return false; 
                }
            }

            
            
            if (shrinkWrapParallelOverflow) {
                maxHeight += scrollbarHeight;
                ownerContext[names.hasOverflowX] = true;

                
                ownerContext.target.componentLayout[names.setHeightInDom] = true;

                
                
                
                
                ownerContext[names.invalidateScrollX] = (Ext.isStrict && Ext.isIE8);
            }

            
            
            stretchMaxPartner = ownerContext.stretchMaxPartner;
            if (stretchMaxPartner) {
                
                ownerContext.setProp('maxChildHeight', maxHeight);
                stretchMaxChildren = stretchMaxPartner.childItems;
                
                if (stretchMaxChildren && stretchMaxChildren.length) {
                    maxHeight = mmax(maxHeight, stretchMaxPartner.getProp('maxChildHeight'));
                    if (isNaN(maxHeight)) {
                        return false;
                    }
                }
            }

            ownerContext[names.setContentHeight](maxHeight + me.padding[heightName] +
                    ownerContext.targetContext.getPaddingInfo()[heightName]);

            
            
            
            if (shrinkWrapParallelOverflow) {
                maxHeight -= scrollbarHeight;
            }
            plan.maxSize = maxHeight;

            if (isStretchMax) {
                height = maxHeight;
            } else if (isCenter || hasPercentageSizes) {
                height = heightShrinkWrap ? maxHeight : mmax(availHeight, maxHeight);

                
                
                
                
                height -= ownerContext.innerCtContext.getBorderInfo()[heightName];
            }
        }

        for (i = 0; i < childItemsLength; i++) {
            childContext = childItems[i];
            childMargins = childContext.marginInfo || childContext.getMarginInfo();

            childTop = top + childMargins[topName];

            if (isStretch) {
                childContext[setHeightName](height - childMargins[heightName]);
            } else {
                percentagePerpendicular = childContext.percentagePerpendicular;
                if (heightShrinkWrap && percentagePerpendicular) {
                    childMargins = childContext.marginInfo || childContext.getMarginInfo();
                    childHeight = percentagePerpendicular * height - childMargins[heightName];
                    childHeight = childContext.setHeight(childHeight);
                }

                if (isCenter) {
                    diff = height - childContext.props[heightName];
                    if (diff > 0) {
                        childTop = top + Math.round(diff / 2);
                    }
                }
            }

            childContext.setProp(topPositionName, childTop);
        }

        return true;
    },

    calculateStretchMax: function (ownerContext, names, plan) {
        var me = this,
            heightName = names.height,
            widthName = names.width,
            childItems = ownerContext.childItems,
            length = childItems.length,
            height = plan.maxSize,
            onBeforeInvalidateChild = me.onBeforeInvalidateChild,
            onAfterInvalidateChild = me.onAfterInvalidateChild,
            childContext, props, i, childHeight;

        for (i = 0; i < length; ++i) {
            childContext = childItems[i];

            props = childContext.props;
            childHeight = height - childContext.getMarginInfo()[heightName];

            if (childHeight != props[heightName] ||   
                childContext[names.heightModel].constrained) { 
                
                
                
                
                
                
                
                childContext.invalidate({
                    before: onBeforeInvalidateChild,
                    after: onAfterInvalidateChild,
                    layout: me,
                    
                    childWidth: props[widthName],
                    
                    childHeight: childHeight,
                    childX: props.x,
                    childY: props.y,
                    names: names
                });
            }
        }
    },

    completeLayout: function(ownerContext) {
        var me = this,
            names = ownerContext.boxNames,
            invalidateScrollX = ownerContext.invalidateScrollX,
            invalidateScrollY = ownerContext.invalidateScrollY,
            dom, el, overflowX, overflowY, styles;

        me.overflowHandler.completeLayout(ownerContext);

        if (invalidateScrollX || invalidateScrollY) {
            el = me.getTarget();
            dom = el.dom;
            styles = dom.style;

            if (invalidateScrollX) {
                
                overflowX = el.getStyle('overflowX');
                if (overflowX == 'auto') {
                    
                    overflowX = styles.overflowX;
                    styles.overflowX = 'scroll'; 
                } else {
                    invalidateScrollX = false; 
                }
            }

            if (invalidateScrollY) {
                
                overflowY = el.getStyle('overflowY');
                if (overflowY == 'auto') {
                    
                    overflowY = styles.overflowY;
                    styles.overflowY = 'scroll'; 
                } else {
                    invalidateScrollY = false; 
                }
            }

            if (invalidateScrollX || invalidateScrollY) { 
                
                dom.scrollWidth;

                if (invalidateScrollX) {
                    styles.overflowX = overflowX; 
                }
                if (invalidateScrollY) {
                    styles.overflowY = overflowY; 
                }
            }
        }

        
        if (me.scrollParallel) {
            me.owner.getTargetEl().dom[names.scrollLeft] = me.scrollPos;
        }
    },

    finishedLayout: function(ownerContext) {
        this.overflowHandler.finishedLayout(ownerContext);
        this.callParent(arguments);

        
        
        
        
        
        
        if (Ext.isWebKit) {
            this.targetEl.setWidth(ownerContext.innerCtContext.props.width);
        }
    },

    onBeforeInvalidateChild: function (childContext, options) {
        
        var heightModelName = options.names.heightModel;

        
        
        
        
        if (!childContext[heightModelName].constrainedMax) {
            
            
            childContext[heightModelName] = Ext.layout.SizeModel.calculated;
        }
    },

    onAfterInvalidateChild: function (childContext, options) {
        
        var names = options.names,
            scrollbarSize = Ext.getScrollbarSize(),
            childHeight = options.childHeight,
            childWidth = options.childWidth;

        childContext.setProp('x', options.childX);
        childContext.setProp('y', options.childY);

        if (childContext[names.heightModel].calculated) {
            
            
            childContext[names.setHeight](childHeight);
        }

        if (childContext[names.widthModel].calculated) {
            childContext[names.setWidth](childWidth);
        }
    },

    publishInnerCtSize: function(ownerContext, reservedSpace) {
        var me = this,
            names = ownerContext.boxNames,
            heightName = names.height,
            widthName = names.width,
            align = ownerContext.boxOptions.align,
            dock = me.owner.dock,
            padding = me.padding,
            plan = ownerContext.state.boxPlan,
            targetSize = plan.targetSize,
            height = targetSize[heightName],
            innerCtContext = ownerContext.innerCtContext,
            innerCtWidth = (ownerContext.parallelSizeModel.shrinkWrap || (plan.tooNarrow && me.scrollParallel)
                    ? ownerContext.state.contentWidth
                    : targetSize[widthName]) - (reservedSpace || 0),
            innerCtHeight;

        if (align.stretch) {
            innerCtHeight = height;
        } else {
            innerCtHeight = plan.maxSize + padding[names.top] + padding[names.bottom] + innerCtContext.getBorderInfo()[heightName];

            if (!ownerContext.perpendicularSizeModel.shrinkWrap && align.center) {
                innerCtHeight = Math.max(height, innerCtHeight);
            }
        }

        innerCtContext[names.setWidth](innerCtWidth);
        innerCtContext[names.setHeight](innerCtHeight);

        
        if (isNaN(innerCtWidth + innerCtHeight)) {
            me.done = false;
        }

        
        
        
        
        
        
        if (plan.calculatedWidth && (dock == 'left' || dock == 'right')) {
            
            ownerContext.setWidth(plan.calculatedWidth, true, true);
        }
    },

    onRemove: function(comp){
        var me = this;
        me.callParent(arguments);
        if (me.overflowHandler) {
            me.overflowHandler.onRemove(comp);
        }
        if (comp.layoutMarginCap == me.id) {
            delete comp.layoutMarginCap;
        }
    },

    
    initOverflowHandler: function() {
        var me = this,
            handler = me.overflowHandler,
            handlerType,
            constructor;

        if (typeof handler == 'string') {
            handler = {
                type: handler
            };
        }

        handlerType = 'None';
        if (handler && handler.type !== undefined) {
            handlerType = handler.type;
        }

        constructor = Ext.layout.container.boxOverflow[handlerType];
        if (constructor[me.type]) {
            constructor = constructor[me.type];
        }

        me.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.' + handlerType, me, handler);
    },

    
    
    getRenderTarget: function() {
        return this.targetEl;
    },

    
    
    getElementTarget: function() {
        return this.innerCt;
    },


    
    destroy: function() {
        Ext.destroy(this.innerCt, this.overflowHandler);
        this.callParent(arguments);
    }
});


Ext.define('Ext.layout.container.HBox', {

    

    alias: ['layout.hbox'],
    extend: 'Ext.layout.container.Box',
    alternateClassName: 'Ext.layout.HBoxLayout',

    

    
    align: 'top', 

    type : 'hbox',

    direction: 'horizontal',

    horizontal: true,

    names: {
        
        lr: 'lr',
        left: 'left',
        leftCap: 'Left',
        right: 'right',
        position: 'left',
        width: 'width',
        contentWidth: 'contentWidth',
        minWidth: 'minWidth',
        maxWidth: 'maxWidth',
        widthCap: 'Width',
        widthModel: 'widthModel',
        widthIndex: 0,
        x: 'x',
        scrollLeft: 'scrollLeft',
        overflowX: 'overflowX',
        hasOverflowX: 'hasOverflowX',
        invalidateScrollX: 'invalidateScrollX',

        
        center: 'middle',
        top: 'top',
        topPosition: 'top',
        bottom: 'bottom',
        height: 'height',
        contentHeight: 'contentHeight',
        minHeight: 'minHeight',
        maxHeight: 'maxHeight',
        heightCap: 'Height',
        heightModel: 'heightModel',
        heightIndex: 1,
        y: 'y',
        scrollTop: 'scrollTop',
        overflowY: 'overflowY',
        hasOverflowY: 'hasOverflowY',
        invalidateScrollY: 'invalidateScrollY',

        
        getWidth: 'getWidth',
        getHeight: 'getHeight',
        setWidth: 'setWidth',
        setHeight: 'setHeight',
        gotWidth: 'gotWidth',
        gotHeight: 'gotHeight',
        setContentWidth: 'setContentWidth',
        setContentHeight: 'setContentHeight',
        setWidthInDom: 'setWidthInDom',
        setHeightInDom: 'setHeightInDom'
    },

    sizePolicy: {
        flex: {
            '': {
                setsWidth: 1,
                setsHeight: 0
            },
            stretch: {
                setsWidth: 1,
                setsHeight: 1
            },
            stretchmax: {
                readsHeight: 1,
                setsWidth: 1,
                setsHeight: 1
            }
        },
        '': {
            setsWidth: 0,
            setsHeight: 0
        },
        stretch: {
            setsWidth: 0,
            setsHeight: 1
        },
        stretchmax: {
            readsHeight: 1,
            setsWidth: 0,
            setsHeight: 1
        }
    }            
});


Ext.define('Ext.grid.ColumnLayout', {
    extend: 'Ext.layout.container.HBox',
    alias: 'layout.gridcolumn',
    type : 'gridcolumn',

    reserveOffset: false,

    firstHeaderCls: Ext.baseCSSPrefix + 'column-header-first',
    lastHeaderCls: Ext.baseCSSPrefix + 'column-header-last',

    initLayout: function() {
        this.grid = this.owner.up('[scrollerOwner]');
        this.callParent();
    },

    
    beginLayout: function (ownerContext) {
        var me = this,
            grid = me.grid,
            view = grid.view,
            i = 0,
            items = me.getVisibleItems(),
            len = items.length,
            item;

        ownerContext.gridContext = ownerContext.context.getCmp(me.grid);

        
        
        
        if (grid.lockable) {
            if (me.owner.up('tablepanel') === view.normalGrid) {
                view = view.normalGrid.getView();
            } else {
                view = null;
            }
        }

        me.callParent(arguments);

        
        for (; i < len; i++) {
            item = items[i];
            item.removeCls([me.firstHeaderCls, me.lastHeaderCls]);
            item.el.setStyle({
                height: 'auto'
            });
            item.titleEl.setStyle({
                height: 'auto',
                paddingTop: ''  
            });
        }

        
        if (len > 0) {
            items[0].addCls(me.firstHeaderCls);
            items[len - 1].addCls(me.lastHeaderCls);
        }

        
        
        
        if (!me.owner.isHeader && Ext.getScrollbarSize().width && !grid.collapsed && view &&
                view.table.dom && (view.autoScroll || view.overflowY)) {
            ownerContext.viewContext = ownerContext.context.getCmp(view);
        }
    },

    roundFlex: function(width) {
        return Math.floor(width);
    },

    calculate: function(ownerContext) {
        var me = this,
            viewContext = ownerContext.viewContext,
            tableHeight,
            viewHeight;

        me.callParent(arguments);

        if (ownerContext.state.parallelDone) {
            ownerContext.setProp('columnWidthsDone', true);
        }

        
        
        
        
        if (viewContext && !ownerContext.state.overflowAdjust.width && !ownerContext.gridContext.heightModel.shrinkWrap) {
            tableHeight = viewContext.tableContext.getProp('height');
            viewHeight = viewContext.getProp('height');

            
            if (isNaN(tableHeight + viewHeight)) {
                me.done = false;
            }

            
            else if (tableHeight >= viewHeight) {
                ownerContext.gridContext.invalidate({
                    after: function() {
                        ownerContext.state.overflowAdjust = {
                            width: Ext.getScrollbarSize().width,
                            height: 0
                        };
                    }
                });
            }
        }
    },
 
    completeLayout: function(ownerContext) {
        var me = this,
            owner = me.owner,
            state = ownerContext.state,
            needsInvalidate = false,
            calculated = me.sizeModels.calculated,
            childItems, len, i, childContext, item;

        me.callParent(arguments);

        
        
        
        if (!state.flexesCalculated && owner.forceFit && !owner.isHeader) {
            childItems = ownerContext.childItems;
            len = childItems.length;

            for (i = 0; i < len; i++) {
                childContext = childItems[i];
                item = childContext.target;

                
                
                if (item.width) {
                    item.flex = ownerContext.childItems[i].flex = item.width;
                    delete item.width;
                    childContext.widthModel = calculated;
                    needsInvalidate = true;
                }
            }

            
            
            if (needsInvalidate) {
                me.cacheFlexes(ownerContext);
                ownerContext.invalidate({
                    state: {
                        flexesCalculated: true
                    }
                });
            }
        }
    },

    finalizeLayout: function() {
        var me = this,
            i = 0,
            items,
            len,
            itemsHeight,
            owner = me.owner,
            titleEl = owner.titleEl;

        
        items = me.getVisibleItems();
        len = items.length;
        
        itemsHeight = owner.el.getViewSize().height;
        if (titleEl) {
        
        
            itemsHeight -= titleEl.getHeight();
        }
        for (; i < len; i++) {
            items[i].setPadding(itemsHeight);
        }
    },

    
    
    publishInnerCtSize: function(ownerContext) {
        var me = this,
            size = ownerContext.state.boxPlan.targetSize,
            cw = ownerContext.peek('contentWidth'),
            view;

        
        if ((cw != null) && !me.owner.isHeader) {
            size.width = cw;

            
            view = me.owner.ownerCt.view;
            if (view.autoScroll || view.overflowY) {
                size.width += Ext.getScrollbarSize().width;
            }
        }

        return me.callParent(arguments);
    }
});


Ext.define('Ext.grid.header.Container', {
    extend: 'Ext.container.Container',
    requires: [
        'Ext.grid.ColumnLayout',
        'Ext.grid.plugin.HeaderResizer',
        'Ext.grid.plugin.HeaderReorderer'
    ],
    uses: [
        'Ext.grid.column.Column',
        'Ext.menu.Menu',
        'Ext.menu.CheckItem',
        'Ext.menu.Separator'
    ],
    border: true,

    alias: 'widget.headercontainer',

    baseCls: Ext.baseCSSPrefix + 'grid-header-ct',
    dock: 'top',

    
    weight: 100,

    defaultType: 'gridcolumn',
    
    detachOnRemove: false,

    
    defaultWidth: 100,
    
    

    
    sortAscText: 'Sort Ascending',
    
    
    sortDescText: 'Sort Descending',
    
    
    sortClearText: 'Clear Sort',
    
    
    columnsText: 'Columns',
    

    headerOpenCls: Ext.baseCSSPrefix + 'column-header-open',

    
    triStateSort: false,

    ddLock: false,

    dragging: false,

    

    
    sortable: true,

    initComponent: function() {
        var me = this;

        me.headerCounter = 0;
        me.plugins = me.plugins || [];

        
        

        
        
        if (!me.isHeader) {
            if (me.enableColumnResize) {
                me.resizer = new Ext.grid.plugin.HeaderResizer();
                me.plugins.push(me.resizer);
            }
            if (me.enableColumnMove) {
                me.reorderer = new Ext.grid.plugin.HeaderReorderer();
                me.plugins.push(me.reorderer);
            }
        }

        
        if (me.isHeader && !me.items) {
            me.layout = me.layout || 'auto';
        }
        
        else {
            me.layout = Ext.apply({
                type: 'gridcolumn',
                align: 'stretchmax'
            }, me.initialConfig.layout);
        }
        me.defaults = me.defaults || {};
        Ext.applyIf(me.defaults, {
            triStateSort: me.triStateSort,
            sortable: me.sortable
        });
        
        me.menuTask = new Ext.util.DelayedTask(me.updateMenuDisabledState, me);
        me.callParent();
        me.addEvents(
            
            'columnresize',

            
            'headerclick',

            
            'headertriggerclick',

            
            'columnmove',
            
            'columnhide',
            
            'columnshow',
            
            'sortchange',
            
            'menucreate'
        );
    },

    onDestroy: function() {
        var me = this;
        
        me.menuTask.cancel();
        Ext.destroy(me.resizer, me.reorderer);
        me.callParent();
    },

    applyColumnsState: function(columns) {
        if (!columns || !columns.length) {
            return;
        }

        var me     = this,
            items  = me.items.items,
            count  = items.length,
            i      = 0,
            length = columns.length,
            c, col, columnState, index;

        for (c = 0; c < length; c++) {
            columnState = columns[c];

            for (index = count; index--; ) {
                col = items[index];
                if (col.getStateId && col.getStateId() == columnState.id) {
                    
                    
                    
                    
                    if (i !== index) {
                        me.moveHeader(index, i);
                    }

                    if (col.applyColumnState) {
                        col.applyColumnState(columnState);
                    }
                    ++i;
                    break;
                }
            }
        }
    },

    getColumnsState: function () {
        var me = this,
            columns = [],
            state;

        me.items.each(function (col) {
            state = col.getColumnState && col.getColumnState();
            if (state) {
                columns.push(state);
            }
        });

        return columns;
    },

    
    
    
    onAdd: function(c) {
        var me = this,
            headerCt = me.isHeader ? me.getOwnerHeaderCt() : me;

        if (!c.headerId) {
            c.headerId = c.initialConfig.id || Ext.id(null, 'header-');
        }

        if (!c.stateId) {
            
            
            
            
            c.stateId = c.initialConfig.id || ('h' + (++me.headerCounter));
        }

        me.callParent(arguments);

        
        if (headerCt) {
            headerCt.purgeCache();
        }
    },

    
    
    
    onRemove: function(c) {
        var me = this,
            headerCt = me.isHeader ? me.getOwnerHeaderCt() : me;

        me.callParent(arguments);
        

        
        if (headerCt) {
            me.purgeCache();
        }
    },

    
    applyDefaults: function(config) {
        var ret; 
        
        if (config && !config.isComponent && config.xtype == 'rownumberer') {
            ret = config;
        } else {
            ret = this.callParent(arguments);
            
            
            if (!config.isGroupHeader && !('width' in ret) && !ret.flex) {
                ret.width = this.defaultWidth;
            }
        }
        return ret;
    },

    afterRender: function() {
        this.callParent();
        this.setSortState();
        
    },
    
    setSortState: function(){
        var store   = this.up('[store]').store,
            
            
            first = store.getFirstSorter(),
            hd;

        if (first) {
            hd = this.down('gridcolumn[dataIndex=' + first.property  +']');
            if (hd) {
                hd.setSortState(first.direction, false, true);
            }
        } else {
            this.clearOtherSortStates(null);
        }
    },
    
    getHeaderMenu: function(){
        var menu = this.getMenu(),
            item;
            
        if (menu) {
            item = menu.child('#columnItem');
            if (item) {
                return item.menu;
            }
        }   
        return null; 
    },
    
    onHeaderVisibilityChange: function(header, visible){
        var me = this,
            menu = me.getHeaderMenu(),
            item;
        
        if (menu) {
            
            item = me.getMenuItemForHeader(menu, header);
            if (item) {
                item.setChecked(visible, true);
            }
            
            me.menuTask.delay(50);
        }
    },
    
    
    getLeafMenuItems: function() {
        var me = this,
            columns = me.getGridColumns(),
            items = [],
            i = 0,
            count = 0,
            len = columns.length,
            menu = me.getMenu(),
            item;

        for (; i < len; ++i) {
            item = columns[i];
            if (item.hideable) {
                item = me.getMenuItemForHeader(menu, item);
                if (item) {
                    items.push(item);
                    if (item.checked) {
                        ++count;
                    }
                }
            } else if (!item.hidden && !item.menuDisabled) {
                ++count;
            }
        }

        return {
            items: items,
            checkedCount: count    
        };
    },
    
    updateMenuDisabledState: function(){
        var me = this,
            result = me.getLeafMenuItems(),
            total = result.checkedCount,
            items = result.items,
            len = items.length,
            i = 0,
            rootItem = me.getMenu().child('#columnItem');
            
        if (total <= 1) {
            
            me.disableMenuItems(rootItem, Ext.ComponentQuery.query('[checked=true]', items)[0]);
        } else {
            
            for (; i < len; ++i) {
                me.setMenuItemState(total, rootItem, items[i]);
            }
        }
    },
    
    disableMenuItems: function(rootItem, item){
        while (item && item != rootItem) {
            item.disableCheckChange();
            item = item.parentMenu.ownerItem;
        }
    },
    
    setMenuItemState: function(total, rootItem, item){
        var parentMenu,
            checkedChildren;
            
        while (item && item != rootItem) {
            parentMenu = item.parentMenu;
            checkedChildren = item.parentMenu.query('[checked=true]:not([menu])').length;
            item.enableCheckChange();
            item = parentMenu.ownerItem;
            if (checkedChildren === total) {
                
                break;
            }
        }
        
        
        this.disableMenuItems(rootItem, item);
    },
    
    getMenuItemForHeader: function(menu, header){
        return header ? menu.down('menucheckitem[headerId=' + header.id + ']') : null;
    },

    onHeaderShow: function(header) {
        
        var me = this,
            gridSection = me.ownerCt;

        me.onHeaderVisibilityChange(header, true);

        
        
        if (!header.isGroupHeader) {
            if (gridSection) {
                gridSection.onHeaderShow(me, header);
            }
        }
        me.fireEvent('columnshow', me, header);
    },

    onHeaderHide: function(header) {
        
        var me = this,
            gridSection = me.ownerCt;

        me.onHeaderVisibilityChange(header, false);

        
        if (!header.isGroupHeader) {
            if (gridSection) {
                gridSection.onHeaderHide(me, header);
            }
        }
        me.fireEvent('columnhide', me, header);
    },

    
    tempLock: function() {
        this.ddLock = true;
        Ext.Function.defer(function() {
            this.ddLock = false;
        }, 200, this);
    },

    onHeaderResize: function(header, w, suppressFocus) {
        var me = this,
            view = me.view,
            gridSection = me.ownerCt;

        
        if (view && view.table.dom) {
            me.tempLock();
            if (gridSection) {
                gridSection.onHeaderResize(me, header, w);
            }
        }
        me.fireEvent('columnresize', this, header, w);
    },

    onHeaderClick: function(header, e, t) {
        header.fireEvent('headerclick', this, header, e, t);
        this.fireEvent("headerclick", this, header, e, t);
    },

    onHeaderTriggerClick: function(header, e, t) {
        
        var me = this;
        if (header.fireEvent('headertriggerclick', me, header, e, t) !== false && me.fireEvent("headertriggerclick", me, header, e, t) !== false) {
            me.showMenuBy(t, header);
        }
    },

    showMenuBy: function(t, header) {
        var menu = this.getMenu(),
            ascItem  = menu.down('#ascItem'),
            descItem = menu.down('#descItem'),
            sortableMth;

        menu.activeHeader = menu.ownerCt = header;
        menu.setFloatParent(header);
        
        header.titleEl.addCls(this.headerOpenCls);

        
        sortableMth = header.sortable ? 'enable' : 'disable';
        if (ascItem) {
            ascItem[sortableMth]();
        }
        if (descItem) {
            descItem[sortableMth]();
        }
        menu.showBy(t);
    },

    
    onMenuDeactivate: function() {
        var menu = this.getMenu();
        
        menu.activeHeader.titleEl.removeCls(this.headerOpenCls);
    },

    moveHeader: function(fromIdx, toIdx) {

        
        this.tempLock();
        this.onHeaderMoved(this.move(fromIdx, toIdx), 1, fromIdx, toIdx);
    },

    purgeCache: function() {
        var me = this;
        
        delete me.gridDataColumns;
        delete me.hideableColumns;

        
        if (me.menu) {
            
            me.menu.hide();
            me.menu.destroy();
            delete me.menu;
        }
    },

    onHeaderMoved: function(header, colsToMove, fromIdx, toIdx) {
        var me = this,
            gridSection = me.ownerCt;

        if (gridSection && gridSection.onHeaderMove) {
            gridSection.onHeaderMove(me, header, colsToMove, fromIdx, toIdx);
        }
        me.fireEvent("columnmove", me, header, fromIdx, toIdx);
    },

    
    getMenu: function() {
        var me = this;

        if (!me.menu) {
            me.menu = new Ext.menu.Menu({
                hideOnParentHide: false,  
                items: me.getMenuItems(),
                listeners: {
                    deactivate: me.onMenuDeactivate,
                    scope: me
                }
            });
            me.updateMenuDisabledState();
            me.fireEvent('menucreate', me, me.menu);
        }
        return me.menu;
    },

    
    getMenuItems: function() {
        var me = this,
            menuItems = [],
            hideableColumns = me.enableColumnHide ? me.getColumnMenu(me) : null;

        if (me.sortable) {
            menuItems = [{
                itemId: 'ascItem',
                text: me.sortAscText,
                cls: Ext.baseCSSPrefix + 'hmenu-sort-asc',
                handler: me.onSortAscClick,
                scope: me
            },{
                itemId: 'descItem',
                text: me.sortDescText,
                cls: Ext.baseCSSPrefix + 'hmenu-sort-desc',
                handler: me.onSortDescClick,
                scope: me
            }];
        }
        if (hideableColumns && hideableColumns.length) {
            menuItems.push('-', {
                itemId: 'columnItem',
                text: me.columnsText,
                cls: Ext.baseCSSPrefix + 'cols-icon',
                menu: hideableColumns
            });
        }
        return menuItems;
    },

    
    onSortAscClick: function() {
        var menu = this.getMenu(),
            activeHeader = menu.activeHeader;

        activeHeader.setSortState('ASC');
    },

    
    onSortDescClick: function() {
        var menu = this.getMenu(),
            activeHeader = menu.activeHeader;

        activeHeader.setSortState('DESC');
    },

    
    getColumnMenu: function(headerContainer) {
        var menuItems = [],
            i = 0,
            item,
            items = headerContainer.query('>gridcolumn[hideable]'),
            itemsLn = items.length,
            menuItem;

        for (; i < itemsLn; i++) {
            item = items[i];
            menuItem = new Ext.menu.CheckItem({
                text: item.menuText || item.text,
                checked: !item.hidden,
                hideOnClick: false,
                headerId: item.id,
                menu: item.isGroupHeader ? this.getColumnMenu(item) : undefined,
                checkHandler: this.onColumnCheckChange,
                scope: this
            });
            menuItems.push(menuItem);

            
            
            item.on({
                destroy: Ext.Function.bind(menuItem.destroy, menuItem)
            });
        }
        return menuItems;
    },

    onColumnCheckChange: function(checkItem, checked) {
        var header = Ext.getCmp(checkItem.headerId);
        header[checked ? 'show' : 'hide']();
    },

    
    getColumnsForTpl: function(flushCache) {
        var cols    = [],
            headers   = this.getGridColumns(flushCache),
            headersLn = headers.length,
            i = 0,
            header,
            width;

        for (; i < headersLn; i++) {
            header = headers[i];

            if (header.hidden || header.up('headercontainer[hidden=true]')) {
                width = 0;
            } else {
                width = header.getDesiredWidth();
            }
            cols.push({
                dataIndex: header.dataIndex,
                align: header.align,
                width: width,
                id: header.id,
                cls: header.tdCls,
                columnId: header.getItemId()
            });
        }
        return cols;
    },

    
    getColumnCount: function() {
        return this.getGridColumns().length;
    },

    
    getFullWidth: function(flushCache) {
        var fullWidth = 0,
            headers = this.getVisibleGridColumns(flushCache),
            headersLn = headers.length,
            i = 0,
            header;
           

        for (; i < headersLn; i++) {
            header = headers[i];
            
            if (header.getDesiredWidth) {
                fullWidth += header.getDesiredWidth() || 0;
            
            } else {
                fullWidth += header.getWidth();
            }
        }
        return fullWidth;
    },

    
    clearOtherSortStates: function(activeHeader) {
        var headers   = this.getGridColumns(),
            headersLn = headers.length,
            i         = 0;

        for (; i < headersLn; i++) {
            if (headers[i] !== activeHeader) {
                
                headers[i].setSortState(null, true);
            }
        }
    },

    
    getVisibleGridColumns: function(refreshCache) {
        return Ext.ComponentQuery.query(':not([hidden])', this.getGridColumns(refreshCache));
    }, 

    
    getGridColumns: function(refreshCache) {
        var me = this,
            result = refreshCache ? null : me.gridDataColumns;

        
        if (!result) {
            me.gridDataColumns = result = [];
            me.cascade(function(c) {
                if ((c !== me) && !c.isGroupHeader) {
                    result.push(c);
                }
            });
        }

        return result;
    },

    
    getHideableColumns: function(refreshCache) {
        var me = this,
            result = refreshCache ? null : me.hideableColumns;

        if (!result) {
            result = me.hideableColumns = me.query('[hideable]');
        }
        return result;
    },

    
    getHeaderIndex: function(header) {
        
        if (header.isGroupHeader) {
            header = header.down(':not([isgroupHeader])');
        }
        return Ext.Array.indexOf(this.getGridColumns(), header);
    },

    
    getHeaderAtIndex: function(index) {
        var columns = this.getGridColumns();
        return columns.length ? columns[index] : null;
    },

    
    getVisibleHeaderClosestToIndex: function(index) {
        var result = this.getHeaderAtIndex(index);
        if (result && result.hidden) {
            result = result.next(':not([hidden])') || result.prev(':not([hidden])');
        }
        return result;
    },

    
    prepareData: function(data, rowIdx, record, view, panel) {
        var me        = this,
            obj       = {},
            headers   = me.gridDataColumns || me.getGridColumns(),
            headersLn = headers.length,
            colIdx    = 0,
            header,
            headerId,
            renderer,
            value,
            metaData,
            store = panel.store;

        for (; colIdx < headersLn; colIdx++) {
            metaData = {
                tdCls: '',
                style: ''
            };
            header = headers[colIdx];
            headerId = header.id;
            renderer = header.renderer;
            value = data[header.dataIndex];

            if (typeof renderer == "function") {
                value = renderer.call(
                    header.scope || me.ownerCt,
                    value,
                    
                    
                    metaData,
                    record,
                    rowIdx,
                    colIdx,
                    store,
                    view
                );
            }

            if (me.markDirty) {
                obj[headerId + '-modified'] = record.isModified(header.dataIndex) ? Ext.baseCSSPrefix + 'grid-dirty-cell' : '';
            }
            obj[headerId+'-tdCls'] = metaData.tdCls;
            obj[headerId+'-tdAttr'] = metaData.tdAttr;
            obj[headerId+'-style'] = metaData.style;
            if (typeof value === 'undefined' || value === null || value === '') {
                value = header.emptyCellText;
            }
            obj[headerId] = value;
        }
        return obj;
    },

    expandToFit: function(header) {
        var view = this.view;
        if (view) {
            view.expandToFit(header);
        }
    }
});


Ext.define('Ext.grid.column.Column', {
    extend: 'Ext.grid.header.Container',
    alias: 'widget.gridcolumn',
    requires: ['Ext.util.KeyNav', 'Ext.grid.ColumnComponentLayout', 'Ext.grid.ColumnLayout'],
    alternateClassName: 'Ext.grid.Column',

    baseCls: Ext.baseCSSPrefix + 'column-header ' + Ext.baseCSSPrefix + 'unselectable',

    
    hoverCls: Ext.baseCSSPrefix + 'column-header-over',

    handleWidth: 5,

    sortState: null,

    possibleSortStates: ['ASC', 'DESC'],

    childEls: [
        'titleEl', 'triggerEl', 'textEl'
    ],

    renderTpl:
        '<div id="{id}-titleEl" {tipMarkup}class="' + Ext.baseCSSPrefix + 'column-header-inner">' +
            '<span id="{id}-textEl" class="' + Ext.baseCSSPrefix + 'column-header-text">' +
                '{text}' +
            '</span>' +
            '<tpl if="!menuDisabled">'+
                '<div id="{id}-triggerEl" class="' + Ext.baseCSSPrefix + 'column-header-trigger"></div>'+
            '</tpl>' +
        '</div>' +
        '{%this.renderContainer(out,values)%}',

    

    

    
    dataIndex: null,

    
    text: '&#160;',

    

    
    menuText: null,

    
    emptyCellText: '&#160;',

    
    sortable: true,

    

    

    

    
    resizable: true,

    
    hideable: true,

    
    menuDisabled: false,

    
    renderer: false,

    
    
    

    
    editRenderer: false,

    
    align: 'left',

    
    draggable: true,
    
    
    
    
    tooltipType: 'qtip',

    
    
    initDraggable: Ext.emptyFn,

    

    

    

    

    

    
    isHeader: true,

    componentLayout: 'columncomponent',
    
    
    initResizable: Ext.emptyFn,

    initComponent: function() {
        var me = this,
            renderer;

        if (Ext.isDefined(me.header)) {
            me.text = me.header;
            delete me.header;
        }

        if (!me.triStateSort) {
            me.possibleSortStates.length = 2;
        }

        
        if (Ext.isDefined(me.columns)) {
            me.isGroupHeader = true;


            
            me.items = me.columns;
            delete me.columns;
            delete me.flex;
            delete me.width;
            me.cls = (me.cls||'') + ' ' + Ext.baseCSSPrefix + 'group-header';
            me.sortable = false;
            me.resizable = false;
            me.align = 'center';
        } else {
            
            
            me.isContainer = false;

            
            
            
            if (me.flex) {
                me.minWidth = me.minWidth || Ext.grid.plugin.HeaderResizer.prototype.minColWidth;
            }
        }
        me.addCls(Ext.baseCSSPrefix + 'column-header-align-' + me.align);
        
        renderer = me.renderer;
        if (renderer) {
            
            
            if (typeof renderer == 'string') {
                me.renderer = Ext.util.Format[renderer];
            }
            me.hasCustomRenderer = true;
        } else if (me.defaultRenderer) {
            me.scope = me;
            me.renderer = me.defaultRenderer;
        }

        
        me.callParent(arguments);

        me.on({
            element:  'el',
            click:    me.onElClick,
            dblclick: me.onElDblClick,
            scope:    me
        });
        me.on({
            element:    'titleEl',
            mouseenter: me.onTitleMouseOver,
            mouseleave: me.onTitleMouseOut,
            scope:      me
        });
    },

    onAdd: function(childHeader) {
        childHeader.isSubHeader = true;
        childHeader.addCls(Ext.baseCSSPrefix + 'group-sub-header');
        this.callParent(arguments);
    },

    onRemove: function(childHeader) {
        childHeader.isSubHeader = false;
        childHeader.removeCls(Ext.baseCSSPrefix + 'group-sub-header');
        this.callParent(arguments);
    },

    initRenderData: function() {
        var me = this,
            tipMarkup = '',
            tip = me.tooltip,
            attr = me.tooltipType == 'qtip' ? 'data-qtip' : 'title';
            
        if (!Ext.isEmpty(tip)) {
            tipMarkup = attr + '="' + tip + '" ';
        }
            
        return Ext.applyIf(me.callParent(arguments), {
            text: me.text,
            menuDisabled: me.menuDisabled,
            tipMarkup: tipMarkup
        });
    },

    applyColumnState: function (state) {
        var me = this,
            defined = Ext.isDefined;
            
        
        me.applyColumnsState(state.columns);

        
        
        if (defined(state.hidden)) {
            me.hidden = state.hidden;
        }
        if (defined(state.locked)) {
            me.locked = state.locked;
        }
        if (defined(state.sortable)) {
            me.sortable = state.sortable;
        }
        if (defined(state.width)) {
            delete me.flex;
            me.width = state.width;
        } else if (defined(state.flex)) {
            delete me.width;
            me.flex = state.flex;
        }
    },

    getColumnState: function () {
        var me = this,
            items = me.items.items,
            
            iLen = items ? items.length : 0,
            i,
            columns = [],
            state = {
                id: me.getStateId()
            };

        me.savePropsToState(['hidden', 'sortable', 'locked', 'flex', 'width'], state);
        
        if (me.isGroupHeader) {
            for (i = 0; i < iLen; i++) {
                columns.push(items[i].getColumnState());
            }

            if (columns.length) {
                state.columns = columns;
            }
        } else if (me.isSubHeader && me.ownerCt.hidden) {
            
            delete me.hidden;
        }

        if ('width' in state) {
            delete state.flex; 
        }
        return state;
    },

    getStateId: function () {
        return this.stateId || this.headerId;
    },

    
    setText: function(text) {
        this.text = text;
        if (this.rendered) {
            this.textEl.update(text);
        }
    },

    
    
    getOwnerHeaderCt: function() {
        return this.up(':not([isHeader])');
    },

    
    getIndex: function() {
        return this.isGroupColumn ? false : this.getOwnerHeaderCt().getHeaderIndex(this);
    },
    
    
    getVisibleIndex: function() {
        return this.isGroupColumn ? false : Ext.Array.indexOf(this.getOwnerHeaderCt().getVisibleGridColumns(), this);
    },

    beforeRender: function() {
        var me = this,
            grid = me.up('tablepanel');

        me.callParent();

        
        
        if (grid && (!me.sortable || grid.sortableColumns === false) && !me.groupable &&
                     !me.lockable && (grid.enableColumnHide === false ||
                     !me.getOwnerHeaderCt().getHideableColumns().length)) {
            me.menuDisabled = true;
        }
    },

    afterRender: function() {
        var me = this,
            el = me.el;

        me.callParent(arguments);

        if (me.overCls) {
            el.addClsOnOver(me.overCls);
        }

        
        
        if (!Ext.isIE8 || !Ext.isStrict) {
            me.mon(me.getFocusEl(), {
                focus: me.onTitleMouseOver,
                blur: me.onTitleMouseOut,
                scope: me
            });
        }

        me.keyNav = new Ext.util.KeyNav(el, {
            enter: me.onEnterKey,
            down: me.onDownKey,
            scope: me
        });
    },

    
    
    afterComponentLayout: function(width, height, oldWidth, oldHeight) {
        var me = this,
            ownerHeaderCt = me.getOwnerHeaderCt();

        me.callParent(arguments);

        if (ownerHeaderCt && (oldWidth != null || me.flex) && width !== oldWidth) {
            ownerHeaderCt.onHeaderResize(me, width, true);
        }
    },

    
    
    
    setPadding: function(headerHeight) {
        var me = this,
            lineHeight = parseInt(me.textEl.getStyle('line-height'), 10),
            textHeight = me.textEl.dom.offsetHeight,
            titleEl = me.titleEl,
            availableHeight = headerHeight - me.el.getBorderWidth('tb'),
            titleElHeight;

        
        if (!me.isGroupHeader) {
            if (titleEl.getHeight() < availableHeight) {
                titleEl.setHeight(availableHeight);
                
                
                
                me.ownerCt.layout.innerCt.setHeight(headerHeight);
            }
        }
        titleElHeight = titleEl.getViewSize().height;

        
        if (textHeight) {
            if(lineHeight) {
                textHeight = Math.ceil(textHeight / lineHeight) * lineHeight;
            }
            titleEl.setStyle({
                paddingTop: Math.floor(Math.max(((titleElHeight - textHeight) / 2), 0)) + 'px'
            });
        }

        
        if (Ext.isIE && me.triggerEl) {
            me.triggerEl.setHeight(titleElHeight);
        }
    },

    onDestroy: function() {
        var me = this;
        
        Ext.destroy(me.textEl, me.keyNav, me.field);
        delete me.keyNav;
        me.callParent(arguments);
    },

    onTitleMouseOver: function() {
        this.titleEl.addCls(this.hoverCls);
    },

    onTitleMouseOut: function() {
        this.titleEl.removeCls(this.hoverCls);
    },

    onDownKey: function(e) {
        if (this.triggerEl) {
            this.onElClick(e, this.triggerEl.dom || this.el.dom);
        }
    },

    onEnterKey: function(e) {
        this.onElClick(e, this.el.dom);
    },

    
    onElDblClick: function(e, t) {
        var me = this,
            ownerCt = me.ownerCt;
        if (ownerCt && Ext.Array.indexOf(ownerCt.items, me) !== 0 && me.isOnLeftEdge(e) ) {
            ownerCt.expandToFit(me.previousSibling('gridcolumn'));
        }
    },

    onElClick: function(e, t) {

        
        var me = this,
            ownerHeaderCt = me.getOwnerHeaderCt();

        if (ownerHeaderCt && !ownerHeaderCt.ddLock) {
            
            
            if (me.triggerEl && (e.target === me.triggerEl.dom || t === me.triggerEl.dom || e.within(me.triggerEl))) {
                ownerHeaderCt.onHeaderTriggerClick(me, e, t);
            
            } else if (e.getKey() || (!me.isOnLeftEdge(e) && !me.isOnRightEdge(e))) {
                me.toggleSortState();
                ownerHeaderCt.onHeaderClick(me, e, t);
            }
        }
    },

    
    processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
        return this.fireEvent.apply(this, arguments);
    },

    toggleSortState: function() {
        var me = this,
            idx,
            nextIdx;

        if (me.sortable) {
            idx = Ext.Array.indexOf(me.possibleSortStates, me.sortState);

            nextIdx = (idx + 1) % me.possibleSortStates.length;
            me.setSortState(me.possibleSortStates[nextIdx]);
        }
    },

    doSort: function(state) {
        var ds = this.up('tablepanel').store;
        ds.sort({
            property: this.getSortParam(),
            direction: state
        });
    },

    
    getSortParam: function() {
        return this.dataIndex;
    },

    
    
    setSortState: function(state, skipClear, initial) {
        var me = this,
            colSortClsPrefix = Ext.baseCSSPrefix + 'column-header-sort-',
            ascCls = colSortClsPrefix + 'ASC',
            descCls = colSortClsPrefix + 'DESC',
            nullCls = colSortClsPrefix + 'null',
            ownerHeaderCt = me.getOwnerHeaderCt(),
            oldSortState = me.sortState;

        if (oldSortState !== state && me.getSortParam()) {
            me.addCls(colSortClsPrefix + state);
            
            if (state && !initial) {
                me.doSort(state);
            }
            switch (state) {
                case 'DESC':
                    me.removeCls([ascCls, nullCls]);
                    break;
                case 'ASC':
                    me.removeCls([descCls, nullCls]);
                    break;
                case null:
                    me.removeCls([ascCls, descCls]);
                    break;
            }
            if (ownerHeaderCt && !me.triStateSort && !skipClear) {
                ownerHeaderCt.clearOtherSortStates(me);
            }
            me.sortState = state;
            
            if (me.triStateSort || state != null) {
                ownerHeaderCt.fireEvent('sortchange', ownerHeaderCt, me, state);
            }
        }
    },

    hide: function(fromOwner) {
        var me = this,
            ownerHeaderCt = me.getOwnerHeaderCt(),
            owner = me.ownerCt,
            ownerIsGroup = owner.isGroupHeader,
            item, items, len, i;

        
        if (ownerIsGroup && !fromOwner) {
            items = owner.query('>:not([hidden])');
            
            if (items.length === 1 && items[0] == me) {
                me.ownerCt.hide();
                return;
            }
        }

        Ext.suspendLayouts();

        if (me.isGroupHeader) {
            items = me.items.items;
            for (i = 0, len = items.length; i < len; i++) {
                item = items[i];
                if (!item.hidden) {
                    item.hide(true);
                }
            }
        }

        me.callParent();
        
        ownerHeaderCt.onHeaderHide(me);

        Ext.resumeLayouts(true);
    },

    show: function(fromOwner, fromChild) {
        var me = this,
            ownerCt = me.ownerCt,
            items,
            len, i,
            item;

        Ext.suspendLayouts();

        
        if (me.isSubHeader && ownerCt.hidden) {
            ownerCt.show(false, true);
        }

        me.callParent(arguments);

        
        if (me.isGroupHeader && fromChild !== true && !me.query(':not([hidden])').length) {
            items = me.query('>*');
            for (i = 0, len = items.length; i < len; i++) {
                item = items[i];
                if (item.hidden) {
                    item.show(true);
                }
            }
        }

        Ext.resumeLayouts(true);

        
        ownerCt = me.getOwnerHeaderCt();
        if (ownerCt) {
            ownerCt.onHeaderShow(me);
        }
    },

    getDesiredWidth: function() {
        var me = this;
        if (me.rendered && me.componentLayout && me.componentLayout.lastComponentSize) {
            
            
            
            
            
            
            return me.componentLayout.lastComponentSize.width;
        
        
        
        }
        else if (me.flex) {
            
            return me.width;
        }
        else {
            return me.width;
        }
    },

    getCellSelector: function() {
        return '.' + Ext.baseCSSPrefix + 'grid-cell-' + this.getItemId();
    },

    getCellInnerSelector: function() {
        return this.getCellSelector() + ' .' + Ext.baseCSSPrefix + 'grid-cell-inner';
    },

    isOnLeftEdge: function(e) {
        return (e.getXY()[0] - this.el.getLeft() <= this.handleWidth);
    },

    isOnRightEdge: function(e) {
        return (this.el.getRight() - e.getXY()[0] <= this.handleWidth);
    }

    
    

    
    
});


Ext.define('Ext.grid.RowNumberer', {
    extend: 'Ext.grid.column.Column',
    alias: 'widget.rownumberer',

    
    text: "&#160",

    
    width: 23,

    
    sortable: false,
    
    
    draggable: false,

    align: 'right',

    constructor : function(config){

        
        
        this.width = this.width;

        this.callParent(arguments);
        if (this.rowspan) {
            this.renderer = Ext.Function.bind(this.renderer, this);
        }
    },

    
    resizable: false,
    hideable: false,
    menuDisabled: true,
    dataIndex: '',
    cls: Ext.baseCSSPrefix + 'row-numberer',
    rowspan: undefined,

    
    renderer: function(value, metaData, record, rowIdx, colIdx, store) {
        if (this.rowspan){
            metaData.cellAttr = 'rowspan="'+this.rowspan+'"';
        }

        metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
        return store.indexOfTotal(record) + 1;
    }
});


Ext.define('Ext.grid.column.Action', {
    extend: 'Ext.grid.column.Column',
    alias: ['widget.actioncolumn'],
    alternateClassName: 'Ext.grid.ActionColumn',

    
    
    
    
    
    
    
    
    
    

    actionIdRe: new RegExp(Ext.baseCSSPrefix + 'action-col-(\\d+)'),

    
    altText: '',

    
    menuText: '<i>Actions</i>',

    sortable: false,

    constructor: function(config) {
        var me = this,
            cfg = Ext.apply({}, config),
            items = cfg.items || [me],
            hasGetClass,
            i,
            len;


        me.origRenderer = cfg.renderer || me.renderer;
        me.origScope = cfg.scope || me.scope;
        
        delete me.renderer;
        delete me.scope;
        delete cfg.renderer;
        delete cfg.scope;
        
        
        delete cfg.items;
        me.callParent([cfg]);

        
        me.items = items;
        
        for (i = 0, len = items.length; i < len; ++i) {
            if (items[i].getClass) {
                hasGetClass = true;
                break;
            }
        }
        
        
        if (me.origRenderer || hasGetClass) {
            me.hasCustomRenderer = true;
        }
    },
    
    
    
    defaultRenderer: function(v, meta){
        var me = this,
            prefix = Ext.baseCSSPrefix,
            scope = me.origScope || me,
            items = me.items,
            len = items.length,
            i = 0,
            item;
            
        
        v = Ext.isFunction(me.origRenderer) ? me.origRenderer.apply(scope, arguments) || '' : '';

        meta.tdCls += ' ' + Ext.baseCSSPrefix + 'action-col-cell';
        for (; i < len; i++) {
            item = items[i];
            
            
            if (!item.hasActionConfiguration) {
                
                
                item.stopSelection = me.stopSelection;
                item.disable = Ext.Function.bind(me.disableAction, me, [i], 0);
                item.enable = Ext.Function.bind(me.enableAction, me, [i], 0);
                item.hasActionConfiguration = true;
            }
            
            v += '<img alt="' + (item.altText || me.altText) + '" src="' + (item.icon || Ext.BLANK_IMAGE_URL) +
                '" class="' + prefix + 'action-col-icon ' + prefix + 'action-col-' + String(i) + ' ' + (item.disabled ? prefix + 'item-disabled' : ' ') +
                ' ' + (Ext.isFunction(item.getClass) ? item.getClass.apply(item.scope || scope, arguments) : (item.iconCls || me.iconCls || '')) + '"' +
                ((item.tooltip) ? ' data-qtip="' + item.tooltip + '"' : '') + ' />';
        }
        return v;    
    },

    
    enableAction: function(index, silent) {
        var me = this;

        if (!index) {
            index = 0;
        } else if (!Ext.isNumber(index)) {
            index = Ext.Array.indexOf(me.items, index);
        }
        me.items[index].disabled = false;
        me.up('tablepanel').el.select('.' + Ext.baseCSSPrefix + 'action-col-' + index).removeCls(me.disabledCls);
        if (!silent) {
            me.fireEvent('enable', me);
        }
    },

    
    disableAction: function(index, silent) {
        var me = this;

        if (!index) {
            index = 0;
        } else if (!Ext.isNumber(index)) {
            index = Ext.Array.indexOf(me.items, index);
        }
        me.items[index].disabled = true;
        me.up('tablepanel').el.select('.' + Ext.baseCSSPrefix + 'action-col-' + index).addCls(me.disabledCls);
        if (!silent) {
            me.fireEvent('disable', me);
        }
    },

    destroy: function() {
        delete this.items;
        delete this.renderer;
        return this.callParent(arguments);
    },

    
    processEvent : function(type, view, cell, recordIndex, cellIndex, e, record, row){
        var me = this,
            target = e.getTarget(),
            match,
            item, fn,
            key = type == 'keydown' && e.getKey();

        
        
        
        if (key && !Ext.fly(target).findParent(view.cellSelector)) {
            target = Ext.fly(cell).down('.' + Ext.baseCSSPrefix + 'action-col-icon', true);
        }

        
        if (target && (match = target.className.match(me.actionIdRe))) {
            item = me.items[parseInt(match[1], 10)];
            if (item) {
                if (type == 'click' || (key == e.ENTER || key == e.SPACE)) {
                    fn = item.handler || me.handler;
                    if (fn && !item.disabled) {
                        fn.call(item.scope || me.origScope || me, view, recordIndex, cellIndex, item, e, record, row);
                    }
                } else if (type == 'mousedown' && item.stopSelection !== false) {
                    return false;
                }
            }
        }
        return me.callParent(arguments);
    },

    cascade: function(fn, scope) {
        fn.call(scope||this, this);
    },

    
    getRefItems: function() {
        return [];
    }
});


Ext.define('Ext.grid.column.Boolean', {
    extend: 'Ext.grid.column.Column',
    alias: ['widget.booleancolumn'],
    alternateClassName: 'Ext.grid.BooleanColumn',

    
    
    trueText: 'true',
    

    
    
    falseText: 'false',
    

    
    undefinedText: '&#160;',

    
    

    defaultRenderer: function(value){
        if (value === undefined) {
            return this.undefinedText;
        }
        
        if (!value || value === 'false') {
            return this.falseText;
        }
        return this.trueText;
    }
});

Ext.define('Ext.grid.column.Date', {
    extend: 'Ext.grid.column.Column',
    alias: ['widget.datecolumn'],
    requires: ['Ext.Date'],
    alternateClassName: 'Ext.grid.DateColumn',

    
    
    

    initComponent: function(){
        if (!this.format) {
            this.format = Ext.Date.defaultFormat;
        }
        
        this.callParent(arguments);
    },
    
    defaultRenderer: function(value){
        return Ext.util.Format.date(value, this.format);
    }
});

Ext.define('Ext.grid.column.Number', {
    extend: 'Ext.grid.column.Column',
    alias: ['widget.numbercolumn'],
    requires: ['Ext.util.Format'],
    alternateClassName: 'Ext.grid.NumberColumn',

    
    
    format : '0,000.00',
    

    
    

    defaultRenderer: function(value){
        return Ext.util.Format.number(value, this.format);
    }
});

Ext.define('Ext.grid.column.Template', {
    extend: 'Ext.grid.column.Column',
    alias: ['widget.templatecolumn'],
    requires: ['Ext.XTemplate'],
    alternateClassName: 'Ext.grid.TemplateColumn',

    
    
    

    initComponent: function(){
        var me = this;
        me.tpl = (!Ext.isPrimitive(me.tpl) && me.tpl.compile) ? me.tpl : new Ext.XTemplate(me.tpl);
        
        
        me.hasCustomRenderer = true;
        me.callParent(arguments);
    },
    
    defaultRenderer: function(value, meta, record) {
        var data = Ext.apply({}, record.data, record.getAssociatedData());
        return this.tpl.apply(data);
    }
});


Ext.define('Ext.grid.plugin.Editing', {
    alias: 'editing.editing',
    extend: 'Ext.AbstractPlugin',

    requires: [
        'Ext.grid.column.Column',
        'Ext.util.KeyNav'
    ],

    mixins: {
        observable: 'Ext.util.Observable'
    },

    
    clicksToEdit: 2,

    
    triggerEvent: undefined,

    
    defaultFieldXType: 'textfield',

    
    editStyle: '',

    constructor: function(config) {
        var me = this;

        me.addEvents(
            
            'beforeedit',

            
            'edit',

            
            'validateedit',
            
            'canceledit'

        );
        me.callParent(arguments);
        me.mixins.observable.constructor.call(me);
        
        me.on("edit", function(editor, e) {
            me.fireEvent("afteredit", editor, e);
        });
    },

    
    init: function(grid) {
        var me = this;

        me.grid = grid;
        me.view = grid.view;
        me.initEvents();
        me.mon(grid, 'reconfigure', me.onReconfigure, me);
        me.onReconfigure();

        grid.relayEvents(me, [
            
            'beforeedit',
            
            'edit',
            
            'validateedit',
            
            'canceledit'
        ]);
        
        
        grid.isEditable = true;
        grid.editingPlugin = grid.view.editingPlugin = me;
    },

    
    onReconfigure: function() {
        this.initFieldAccessors(this.view.getGridColumns());
    },

    
    destroy: function() {
        var me = this,
            grid = me.grid;

        Ext.destroy(me.keyNav);
        me.removeFieldAccessors(grid.getView().getGridColumns());

        
        me.clearListeners();

        delete me.grid.editingPlugin;
        delete me.grid.view.editingPlugin;
        delete me.grid;
        delete me.view;
        delete me.editor;
        delete me.keyNav;
    },

    
    getEditStyle: function() {
        return this.editStyle;
    },

    
    initFieldAccessors: function(columns) {
        columns = [].concat(columns);

        var me   = this,
            c,
            cLen = columns.length,
            column;

        for (c = 0; c < cLen; c++) {
            column = columns[c];

            Ext.applyIf(column, {
                getEditor: function(record, defaultField) {
                    return me.getColumnField(this, defaultField);
                },

                setEditor: function(field) {
                    me.setColumnField(this, field);
                }
            });
        }
    },

    
    removeFieldAccessors: function(columns) {
        columns = [].concat(columns);

        var c,
            cLen = columns.length,
            column;

        for (c = 0; c < cLen; c++) {
            column = columns[c];

            delete column.getEditor;
            delete column.setEditor;
        }
    },

    
    
    getColumnField: function(columnHeader, defaultField) {
        var field = columnHeader.field;

        if (!field && columnHeader.editor) {
            field = columnHeader.editor;
            delete columnHeader.editor;
        }

        if (!field && defaultField) {
            field = defaultField;
        }

        if (field) {
            if (Ext.isString(field)) {
                field = { xtype: field };
            }
            if (!field.isFormField) {
                field = Ext.ComponentManager.create(field, this.defaultFieldXType);
            }
            columnHeader.field = field;
 
            Ext.apply(field, {
                name: columnHeader.dataIndex
            });

            return field;
        }
    },

    
    
    setColumnField: function(column, field) {
        if (Ext.isObject(field) && !field.isFormField) {
            field = Ext.ComponentManager.create(field, this.defaultFieldXType);
        }
        column.field = field;
    },

    
    initEvents: function() {
        var me = this;
        me.initEditTriggers();
        me.initCancelTriggers();
    },

    
    initCancelTriggers: Ext.emptyFn,
    
    
    initEditTriggers: function() {
        var me = this,
            view = me.view;

        
        if (me.triggerEvent == 'cellfocus') {
            me.mon(view, 'cellfocus', me.onCellFocus, me);
        } else if (me.triggerEvent == 'rowfocus') {
            me.mon(view, 'rowfocus', me.onRowFocus, me);
        } else {

            
            
            
            
            
            
            if (view.selModel.isCellModel) {
                view.onCellFocus = Ext.Function.bind(me.beforeViewCellFocus, me);
            }

            
            me.mon(view, me.triggerEvent || ('cell' + (me.clicksToEdit === 1 ? 'click' : 'dblclick')), me.onCellClick, me);
        }
        
        
        
        me.initAddRemoveHeaderEvents()
        
        view.on('render', me.initKeyNavHeaderEvents, me, {single: true});
    },

    
    beforeViewCellFocus: function(position) {
        
        if (this.view.selModel.keyNavigation || !this.editing || !this.isCellEditable || !this.isCellEditable(position.row, position.columnHeader)) {
            this.view.focusCell.apply(this.view, arguments);
        }
    },

    
    onRowFocus: function(record, row, rowIdx) {
        this.startEdit(row, 0);
    },

    
    onCellFocus: function(record, cell, position) {
        this.startEdit(position.row, position.column);
    },

    
    onCellClick: function(view, cell, colIdx, record, row, rowIdx, e) {
        
        if(!view.expanderSelector || !e.getTarget(view.expanderSelector)) {
            this.startEdit(record, view.getHeaderAtIndex(colIdx));
        }
    },

    initAddRemoveHeaderEvents: function(){
        var me = this;
        me.mon(me.grid.headerCt, {
            scope: me,
            add: me.onColumnAdd,
            remove: me.onColumnRemove
        });
    },

    initKeyNavHeaderEvents: function() {
        var me = this;

        me.keyNav = Ext.create('Ext.util.KeyNav', me.view.el, {
            enter: me.onEnterKey,
            esc: me.onEscKey,
            scope: me
        });
    },
    
    
    onColumnAdd: function(ct, column) {
        if (column.isHeader) {
            this.initFieldAccessors(column);
        }
    },

    
    onColumnRemove: function(ct, column) {
        if (column.isHeader) {
            this.removeFieldAccessors(column);
        }
    },

    
    onEnterKey: function(e) {
        var me = this,
            grid = me.grid,
            selModel = grid.getSelectionModel(),
            record,
            pos,
            columnHeader = grid.headerCt.getHeaderAtIndex(0);

        
        
        if (selModel.getCurrentPosition) {
            pos = selModel.getCurrentPosition();
            if (pos) {
                record = grid.store.getAt(pos.row);
                columnHeader = grid.headerCt.getHeaderAtIndex(pos.column);
            }
        }
        
        else {
            record = selModel.getLastSelected();
        }

        
        if (record && columnHeader) {
            me.startEdit(record, columnHeader);
        }
    },

    
    onEscKey: function(e) {
        this.cancelEdit();
    },

    
    beforeEdit: Ext.emptyFn,

    
    startEdit: function(record, columnHeader) {
        var me = this,
            context = me.getEditingContext(record, columnHeader);

        if (context == null || me.beforeEdit(context) === false || me.fireEvent('beforeedit', me, context) === false || context.cancel || !me.grid.view.isVisible(true)) {
            return false;
        }

        me.context = context;

        
        me.editing = true;
    },

    
    
    getEditingContext: function(record, columnHeader) {
        var me = this,
            grid = me.grid,
            view = grid.getView(),
            node = view.getNode(record),
            rowIdx, colIdx;

        
        if (!node) {
            return;
        }

        
        columnHeader = grid.headerCt.getVisibleHeaderClosestToIndex(Ext.isNumber(columnHeader) ? columnHeader : columnHeader.getIndex());

        
        if (!columnHeader) {
            return;
        }

        colIdx = columnHeader.getIndex();

        if (Ext.isNumber(record)) {
            
            rowIdx = record;
            record = view.getRecord(node);
        } else {
            rowIdx = view.indexOf(node);
        }

        return {
            grid   : grid,
            record : record,
            field  : columnHeader.dataIndex,
            value  : record.get(columnHeader.dataIndex),
            row    : view.getNode(rowIdx),
            column : columnHeader,
            rowIdx : rowIdx,
            colIdx : colIdx
        };
    },

    
    cancelEdit: function() {
        var me = this;

        me.editing = false;
        me.fireEvent('canceledit', me, me.context);
    },

    
    completeEdit: function() {
        var me = this;

        if (me.editing && me.validateEdit()) {
            me.fireEvent('edit', me, me.context);
        }

        delete me.context;
        me.editing = false;
    },

    
    validateEdit: function() {
        var me = this,
            context = me.context;

        return me.fireEvent('validateedit', me, context) !== false && !context.cancel;
    }
});


Ext.define('Ext.grid.plugin.CellEditing', {
    alias: 'plugin.cellediting',
    extend: 'Ext.grid.plugin.Editing',
    requires: ['Ext.grid.CellEditor', 'Ext.util.DelayedTask'],

    constructor: function() {
        
        
        
        

        this.callParent(arguments);
        this.editors = new Ext.util.MixedCollection(false, function(editor) {
            return editor.editorId;
        });
        this.editTask = new Ext.util.DelayedTask();
    },

    onReconfigure: function(){
        this.editors.clear();
        this.callParent();    
    },

    
    destroy: function() {
        var me = this;
        me.editTask.cancel();
        me.editors.each(Ext.destroy, Ext);
        me.editors.clear();
        me.callParent(arguments);
    },
    
    onBodyScroll: function() {
        var me = this,
            ed = me.getActiveEditor(),
            scroll = me.view.el.getScroll();

        
        if (ed && ed.editing) {
            
            if (scroll.top !== me.scroll.top) {
                if (ed.field) {
                    if (ed.field.triggerBlur) {
                        ed.field.triggerBlur();
                    } else {
                        ed.field.blur();
                    }
                }
            }
            
            else {
                 ed.realign();
            }
        }
        me.scroll = scroll;
    },

    
    
    initCancelTriggers: function() {
        var me   = this,
            grid = me.grid,
            view = grid.view;
            
        view.addElListener('mousewheel', me.cancelEdit, me);
        me.mon(view, 'bodyscroll', me.onBodyScroll, me);
        me.mon(grid, {
            columnresize: me.cancelEdit,
            columnmove: me.cancelEdit,
            scope: me
        });
    },

    isCellEditable: function(record, columnHeader) {
        var me = this,
            context = me.getEditingContext(record, columnHeader);

        if (me.grid.view.isVisible(true) && context) {
            columnHeader = context.column;
            record = context.record;
            if (columnHeader && me.getEditor(record, columnHeader)) {
                return true;
            }
        }
    },

    
    startEdit: function(record, columnHeader) {
        var me = this,
            context = me.getEditingContext(record, columnHeader),
            value, ed;

        
        
        
        me.completeEdit();

        
        if (!context || !me.grid.view.isVisible(true)) {
            return false;
        }

        record = context.record;
        columnHeader = context.column;

        
        if (columnHeader && !columnHeader.getEditor(record)) {
            return false;
        }

        value = record.get(columnHeader.dataIndex);
        context.originalValue = context.value = value;
        if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', me, context) === false || context.cancel) {
            return false;
        }

        ed = me.getEditor(record, columnHeader);

        
        me.grid.view.cancelFocus();
        me.view.focusCell({
            row: context.rowIdx,
            column: context.colIdx
        });
        if (ed) {
            me.editTask.delay(15, me.showEditor, me, [ed, context, value]);
            return true;
        }
        return false;
    },

    showEditor: function(ed, context, value) {
        var me = this,
            record = context.record,
            columnHeader = context.column,
            sm = me.grid.getSelectionModel(),
            selection = sm.getCurrentPosition();

        me.context = context;
        me.setActiveEditor(ed);
        me.setActiveRecord(record);
        me.setActiveColumn(columnHeader);

        
        if (sm.selectByPosition && (!selection || selection.column !== context.colIdx || selection.row !== context.rowIdx)) {
            sm.selectByPosition({
                row: context.rowIdx,
                column: context.colIdx
            });
        }

        ed.startEdit(me.getCell(record, columnHeader), value);
        me.editing = true;
        me.scroll = me.view.el.getScroll();
    },

    completeEdit: function() {
        var activeEd = this.getActiveEditor();
        if (activeEd) {
            activeEd.completeEdit();
            this.editing = false;
        }
    },

    
    setActiveEditor: function(ed) {
        this.activeEditor = ed;
    },

    getActiveEditor: function() {
        return this.activeEditor;
    },

    setActiveColumn: function(column) {
        this.activeColumn = column;
    },

    getActiveColumn: function() {
        return this.activeColumn;
    },

    setActiveRecord: function(record) {
        this.activeRecord = record;
    },

    getActiveRecord: function() {
        return this.activeRecord;
    },

    getEditor: function(record, column) {
        var me = this,
            editors = me.editors,
            editorId = column.getItemId(),
            editor = editors.getByKey(editorId);

        if (editor) {
            return editor;
        } else {
            editor = column.getEditor(record);
            if (!editor) {
                return false;
            }

            
            
            
            if (!(editor instanceof Ext.grid.CellEditor)) {
                editor = new Ext.grid.CellEditor({
                    editorId: editorId,
                    field: editor,
                    ownerCt: me.grid
                });
            } else {
                editor.ownerCt = me.grid;
            }
            editor.editingPlugin = me;
            editor.isForTree = me.grid.isTree;
            editor.on({
                scope: me,
                specialkey: me.onSpecialKey,
                complete: me.onEditComplete,
                canceledit: me.cancelEdit
            });
            editors.add(editor);
            return editor;
        }
    },
    
    
    setColumnField: function(column, field) {
        var ed = this.editors.getByKey(column.getItemId());
        Ext.destroy(ed, column.field);
        this.editors.removeAtKey(column.getItemId());
        this.callParent(arguments);
    },

    
    getCell: function(record, column) {
        return this.grid.getView().getCell(record, column);
    },

    onSpecialKey: function(ed, field, e) {
        var me = this,
            grid = me.grid,
            sm;
            
        if (e.getKey() === e.TAB) {
            e.stopEvent();
            
            if (ed) {
                
                
                ed.onEditorTab(e);
            }
            
            sm = grid.getSelectionModel();
            if (sm.onEditorTab) {
                sm.onEditorTab(me, e);
            }
        }
    },

    onEditComplete : function(ed, value, startValue) {
        var me = this,
            grid = me.grid,
            activeColumn = me.getActiveColumn(),
            sm = grid.getSelectionModel(),
            record;

        if (activeColumn) {
            record = me.context.record;

            me.setActiveEditor(null);
            me.setActiveColumn(null);
            me.setActiveRecord(null);
    
            if (!me.validateEdit()) {
                return;
            }

            
            
            if (!record.isEqual(value, startValue)) {
                record.set(activeColumn.dataIndex, value);
            }

            
            if (sm.setCurrentPosition) {
                sm.setCurrentPosition(sm.getCurrentPosition());
            }
            grid.getView().getEl(activeColumn).focus();

            me.context.value = value;
            me.fireEvent('edit', me, me.context);
        }
    },

    
    cancelEdit: function() {
        var me = this,
            activeEd = me.getActiveEditor(),
            viewEl = me.grid.getView().getEl(me.getActiveColumn());

        me.setActiveEditor(null);
        me.setActiveColumn(null);
        me.setActiveRecord(null);
        if (activeEd) {
            activeEd.cancelEdit();
            viewEl.focus();
            me.callParent(arguments);
        }
    },

    
    startEditByPosition: function(position) {

        
        position.column = this.view.getHeaderCt().getVisibleHeaderClosestToIndex(position.column).getIndex();

        return this.startEdit(position.row, position.column);
    }
});


Ext.define('Ext.grid.property.HeaderContainer', {

    extend: 'Ext.grid.header.Container',

    alternateClassName: 'Ext.grid.PropertyColumnModel',
    
    nameWidth: 115,

    
    
    nameText : 'Name',
    
    
    valueText : 'Value',
    
    
    dateFormat : 'm/j/Y',
    
    
    trueText: 'true',
    
    
    falseText: 'false',
    

    
    nameColumnCls: Ext.baseCSSPrefix + 'grid-property-name',

    
    constructor : function(grid, store) {
        var me = this;
        
        me.grid = grid;
        me.store = store;
        me.callParent([{
            items: [{
                header: me.nameText,
                width: grid.nameColumnWidth || me.nameWidth,
                sortable: grid.sortableColumns,
                dataIndex: grid.nameField,
                renderer: Ext.Function.bind(me.renderProp, me),
                itemId: grid.nameField,
                menuDisabled :true,
                tdCls: me.nameColumnCls
            }, {
                header: me.valueText,
                renderer: Ext.Function.bind(me.renderCell, me),
                getEditor: Ext.Function.bind(me.getCellEditor, me),
                sortable: grid.sortableColumns,
                flex: 1,
                fixed: true,
                dataIndex: grid.valueField,
                itemId: grid.valueField,
                menuDisabled: true
            }]
        }]);
    },
    
    getCellEditor: function(record){
        return this.grid.getCellEditor(record, this);
    },

    
    
    renderProp : function(v) {
        return this.getPropertyName(v);
    },

    
    
    renderCell : function(val, meta, rec) {
        var me = this,
            renderer = me.grid.customRenderers[rec.get(me.grid.nameField)],
            result = val;

        if (renderer) {
            return renderer.apply(me, arguments);
        }
        if (Ext.isDate(val)) {
            result = me.renderDate(val);
        } else if (Ext.isBoolean(val)) {
            result = me.renderBool(val);
        }
        return Ext.util.Format.htmlEncode(result);
    },

    
    renderDate : Ext.util.Format.date,

    
    renderBool : function(bVal) {
        return this[bVal ? 'trueText' : 'falseText'];
    },

    
    
    getPropertyName : function(name) {
        var pn = this.grid.propertyNames;
        return pn && pn[name] ? pn[name] : name;
    }
});

Ext.define('Ext.layout.container.VBox', {

    

    alias: ['layout.vbox'],
    extend: 'Ext.layout.container.Box',
    alternateClassName: 'Ext.layout.VBoxLayout',

    

    
    align : 'left', 

    type: 'vbox',

    direction: 'vertical',

    horizontal: false,

    names: {
        
        lr: 'tb',
        left: 'top',
        leftCap: 'Top',
        right: 'bottom',
        position: 'top',
        width: 'height',
        contentWidth: 'contentHeight',
        minWidth: 'minHeight',
        maxWidth: 'maxHeight',
        widthCap: 'Height',
        widthModel: 'heightModel',
        widthIndex: 1,
        x: 'y',
        scrollLeft: 'scrollTop',
        overflowX: 'overflowY',
        hasOverflowX: 'hasOverflowY',
        invalidateScrollX: 'invalidateScrollY',

        
        center: 'center',
        top: 'left',
        topPosition: 'left',
        bottom: 'right',
        height: 'width',
        contentHeight: 'contentWidth',
        minHeight: 'minWidth',
        maxHeight: 'maxWidth',
        heightCap: 'Width',
        heightModel: 'widthModel',
        heightIndex: 0,
        y: 'x',
        scrollTop: 'scrollLeft',
        overflowY: 'overflowX',
        hasOverflowY: 'hasOverflowX',
        invalidateScrollY: 'invalidateScrollX',

        
        getWidth: 'getHeight',
        getHeight: 'getWidth',
        setWidth: 'setHeight',
        setHeight: 'setWidth',
        gotWidth: 'gotHeight',
        gotHeight: 'gotWidth',
        setContentWidth: 'setContentHeight',
        setContentHeight: 'setContentWidth',
        setWidthInDom: 'setHeightInDom',
        setHeightInDom: 'setWidthInDom'
    },

    sizePolicy: {
        flex: {
            '': {
                setsWidth: 0,
                setsHeight: 1
            },
            stretch: {
                setsWidth: 1,
                setsHeight: 1
            },
            stretchmax: {
                readsWidth: 1,
                setsWidth: 1,
                setsHeight: 1
            }
        },
        '': {
            setsWidth: 0,
            setsHeight: 0
        },
        stretch: {
            setsWidth: 1,
            setsHeight: 0
        },
        stretchmax: {
            readsWidth: 1,
            setsWidth: 1,
            setsHeight: 0
        }
    }
});


Ext.define('Ext.layout.container.Accordion', {
    extend: 'Ext.layout.container.VBox',
    alias: ['layout.accordion'],
    alternateClassName: 'Ext.layout.AccordionLayout',

    itemCls: [Ext.baseCSSPrefix + 'box-item', Ext.baseCSSPrefix + 'accordion-item'],

    align: 'stretch',

    
    fill : true,

    

    
    titleCollapse : true,

    
    hideCollapseTool : false,

    
    collapseFirst : false,

    
    animate : true,
    
    activeOnTop : false,
    
    multi: false,
    
    defaultAnimatePolicy: {
        y: true,
        height: true
    },

    constructor: function() {
        var me = this;

        me.callParent(arguments);

        if (me.animate) {
            me.animatePolicy = Ext.apply({}, me.defaultAnimatePolicy);
        } else {
            me.animatePolicy = null;
        }
    },

    beforeRenderItems: function (items) {
        var me = this,
            ln = items.length,
            i = 0,
            comp;

        for (; i < ln; i++) {
            comp = items[i];
            if (!comp.rendered) {
                
                if (me.collapseFirst) {
                    comp.collapseFirst = me.collapseFirst;
                }
                if (me.hideCollapseTool) {
                    comp.hideCollapseTool = me.hideCollapseTool;
                    comp.titleCollapse = true;
                }
                else if (me.titleCollapse) {
                    comp.titleCollapse = me.titleCollapse;
                }

                delete comp.hideHeader;
                delete comp.width;
                comp.collapsible = true;
                comp.title = comp.title || '&#160;';
                comp.addBodyCls(Ext.baseCSSPrefix + 'accordion-body');

                
                
                if (!me.multi) {
                    
                    if (me.expandedItem !== undefined) {
                        comp.collapsed = true;
                    }
                    
                    else if (comp.hasOwnProperty('collapsed') && comp.collapsed === false) {
                        me.expandedItem = i;
                    } else {
                        comp.collapsed = true;
                    }

                    
                    me.owner.mon(comp, {
                        show: me.onComponentShow,
                        beforeexpand: me.onComponentExpand,
                        scope: me
                    });
                }

                
                
                if (me.fill) {
                    me.owner.mon(comp, {
                        beforecollapse: me.onComponentCollapse,
                        scope: me
                    });
                }
            }
        }

        
        if (ln && me.expandedItem === undefined) {
            me.expandedItem = 0;
            items[0].collapsed = false;
        }
    },

    getItemsRenderTree: function(items) {
        this.beforeRenderItems(items);

        return this.callParent(arguments);
    },

    renderItems : function(items, target) {
        this.beforeRenderItems(items);

        this.callParent(arguments);
    },

    configureItem: function(item) {
        this.callParent(arguments);

        
        
        item.animCollapse = item.border = false;

        
        if (this.fill) {
            item.flex = 1;
        }
    },

    onChildPanelRender: function(panel) {
        panel.header.addCls(Ext.baseCSSPrefix + 'accordion-hd');
    },

    beginLayout: function (ownerContext) {
        this.callParent(arguments);
        this.updatePanelClasses(ownerContext);
    },

    updatePanelClasses: function(ownerContext) {
        var children = ownerContext.visibleItems,
            ln = children.length,
            siblingCollapsed = true,
            i, child, header;

        for (i = 0; i < ln; i++) {
            child = children[i];
            header = child.header;
            header.addCls(Ext.baseCSSPrefix + 'accordion-hd');

            if (siblingCollapsed) {
                header.removeCls(Ext.baseCSSPrefix + 'accordion-hd-sibling-expanded');
            } else {
                header.addCls(Ext.baseCSSPrefix + 'accordion-hd-sibling-expanded');
            }

            if (i + 1 == ln && child.collapsed) {
                header.addCls(Ext.baseCSSPrefix + 'accordion-hd-last-collapsed');
            } else {
                header.removeCls(Ext.baseCSSPrefix + 'accordion-hd-last-collapsed');
            }

            siblingCollapsed = child.collapsed;
        }
    },

    
    
    
    onComponentExpand: function(toExpand) {
        var me = this,
            owner = me.owner,
            expanded,
            expandedCount, i,
            previousValue;

        if (!me.processing) {
            me.processing = true;
            previousValue = owner.deferLayouts;
            owner.deferLayouts = true;
            expanded = me.multi ? [] : owner.query('>panel:not([collapsed])');
            expandedCount = expanded.length;
            
            
            for (i = 0; i < expandedCount; i++) {
                expanded[i].collapse();
            }
            owner.deferLayouts = previousValue;
            me.processing = false;
        }
    },

    onComponentCollapse: function(comp) {
        var me = this,
            owner = me.owner,
            toExpand,
            expanded,
            previousValue;

        if (me.owner.items.getCount() === 1) {
            
            return false;
        }

        if (!me.processing) {
            me.processing = true;
            previousValue = owner.deferLayouts;
            owner.deferLayouts = true;
            toExpand = comp.next() || comp.prev();

            
            
            if (me.multi) {
                expanded = me.owner.query('>panel:not([collapsed])');

                
                
                if (expanded.length === 1) {
                    toExpand.expand();
                }

            } else if (toExpand) {
                toExpand.expand();
            }
            owner.deferLayouts = previousValue;
            me.processing = false;
        }
    },

    onComponentShow: function(comp) {
        
        this.onComponentExpand(comp);
    }
});

Ext.define('Ext.toolbar.Spacer', {
    extend: 'Ext.Component',
    alias: 'widget.tbspacer',
    alternateClassName: 'Ext.Toolbar.Spacer',
    baseCls: Ext.baseCSSPrefix + 'toolbar-spacer',
    focusable: false
});

Ext.define('Ext.toolbar.TextItem', {
    extend: 'Ext.toolbar.Item',
    requires: ['Ext.XTemplate'],
    alias: 'widget.tbtext',
    alternateClassName: 'Ext.Toolbar.TextItem',

    
    text: '',

    renderTpl: '{text}',
    
    baseCls: Ext.baseCSSPrefix + 'toolbar-text',

    beforeRender : function() {
        var me = this;

        me.callParent();

        Ext.apply(me.renderData, {
            text: me.text
        });
    },

    
    setText : function(text) {
        var me = this;
        if (me.rendered) {
            me.el.update(text);
            me.updateLayout();
        } else {
            this.text = text;
        }
    }
});

Ext.define('Ext.toolbar.Toolbar', {
    extend: 'Ext.container.Container',
    requires: [
        'Ext.toolbar.Fill',
        'Ext.layout.container.HBox',
        'Ext.layout.container.VBox'
    ],
    uses: [
        'Ext.toolbar.Separator'
    ],
    alias: 'widget.toolbar',
    alternateClassName: 'Ext.Toolbar',

    
    isToolbar: true,
    baseCls  : Ext.baseCSSPrefix + 'toolbar',
    ariaRole : 'toolbar',

    defaultType: 'button',

    
    vertical: false,

    

    
    enableOverflow: false,

    
    menuTriggerCls: Ext.baseCSSPrefix + 'toolbar-more-icon',
    
    
    trackMenus: true,

    itemCls: Ext.baseCSSPrefix + 'toolbar-item',

    statics: {
        shortcuts: {
            '-' : 'tbseparator',
            ' ' : 'tbspacer'
        },

        shortcutsHV: {
            
            0: {
                '->': { xtype: 'tbfill', height: 0 }
            },
            
            1: {
                '->': { xtype: 'tbfill', width: 0 }
            }
        }
    },

    initComponent: function() {
        var me = this,
            keys;

        
        if (!me.layout && me.enableOverflow) {
            me.layout = { overflowHandler: 'Menu' };
        }

        if (me.dock === 'right' || me.dock === 'left') {
            me.vertical = true;
        }

        me.layout = Ext.applyIf(Ext.isString(me.layout) ? {
            type: me.layout
        } : me.layout || {}, {
            type: me.vertical ? 'vbox' : 'hbox',
            align: me.vertical ? 'stretchmax' : 'middle'
        });

        if (me.vertical) {
            me.addClsWithUI('vertical');
        }

        
        if (me.ui === 'footer') {
            me.ignoreBorderManagement = true;
        }

        me.callParent();

        
        me.addEvents('overflowchange');
    },

    getRefItems: function(deep) {
        var me = this,
            items = me.callParent(arguments),
            layout = me.layout,
            handler;

        if (deep && me.enableOverflow) {
            handler = layout.overflowHandler;
            if (handler && handler.menu) {
                items = items.concat(handler.menu.getRefItems(deep));
            }
        }
        return items;
    },

    

    
    lookupComponent: function(c) {
        if (typeof c == 'string') {
            var T = Ext.toolbar.Toolbar,
                shortcut = T.shortcutsHV[this.vertical ? 1 : 0][c] || T.shortcuts[c];

            if (typeof shortcut == 'string') {
                c = {
                    xtype: shortcut
                };
            } else if (shortcut) {
                c = Ext.apply({}, shortcut);
            } else {
                c = {
                    xtype: 'tbtext',
                    text: c
                };
            }

            this.applyDefaults(c);
        }

        return this.callParent(arguments);
    },

    
    applyDefaults: function(c) {
        if (!Ext.isString(c)) {
            c = this.callParent(arguments);
        }
        return c;
    },

    
    trackMenu: function(item, remove) {
        if (this.trackMenus && item.menu) {
            var method = remove ? 'mun' : 'mon',
                me = this;

            me[method](item, 'mouseover', me.onButtonOver, me);
            me[method](item, 'menushow', me.onButtonMenuShow, me);
            me[method](item, 'menuhide', me.onButtonMenuHide, me);
        }
    },

    
    constructButton: function(item) {
        return item.events ? item
                : Ext.widget(item.split ? 'splitbutton' : this.defaultType, item);
    },

    
    onBeforeAdd: function(component) {
        if (component.is('field') || (component.is('button') && this.ui != 'footer')) {
            component.ui = component.ui + '-toolbar';
        }

        
        if (component instanceof Ext.toolbar.Separator) {
            component.setUI((this.vertical) ? 'vertical' : 'horizontal');
        }

        this.callParent(arguments);
    },

    
    onAdd: function(component) {
        this.callParent(arguments);
        this.trackMenu(component);
    },
    
    
    onRemove: function(c) {
        this.callParent(arguments);
        this.trackMenu(c, true);
    },
    
    getChildItemsToDisable: function() {
        return this.items.getRange();   
    },

    
    onButtonOver: function(btn){
        if (this.activeMenuBtn && this.activeMenuBtn != btn) {
            this.activeMenuBtn.hideMenu();
            btn.showMenu();
            this.activeMenuBtn = btn;
        }
    },

    
    onButtonMenuShow: function(btn) {
        this.activeMenuBtn = btn;
    },

    
    onButtonMenuHide: function(btn) {
        delete this.activeMenuBtn;
    }
});

Ext.define('Ext.panel.AbstractPanel', {

    

    extend: 'Ext.container.Container',

    mixins: {
        docking: 'Ext.container.DockingContainer'
    },

    requires: ['Ext.util.MixedCollection', 'Ext.Element', 'Ext.toolbar.Toolbar'],

    

    
    baseCls : Ext.baseCSSPrefix + 'panel',

    

    

    

    

    
    isPanel: true,

    componentLayout: 'dock',

    childEls: [
        'body'
    ],

    renderTpl: [
        
        '{% this.renderDockedItems(out,values,0); %}',
        
        
        
        
        
        
        
        (Ext.isIE6 || Ext.isIE7 || Ext.isIEQuirks) ? '<div></div>' : '',
        '<div id="{id}-body" class="{baseCls}-body<tpl if="bodyCls"> {bodyCls}</tpl>',
            ' {baseCls}-body-{ui}<tpl if="uiCls">',
                '<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl>',
            '</tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>>',
            '{%this.renderContainer(out,values);%}',
        '</div>',
        '{% this.renderDockedItems(out,values,1); %}'
    ],

    bodyPosProps: {
        x: 'x',
        y: 'y'
    },

    
    

    border: true,

    
    emptyArray: [],

    initComponent : function() {
        var me = this;

        
        

        if (me.frame && me.border && me.bodyBorder === undefined) {
            me.bodyBorder = false;
        }
        if (me.frame && me.border && (me.bodyBorder === false || me.bodyBorder === 0)) {
            me.manageBodyBorders = true;
        }

        me.callParent();
    },

    beforeDestroy: function(){
        this.destroyDockedItems();
        this.callParent();
    },

    
    initItems : function() {
        this.callParent();
        this.initDockingItems();
    },

    
    initRenderData: function() {
        var me = this,
            data = me.callParent();

        me.initBodyStyles();
        me.protoBody.writeTo(data);
        delete me.protoBody;

        return data;
    },

    
    getComponent: function(comp) {
        var component = this.callParent(arguments);
        if (component === undefined && !Ext.isNumber(comp)) {
            
            component = this.getDockedComponent(comp);
        }
        return component;
    },

    getProtoBody: function () {
        var me = this,
            body = me.protoBody;

        if (!body) {
            me.protoBody = body = new Ext.util.ProtoElement({
                cls: me.bodyCls,
                style: me.bodyStyle,
                clsProp: 'bodyCls',
                styleProp: 'bodyStyle',
                styleIsText: true
            });
        }

        return body;
    },

    
    initBodyStyles: function() {
        var me = this,
            body = me.getProtoBody(),
            Element = Ext.Element;

        if (me.bodyPadding !== undefined) {
            body.setStyle('padding', Element.unitizeBox((me.bodyPadding === true) ? 5 : me.bodyPadding));
        }
        if (me.frame && me.bodyBorder) {
            if (!Ext.isNumber(me.bodyBorder)) {
                me.bodyBorder = 1;
            }
            body.setStyle('border-width', Element.unitizeBox(me.bodyBorder));
        }
    },

    getCollapsedDockedItems: function () {
        var me = this;
        return me.collapseMode == 'placeholder' ? me.emptyArray : [ me.getReExpander() ];
    },

    
    setBodyStyle: function(style, value) {
        var me = this,
            body = me.rendered ? me.body : me.getProtoBody();

        if (Ext.isFunction(style)) {
            style = style();
        }
        if (arguments.length == 1) {
            if (Ext.isString(style)) {
                style = Ext.Element.parseStyles(style);     
            }
            body.setStyle(style);
        } else {
            body.setStyle(style, value);
        }
        return me;
    },

    
    addBodyCls: function(cls) {
        var me = this,
            body = me.rendered ? me.body : me.getProtoBody();

        body.addCls(cls);
        return me;
    },

    
    removeBodyCls: function(cls) {
        var me = this,
            body = me.rendered ? me.body : me.getProtoBody();

        body.removeCls(cls);
        return me;
    },

    
    addUIClsToElement: function(cls) {
        var me = this,
            result = me.callParent(arguments);

        me.addBodyCls([Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls]);
        return result;
    },

    
    removeUIClsFromElement: function(cls) {
        var me = this,
            result = me.callParent(arguments);

        me.removeBodyCls([Ext.baseCSSPrefix + cls, me.baseCls + '-body-' + cls, me.baseCls + '-body-' + me.ui + '-' + cls]);
        return result;
    },

    
    addUIToElement: function() {
        var me = this;

        me.callParent(arguments);
        me.addBodyCls(me.baseCls + '-body-' + me.ui);
    },

    
    removeUIFromElement: function() {
        var me = this;

        me.callParent(arguments);
        me.removeBodyCls(me.baseCls + '-body-' + me.ui);
    },

    
    getTargetEl : function() {
        return this.body;
    },

    getRefItems: function(deep) {
        var items = this.callParent(arguments);

        return this.getDockingRefItems(deep, items);
    },

    setupRenderTpl: function (renderTpl) {
        this.callParent(arguments);
        this.setupDockingRenderTpl(renderTpl);
    }
});


Ext.define('Ext.panel.Panel', {
    extend: 'Ext.panel.AbstractPanel',
    requires: [
        'Ext.panel.Header',
        'Ext.fx.Anim',
        'Ext.util.KeyMap',
        'Ext.panel.DD',
        'Ext.XTemplate',
        'Ext.layout.component.Dock',
        'Ext.util.Memento'
    ],
    alias: 'widget.panel',
    alternateClassName: 'Ext.Panel',

    
    collapsedCls: 'collapsed',

    
    animCollapse: Ext.enableFx,

    
    minButtonWidth: 75,

    
    collapsed: false,

    
    collapseFirst: true,

    
    hideCollapseTool: false,

    
    titleCollapse: false,

    

    

    
    floatable: true,

    

    
    collapsible: false,

    

    
    closable: false,

    
    closeAction: 'destroy',

    

    
    placeholderCollapseHideMode: Ext.Element.VISIBILITY,

    
     preventHeader: false,

    
    header: undefined,

    
    headerPosition: 'top',

    
    frame: false,

    
    frameHeader: true,

    

    

    
    titleAlign: 'left',

    
    manageHeight: true,

    
    
    

    initComponent: function() {
        var me = this;

        me.addEvents(

            
            'beforeclose',
            
            
            'close',

            
            "beforeexpand",

            
            "beforecollapse",

            
            "expand",

            
            "collapse",

            
            'titlechange',

            
            'iconchange',
            
            
            'iconclschange'
        );

        if (me.collapsible) {
        
            this.addStateEvents(['expand', 'collapse']);
        }
        if (me.unstyled) {
            me.setUI('plain');
        }

        if (me.frame) {
            me.setUI(me.ui + '-framed');
        }

        
        me.bridgeToolbars();

        me.callParent();
        me.collapseDirection = me.collapseDirection || me.headerPosition || Ext.Component.DIRECTION_TOP;

        
        me.hiddenOnCollapse = new Ext.dom.CompositeElement();

    },

    beforeDestroy: function() {
        var me = this;
        Ext.destroy(
            me.placeholder,
            me.ghostPanel,
            me.dd
        );
        me.callParent();
    },

    initAria: function() {
        this.callParent();
        this.initHeaderAria();
    },

    getFocusEl: function() {
        return  this.el;
    },

    initHeaderAria: function() {
        var me = this,
            el = me.el,
            header = me.header;
        if (el && header) {
            el.dom.setAttribute('aria-labelledby', header.titleCmp.id);
        }
    },

    
    getHeader: function() {
        return this.header;
    },

    
    setTitle: function(newTitle) {
        var me = this,
            oldTitle = me.title,
            header = me.header,
            reExpander = me.reExpander,
            placeholder = me.placeholder;

        me.title = newTitle;

        if (header) {
            if (header.isHeader) {
                header.setTitle(newTitle);
            } else {
                header.title = newTitle;
            }
        } else {
            me.updateHeader();
        }

        if (reExpander) {
            reExpander.setTitle(newTitle);
        }

        if (placeholder && placeholder.setTitle) {
            placeholder.setTitle(newTitle);
        }

        me.fireEvent('titlechange', me, newTitle, oldTitle);
    },

    
    setIconCls: function(newIconCls) {
        var me = this,
            oldIconCls = me.iconCls,
            header = me.header,
            placeholder = me.placeholder;

        me.iconCls = newIconCls;

        if (header) {
            if (header.isHeader) {
                header.setIconCls(newIconCls);
            } else {
                header.iconCls = newIconCls;
            }
        } else {
            me.updateHeader();
        }

        if (placeholder && placeholder.setIconCls) {
            placeholder.setIconCls(newIconCls);
        }

        me.fireEvent('iconclschange', me, newIconCls, oldIconCls);
    },
    
    
    setIcon: function(newIcon) {
        var me = this,
            oldIcon = me.icon,
            header = me.header,
            placeholder = me.placeholder;

        me.icon = newIcon;

        if (header) {
            if (header.isHeader) {
                header.setIcon(newIcon);
            } else {
                header.icon = newIcon;
            }
        } else {
            me.updateHeader();
        }

        if (placeholder && placeholder.setIcon) {
            placeholder.setIcon(newIcon);
        }

        me.fireEvent('iconchange', me, newIcon, oldIcon);
    },

    bridgeToolbars: function() {
        var me = this,
            docked = [],
            fbar,
            fbarDefaults,
            minButtonWidth = me.minButtonWidth;

        function initToolbar (toolbar, pos, useButtonAlign) {
            if (Ext.isArray(toolbar)) {
                toolbar = {
                    xtype: 'toolbar',
                    items: toolbar
                };
            }
            else if (!toolbar.xtype) {
                toolbar.xtype = 'toolbar';
            }
            toolbar.dock = pos;
            if (pos == 'left' || pos == 'right') {
                toolbar.vertical = true;
            }

            
            if (useButtonAlign) {
                toolbar.layout = Ext.applyIf(toolbar.layout || {}, {
                    
                    pack: { left:'start', center:'center' }[me.buttonAlign] || 'end'
                });
            }
            return toolbar;
        }

        

        

        
        if (me.tbar) {
            docked.push(initToolbar(me.tbar, 'top'));
            me.tbar = null;
        }

        
        if (me.bbar) {
            docked.push(initToolbar(me.bbar, 'bottom'));
            me.bbar = null;
        }

        
        if (me.buttons) {
            me.fbar = me.buttons;
            me.buttons = null;
        }

        
        if (me.fbar) {
            fbar = initToolbar(me.fbar, 'bottom', true); 
            fbar.ui = 'footer';

            
            if (minButtonWidth) {
                fbarDefaults = fbar.defaults;
                fbar.defaults = function(config) {
                    var defaults = fbarDefaults || {};
                    if ((!config.xtype || config.xtype === 'button' || (config.isComponent && config.isXType('button'))) &&
                            !('minWidth' in defaults)) {
                        defaults = Ext.apply({minWidth: minButtonWidth}, defaults);
                    }
                    return defaults;
                };
            }

            docked.push(fbar);
            me.fbar = null;
        }

        
        if (me.lbar) {
            docked.push(initToolbar(me.lbar, 'left'));
            me.lbar = null;
        }

        
        if (me.rbar) {
            docked.push(initToolbar(me.rbar, 'right'));
            me.rbar = null;
        }

        if (me.dockedItems) {
            if (!Ext.isArray(me.dockedItems)) {
                me.dockedItems = [me.dockedItems];
            }
            me.dockedItems = me.dockedItems.concat(docked);
        } else {
            me.dockedItems = docked;
        }
    },

    isPlaceHolderCollapse: function(){
        return this.collapseMode == 'placeholder';
    },

    onBoxReady: function(){
        this.callParent();
        if (this.collapsed) {
            this.setHiddenDocked();
        }    
    },

    beforeRender: function() {
        var me = this,
            wasCollapsed;

        me.callParent();

        
        
        me.initTools();

        
        if (!(me.preventHeader || (me.header === false))) {
            me.updateHeader();
        }

        
        if (me.collapsed) {
            if (me.isPlaceHolderCollapse()) {
                me.hidden = true;

                
                
                
                me.placeholderCollapse();
                wasCollapsed = me.collapsed;

                
                
                
                me.collapsed = false;
            } else {
                me.beginCollapse();
                me.addClsWithUI(me.collapsedCls);
            }
        }

        
        if (wasCollapsed) {
            me.collapsed = wasCollapsed;
        }
    },

    
    initTools: function() {
        var me = this;

        me.tools = me.tools ? Ext.Array.clone(me.tools) : [];

        
        
        if (me.collapsible && !(me.hideCollapseTool || me.header === false || me.preventHeader)) {
            me.collapseDirection = me.collapseDirection || me.headerPosition || 'top';
            me.collapseTool = me.expandTool = Ext.widget({
                xtype: 'tool',
                type: (me.collapsed && !me.isPlaceHolderCollapse()) ? ('expand-' + me.getOppositeDirection(me.collapseDirection)) : ('collapse-' + me.collapseDirection),
                handler: me.toggleCollapse,
                scope: me
            });

            
            if (me.collapseFirst) {
                me.tools.unshift(me.collapseTool);
            }
        }

        
        me.addTools();

        
        if (me.closable) {
            me.addClsWithUI('closable');
            me.addTool({
                type: 'close',
                handler: Ext.Function.bind(me.close, me, [])
            });
        }

        
        if (me.collapseTool && !me.collapseFirst) {
            me.addTool(me.collapseTool);
        }
    },

    
    addTools: Ext.emptyFn,

    
    close: function() {
        if (this.fireEvent('beforeclose', this) !== false) {
            this.doClose();
        }
    },

    
    doClose: function() {
        this.fireEvent('close', this);
        this[this.closeAction]();
    },

    
    updateHeader: function(force) {
        var me = this,
            header = me.header,
            title = me.title,
            tools = me.tools,
            icon = me.icon || me.iconCls,
            vertical = me.headerPosition == 'left' || me.headerPosition == 'right';

        if ((header !== false) && (force || (title || icon) || (tools && tools.length) || (me.collapsible && !me.titleCollapse))) {
            if (header && header.isHeader) {
                header.show();
            } else {
                
                header = me.header = Ext.widget(Ext.apply({
                    xtype       : 'header',
                    title       : title,
                    titleAlign  : me.titleAlign,
                    orientation : vertical ? 'vertical' : 'horizontal',
                    dock        : me.headerPosition || 'top',
                    textCls     : me.headerTextCls,
                    iconCls     : me.iconCls,
                    icon        : me.icon,
                    baseCls     : me.baseCls + '-header',
                    tools       : tools,
                    ui          : me.ui,
                    id          : me.id + '_header',
                    indicateDrag: me.draggable,
                    frame       : (me.frame || me.alwaysFramed) && me.frameHeader,
                    ignoreParentFrame : me.frame || me.overlapHeader,
                    ignoreBorderManagement: me.frame || me.ignoreHeaderBorderManagement,
                    listeners   : me.collapsible && me.titleCollapse ? {
                        click: me.toggleCollapse,
                        scope: me
                    } : null
                }, me.header));
                me.addDocked(header, 0);

                
                
                me.tools = header.tools;
            }
            me.initHeaderAria();
        } else if (header) {
            header.hide();
        }
    },

    
    setUI: function(ui) {
        var me = this;

        me.callParent(arguments);

        if (me.header && me.header.rendered) {
            me.header.setUI(ui);
        }
    },

    
    getContentTarget: function() {
        return this.body;
    },

    getTargetEl: function() {
        var me = this;
        return me.body || me.protoBody || me.frameBody || me.el;
    },

    

    
    isVisible: function(deep){
        var me = this;
        if (me.collapsed && me.placeholder) {
            return me.placeholder.isVisible(deep);
        }
        return me.callParent(arguments);
    },

    
    onHide: function(){
        var me = this;
        if (me.collapsed && me.placeholder) {
            me.placeholder.hide();
        } else {
            me.callParent(arguments);
        }
    },

    
    onShow: function(){
        var me = this;
        if (me.collapsed && me.placeholder) {
            
            me.hidden = true;
            me.placeholder.show();
        } else {
            me.callParent(arguments);
        }
    },

    onRemoved: function(destroying) {
        var me = this;

        me.callParent(arguments);

        
        
        if (me.placeholder && !destroying) {
            me.ownerCt.remove(me.placeholder, false);
        }
    },

    addTool: function(tools) {
        tools = [].concat(tools);

        var me     = this,
            header = me.header,
            t,
            tLen   = tools.length,
            tool;

        for (t = 0; t < tLen; t++) {
            tool = tools[t];

            me.tools.push(tool);

            if (header && header.isHeader) {
                header.addTool(tool);
            }
        }

        me.updateHeader();
    },

    getOppositeDirection: function(d) {
        var c = Ext.Component;
        switch (d) {
            case c.DIRECTION_TOP:
                return c.DIRECTION_BOTTOM;
            case c.DIRECTION_RIGHT:
                return c.DIRECTION_LEFT;
            case c.DIRECTION_BOTTOM:
                return c.DIRECTION_TOP;
            case c.DIRECTION_LEFT:
                return c.DIRECTION_RIGHT;
        }
    },

    getWidthAuthority: function() {
        if (this.collapsed && this.collapsedHorizontal()) {
            return 1; 
        }

        return this.callParent();
    },

    getHeightAuthority: function() {
        if (this.collapsed && this.collapsedVertical()) {
            return 1; 
        }

        return this.callParent();
    },

    collapsedHorizontal: function () {
        var dir = this.getCollapsed();
        return dir == 'left' || dir == 'right';
    },

    collapsedVertical: function () {
        var dir = this.getCollapsed();
        return dir == 'top' || dir == 'bottom';
    },
    
    restoreDimension: function(){
        var dir = this.collapseDirection;
        
        
        return (dir === 'top' || dir === 'bottom') ? 'height' : 'width';    
    },

    
    getCollapsed: function() {
        var me = this;
        
        
        if (me.collapsed === true) {
            return me.collapseDirection;
        }
        return me.collapsed;
    },

    getState: function() {
        var me = this,
            state = me.callParent(),
            memento;

        state = me.addPropertyToState(state, 'collapsed');

        
        if (me.collapsed) {
            memento = me.collapseMemento;
            memento = memento && memento.data;

            if (me.collapsedVertical()) {
                if (state) {
                    delete state.height;
                }
                if (memento) {
                    state = me.addPropertyToState(state, 'height', memento.height);
                }
            } else {
                if (state) {
                    delete state.width;
                }
                if (memento) {
                    state = me.addPropertyToState(state, 'width', memento.width);
                }
            }
        }

        return state;
    },

    findReExpander: function (direction) {
        var me = this,
            c = Ext.Component,
            dockedItems = me.dockedItems.items,
            dockedItemCount = dockedItems.length,
            comp, i;
            
        
        if (me.collapseMode == 'mini') {
            return;
        }

        switch (direction) {
            case c.DIRECTION_TOP:
            case c.DIRECTION_BOTTOM:

                
                
                for (i = 0; i < dockedItemCount; i++) {
                    comp = dockedItems[i];
                    if (!comp.hidden) {
                        if (comp.isHeader && (!comp.dock || comp.dock == 'top' || comp.dock == 'bottom')) {
                            return comp;
                        }
                    }
                }
                break;

            case c.DIRECTION_LEFT:
            case c.DIRECTION_RIGHT:

                
                
                for (i = 0; i < dockedItemCount; i++) {
                    comp = dockedItems[i];
                    if (!comp.hidden) {
                        if (comp.isHeader && (comp.dock == 'left' || comp.dock == 'right')) {
                            return comp;
                        }
                    }
                }
                break;

            default:
                throw('Panel#findReExpander must be passed a valid collapseDirection');
        }
    },

    getReExpander: function (direction) {
        var me = this,
            collapseDir = direction || me.collapseDirection,
            reExpander = me.reExpander || me.findReExpander(collapseDir);

        me.expandDirection = me.getOppositeDirection(collapseDir);

        if (!reExpander) {
        
            me.reExpander = reExpander = me.createReExpander(collapseDir, {
                dock: collapseDir,
                cls: Ext.baseCSSPrefix + 'docked ' + me.baseCls + '-' + me.ui + '-collapsed',
                ownerCt: me,
                ownerLayout: me.componentLayout
            });

            me.dockedItems.insert(0, reExpander);
        }
        return reExpander;
    },

    createReExpander: function(direction, defaults) {
        var me = this,
            isLeft = direction == 'left',
            isRight = direction == 'right',
            isVertical = isLeft || isRight,
            toolAtTop,
            result = Ext.apply({
                hideMode: 'offsets',
                title: me.title,
                orientation: isVertical ? 'vertical' : 'horizontal',
                textCls: me.headerTextCls,
                icon: me.icon,
                iconCls: me.iconCls,
                baseCls: me.baseCls + '-header',
                ui: me.ui,
                frame: me.frame && me.frameHeader,
                ignoreParentFrame: me.frame || me.overlapHeader,
                indicateDrag: me.draggable
            }, defaults);
            
            
            
            if (me.collapseMode == 'mini') {
                if (isVertical) {
                    result.width = 1;
                } else {
                    result.height = 1;
                }
            }

        
        
        
        if (!me.hideCollapseTool) {
            toolAtTop = isLeft || (isRight && me.isPlaceHolderCollapse());
            result[toolAtTop ? 'items' : 'tools'] = [{
                xtype: 'tool',
                type: 'expand-' + me.getOppositeDirection(direction),
                uiCls: ['top'],
                handler: me.toggleCollapse,
                scope: me
            }];
        }
        result = new Ext.panel.Header(result);
        result.addClsWithUI(me.getHeaderCollapsedClasses(result));
        return result;
    },

    
    
    getHeaderCollapsedClasses: function(header) {
        var me = this,
            collapsedCls = me.collapsedCls,
            collapsedClasses;

        collapsedClasses = [ collapsedCls, collapsedCls + '-' + header.dock];
        if (me.border && (!me.frame || (me.frame && Ext.supports.CSS3BorderRadius))) {
            collapsedClasses.push(collapsedCls + '-border-' + header.dock);
        }
        return collapsedClasses;
    },

    
    beginCollapse: function() {
        var me = this,
            lastBox = me.lastBox,
            rendered = me.rendered,
            collapseMemento = me.collapseMemento || (me.collapseMemento = new Ext.util.Memento(me)),
            sizeModel = me.getSizeModel(),
            reExpander;

        
        
        
        
        
        
        
        
        
        
        
        collapseMemento.capture(['height', 'minHeight', 'width', 'minWidth']);
        if (lastBox) {
            collapseMemento.capture(me.restoreDimension(), lastBox, 'last.');
        }
        
        
        
        
        
        if (me.collapsedVertical()) {
            if (sizeModel.width.shrinkWrap) {
                me.width = rendered ? me.getWidth() : me.width || me.minWidth || 100;
            }
            delete me.height;
            me.minHeight = 0;
        } else if (me.collapsedHorizontal()) {
            if (sizeModel.height.shrinkWrap) {
                me.height = rendered ? me.getHeight() : me.height || me.minHeight || 100;
            }
            delete me.width;
            me.minWidth = 0;
        }

        if (me.ownerCt) {
            me.ownerCt.getLayout().beginCollapse(me);
        }

        
        
        if (!me.isPlaceHolderCollapse()) {
            if (me.header === (reExpander = me.getReExpander())) {
                me.header.addClsWithUI(me.getHeaderCollapsedClasses(me.header));

                
                if (me.header.rendered) {
                    me.header.updateFrame();
                }
            }
            
            else {
                if (reExpander.el) {
                    reExpander.el.show();
                    reExpander.hidden = false;
                }
            }
        }
        if (me.resizer) {
            me.resizer.disable();
        }
    },

    beginExpand: function() {
        var me = this,
            lastBox = me.lastBox,
            collapseMemento = me.collapseMemento,
            restoreDimension = this.restoreDimension(),
            reExpander;

        collapseMemento.restore(['minHeight', 'minWidth', restoreDimension]);
        if (lastBox) {
            collapseMemento.restore(restoreDimension, true, lastBox, 'last.');
        }

        if (me.ownerCt) {
            me.ownerCt.getLayout().beginExpand(me);
        }

        if (!me.isPlaceHolderCollapse()) {
            
            if (me.header === (reExpander = me.getReExpander())) {
                me.header.removeClsWithUI(me.getHeaderCollapsedClasses(me.header));

                
                if (me.header.rendered) {
                    me.header.updateFrame();
                }
            }
            
            else {
                reExpander.hidden = true;
                reExpander.el.hide();
            }
        }
        if (me.resizer) {
            me.resizer.enable();
        }
    },

    
    collapse: function(direction, animate) {
        var me = this,
            collapseDir = direction || me.collapseDirection,
            ownerCt = me.ownerCt;

        if (me.isCollapsingOrExpanding) {
            return me;
        }

        if (arguments.length < 2) {
            animate = me.animCollapse;
        }

        if (me.collapsed || me.fireEvent('beforecollapse', me, direction, animate) === false) {
            return me;
        }

        if (ownerCt && me.isPlaceHolderCollapse()) {
            return me.placeholderCollapse(direction, animate);
        }

        me.collapsed = collapseDir;
        me.beginCollapse();

        me.fireHierarchyEvent('collapse');

        return me.doCollapseExpand(1, animate);
    },

    doCollapseExpand: function (flags, animate) {
        var me = this,
            originalAnimCollapse = me.animCollapse,
            ownerLayout = me.ownerLayout;

        
        
        me.animCollapse = animate;

        
        
        me.isCollapsingOrExpanding = flags;

        if (ownerLayout && !animate) {
            ownerLayout.onContentChange(me);
        } else {
            me.updateLayout({ isRoot: true });
        }

        
        me.animCollapse = originalAnimCollapse;

        return me;
    },

    
    afterCollapse: function(animated) {
        var me = this,
            ownerLayout = me.ownerLayout;

        me.isCollapsingOrExpanding = 0;
        if (me.collapseTool) {
            me.collapseTool.setType('expand-' + me.getOppositeDirection(me.collapseDirection));
        }

        if (ownerLayout && animated) {
            ownerLayout.onContentChange(me);
        }

        me.setHiddenDocked();
        me.fireEvent('collapse', me);
    },
    
    setHiddenDocked: function(){
        
        
        var me = this,
            toHide = me.hiddenOnCollapse,
            reExpander = me.getReExpander(),
            items = me.getDockedItems(),
            len = items.length,
            i = 0,
            item;
            
        toHide.add(me.body);
        for (; i < len; i++) {
            item = items[i];
            if (item && item !== reExpander && item.el) {
                toHide.add(item.el);
            }
        }
        toHide.setStyle('visibility', 'hidden');
    },
    
    restoreHiddenDocked: function(){
        var toShow = this.hiddenOnCollapse;
        
        toShow.setStyle('visibility', '');
        toShow.clear();
    },

    getPlaceholder: function(direction) {
        var me = this,
            collapseDir = direction || me.collapseDirection,
            listeners = null,
            placeholder = me.placeholder;

        if (!placeholder) {
            if (me.floatable || (me.collapsible && me.titleCollapse)) {
                listeners = {
                    click: {
                        fn: me.floatable ? me.floatCollapsedPanel : me.toggleCollapse,
                        element: 'el',
                        scope: me
                    }
                };
            }

            me.placeholder = placeholder = Ext.widget(me.createReExpander(collapseDir, {
                id: me.id + '-placeholder',
                listeners: listeners
            }));
        }

        
        if (!placeholder.placeholderFor) {
            
            if (!placeholder.isComponent) {
                me.placeholder = placeholder = me.lookupComponent(placeholder);
            }
            Ext.applyIf(placeholder, {
                margins: me.margins,
                placeholderFor: me
            });

            placeholder.addCls([Ext.baseCSSPrefix + 'region-collapsed-placeholder', Ext.baseCSSPrefix + 'region-collapsed-' + collapseDir + '-placeholder', me.collapsedCls]);
        }

        return placeholder;
    },

    placeholderCollapse: function(direction, animate) {
        var me = this,
            ownerCt = me.ownerCt,
            collapseDir = direction || me.collapseDirection,
            floatCls = Ext.baseCSSPrefix + 'border-region-slide-in',
            placeholder = me.getPlaceholder(direction);

        me.isCollapsingOrExpanding = 1;

        
        me.hidden = true;
        me.collapsed = collapseDir;

        if (placeholder.rendered) {
            
            if (placeholder.el.dom.parentNode !== me.el.dom.parentNode) {
                me.el.dom.parentNode.insertBefore(placeholder.el.dom, me.el.dom);
            }

            placeholder.hidden = false;
            placeholder.el.show();
            ownerCt.updateLayout();
        } else {
            ownerCt.insert(ownerCt.items.indexOf(me), placeholder);
        }

        if (me.rendered) {
            
            me.el.setVisibilityMode(me.placeholderCollapseHideMode);
            if (animate) {
                me.el.addCls(floatCls);
                placeholder.el.hide();

                me.el.slideOut(collapseDir.substr(0, 1), {
                    preserveScroll: true,
                    duration: Ext.Number.from(animate, Ext.fx.Anim.prototype.duration),
                    listeners: {
                        afteranimate: function() {
                            me.el.removeCls(floatCls);
                            
                            placeholder.el.show().setStyle('display', 'none').slideIn(collapseDir.substr(0, 1), {
                                easing: 'linear',
                                duration: 100,
                                listeners: {
                                    afteranimate: function() {
                                        placeholder.focus();
                                        me.isCollapsingOrExpanding = 0;
                                        me.fireEvent('collapse', me);
                                    }
                                }
                            });
                        }
                    }
                });
            } else {
                me.el.hide();
                me.isCollapsingOrExpanding = 0;
                me.fireEvent('collapse', me);
            }
        } else {
            me.isCollapsingOrExpanding = 0;
            me.fireEvent('collapse', me);
        }

        return me;
    },

    floatCollapsedPanel: function() {
        var me = this,
            placeholder = me.placeholder,
            pb = placeholder.getBox(true),
            myBox,
            floatCls = Ext.baseCSSPrefix + 'border-region-slide-in',
            collapsed = me.collapsed,
            layoutOwner = me.ownerCt || me,
            slideDirection;

        
        if (me.el.hasCls(floatCls)) {
            me.slideOutFloatedPanel();
            return;
        }

        if (me.isSliding) {
            return;
        }
        me.isSliding = true;

        
        
        function onMouseLeaveFloated(e) {
            if (!me.isDestroyed) {
                var slideRegion = me.el.getRegion().union(placeholder.el.getRegion()).adjust(1, -1, -1, 1);

                
                if (!slideRegion.contains(e.getPoint())) {
                    me.slideOutFloatedPanel();
                }
            }
        }

        
        me.placeholder.el.hide();
        me.placeholder.hidden = true;
        me.el.show();
        me.hidden = false;
        me.collapsed = false;
        layoutOwner.updateLayout();
        myBox = me.getBox(true);

        
        me.placeholder.el.show();
        me.placeholder.hidden = false;
        me.el.hide();
        me.hidden = true;
        me.collapsed = collapsed;
        layoutOwner.updateLayout();

        
        me.placeholderMouseMon = placeholder.el.monitorMouseLeave(500, onMouseLeaveFloated);
        me.panelMouseMon       = me.el.monitorMouseLeave(500, onMouseLeaveFloated);
        me.el.addCls(floatCls);

        
        if (me.collapseTool) {
            me.collapseTool.el.hide();
        }

        switch (me.collapsed) {
            case 'top':
                me.el.setLeftTop(pb.x, pb.y + pb.height - 1);
                slideDirection = 't';
                break;
            case 'right':
                me.el.setLeftTop(pb.x - myBox.width + 1, pb.y);
                slideDirection = 'r';
                break;
            case 'bottom':
                me.el.setLeftTop(pb.x, pb.y - myBox.height + 1);
                slideDirection = 'b';
                break;
            case 'left':
                me.el.setLeftTop(pb.x + pb.width - 1, pb.y);
                slideDirection = 'l';
                break;
        }

        
        
        me.floatedFromCollapse = me.collapsed;
        me.collapsed = me.hidden = false;

        me.el.slideIn(slideDirection, {
            preserveScroll: true,
            listeners: {
                afteranimate: function() {
                    me.isSliding = false;
                }
            }
        });
    },

    isLayoutRoot: function() {
        if (this.floatedFromCollapse) {
            return true;
        }
        return this.callParent();
    },

    slideOutFloatedPanel: function() {
        var me = this,
            compEl = this.el,
            collapseDirection;

        if (me.isSliding) {
            return;
        }

        me.isSliding = true;

        me.slideOutFloatedPanelBegin();

        if (typeof me.collapsed == 'string') {
            collapseDirection = me.collapsed.charAt(0);
        }

        compEl.slideOut(collapseDirection, {
            preserveScroll: true,
            listeners: {
                afteranimate: function() {
                    me.slideOutFloatedPanelEnd();
                    
                    
                    me.el.removeCls(Ext.baseCSSPrefix + 'border-region-slide-in');
                    me.isSliding = false;
                }
            }
        });
    },

    
    slideOutFloatedPanelBegin: function() {
        var me = this,
            compEl = this.el;

        me.collapsed = me.floatedFromCollapse;
        me.hidden = true;
        me.floatedFromCollapse = null;

        
        compEl.un(me.panelMouseMon);
        me.placeholder.el.un(me.placeholderMouseMon);
    },

    
    slideOutFloatedPanelEnd: function() {
        if (this.collapseTool) {
            this.collapseTool.el.show();
        }
    },

    
    expand: function(animate) {
        var me = this;

        if (me.isCollapsingOrExpanding) {
            return me;
        }

        if (!arguments.length) {
            animate = me.animCollapse;
        }

        if (!me.collapsed && !me.floatedFromCollapse) {
            return me;
        }

        if (me.fireEvent('beforeexpand', me, animate) === false) {
            return me;
        }

        if (me.isPlaceHolderCollapse()) {
            return me.placeholderExpand(animate);
        }

        me.restoreHiddenDocked();
        me.beginExpand();
        me.collapsed = false;

        me.fireHierarchyEvent('expand');

        return me.doCollapseExpand(2, animate);
    },

    placeholderExpand: function(animate) {
        var me = this,
            collapseDir = me.collapsed,
            floatCls = Ext.baseCSSPrefix + 'border-region-slide-in',
            finalPos,
            floatedPos,
            slideInDirection;

        if (me.floatedFromCollapse) {
            floatedPos = me.getPosition(true);
            
            me.slideOutFloatedPanelBegin();
            me.slideOutFloatedPanelEnd();
        }

        me.isCollapsingOrExpanding = 2;

        
        me.placeholder.hidden = true;
        me.placeholder.el.hide();
        me.collapsed = false;
        me.show();

        if (animate) {
            
            if (floatedPos) {
                finalPos = me.el.getXY();
                me.el.setLeftTop(floatedPos[0], floatedPos[1]);
                me.el.moveTo(finalPos[0], finalPos[1], {
                    duration: Ext.Number.from(animate, Ext.fx.Anim.prototype.duration),
                    listeners: {
                        afteranimate: function() {
                            me.el.removeCls(floatCls);
                            me.isCollapsingOrExpanding = 0;
                            me.fireEvent('expand', me);
                        }
                    }
                });
            }
            
            else {
                me.hidden = true;
                me.el.addCls(floatCls);
                me.el.hide();
                me.collapsed = collapseDir;
                me.placeholder.show();
                slideInDirection = collapseDir.substr(0, 1);

                
                me.hidden = false;
                me.el.slideIn(slideInDirection, {
                    preserveScroll: true,
                    duration: Ext.Number.from(animate, Ext.fx.Anim.prototype.duration),
                    listeners: {
                        afteranimate: function() {
                            me.collapsed = false;

                            
                            
                            
                            
                            
                            me.el.removeCls(floatCls);
                            me.placeholder.hide();

                            me.isCollapsingOrExpanding = 0;
                            me.fireEvent('expand', me);
                        }
                    }
                });
            }

        } else {
            me.isCollapsingOrExpanding = 0;
            me.fireEvent('expand', me);
        }

        return me;
    },

    
    afterExpand: function(animated) {
        var me = this,
            ownerLayout = me.ownerLayout;

        me.isCollapsingOrExpanding = 0;
        if (me.collapseTool) {
            me.collapseTool.setType('collapse-' + me.collapseDirection);
        }

        if (ownerLayout && animated) {
            ownerLayout.onContentChange(me);
        }

        me.fireEvent('expand', me);
    },
    
    
    setBorder: function(border, targetEl) {
        if (targetEl) {
            
            return;
        }
        
        var me = this,
            header = me.header;
            
        if (!border) {
            border = 0;
        } else {
            border = Ext.Element.unitizeBox((border === true) ? 1 : border);
        }
        
        if (header) {
            if (header.isHeader) {
                header.setBorder(border);
            } else {
                header.border = border;
            }
        }
        
        if (me.rendered && me.bodyBorder !== false) {
            me.body.setStyle('border-width', border);
        }
        me.updateLayout();
        
        me.border = border;
    },

    
    toggleCollapse: function() {
        return (this.collapsed || this.floatedFromCollapse) ? this.expand() : this.collapse();
    },

    
    getKeyMap : function() {
        return this.keyMap || (this.keyMap = new Ext.util.KeyMap(Ext.apply({
            target: this.el
        }, this.keys)));
    },

    
    initDraggable : function(){
        
        this.dd = new Ext.panel.DD(this, Ext.isBoolean(this.draggable) ? null : this.draggable);
    },

    
    ghostTools : function() {
        var tools = [],
            header = this.header,
            headerTools = header ? header.query('tool[hidden=false]') : [],
            t, tLen, tool;

        if (headerTools.length) {
            t = 0;
            tLen = headerTools.length;

            for (; t < tLen; t++) {
                tool = headerTools[t];

                
                
                
                
                tools.push({
                    type: tool.type
                });
            }
        } else {
            tools = [{
                type: 'placeholder'
            }];
        }
        return tools;
    },

    
    ghost: function(cls) {
        var me = this,
            ghostPanel = me.ghostPanel,
            box = me.getBox(),
            header;

        if (!ghostPanel) {
            ghostPanel = new Ext.panel.Panel({
                renderTo: document.body,
                floating: {
                    shadow: false
                },
                frame: me.frame && !me.alwaysFramed,
                alwaysFramed: me.alwaysFramed,
                overlapHeader: me.overlapHeader,
                headerPosition: me.headerPosition,
                baseCls: me.baseCls,
                cls: me.baseCls + '-ghost ' + (cls ||'')
            });
            me.ghostPanel = ghostPanel;
        } else {
            ghostPanel.el.show();
        }
        ghostPanel.floatParent = me.floatParent;
        if (me.floating) {
            ghostPanel.setZIndex(Ext.Number.from(me.el.getStyle('zIndex'), 0));
        } else {
            ghostPanel.toFront();
        }
        if (!(me.preventHeader || (me.header === false))) {
            header = ghostPanel.header;
            
            if (header) {
                header.suspendLayouts();
                Ext.Array.forEach(header.query('tool'), header.remove, header);
                header.resumeLayouts();
            }
            ghostPanel.addTool(me.ghostTools());
            ghostPanel.setTitle(me.title);
            ghostPanel.setIconCls(me.iconCls);
        }

        ghostPanel.setPagePosition(box.x, box.y);
        ghostPanel.setSize(box.width, box.height);
        me.el.hide();
        return ghostPanel;
    },

    
    unghost: function(show, matchPosition) {
        var me = this;
        if (!me.ghostPanel) {
            return;
        }
        if (show !== false) {
            
            
            me.el.show();
            if (matchPosition !== false) {
                me.setPagePosition(me.ghostPanel.el.getXY());
                if (me.hideMode == 'offsets') {
                    
                    delete me.el.hideModeStyles;
                }
            }
            Ext.defer(me.focus, 10, me);
        }
        me.ghostPanel.el.hide();
    },

    beginDrag: function() {
        if (this.floatingDescendants) {
            this.floatingDescendants.hide();
        }
    },

    endDrag: function() {
        if (this.floatingDescendants) {
            this.floatingDescendants.show();
        }
    },

    initResizable: function(resizable) {
        if (this.collapsed) {
            resizable.disabled = true;
        }
        this.callParent([resizable]);
    }
}, function() {
    this.prototype.animCollapse = Ext.enableFx;
});


Ext.define('Ext.container.ButtonGroup', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.buttongroup',
    alternateClassName: 'Ext.ButtonGroup',

    requires: ['Ext.layout.container.Table'],

    

    
    baseCls: Ext.baseCSSPrefix + 'btn-group',

    
    layout: {
        type: 'table'
    },

    defaultType: 'button',

    
    frame: true,

    frameHeader: false,

    titleAlign: 'center',

    initComponent : function() {
        
        var me = this,
            cols = me.columns;

        me.noTitleCls = me.baseCls + '-notitle';
        if (cols) {
            me.layout = Ext.apply({}, {columns: cols}, me.layout);
        }

        if (!me.title) {
            me.addCls(me.noTitleCls);
        }
        me.callParent(arguments);
    },

    
    onBeforeAdd: function(component) {
        if (component.isButton) {
            component.ui = component.ui + '-toolbar';
        }
        this.callParent(arguments);
    },

    
    applyDefaults: function(c) {
        if (!Ext.isString(c)) {
            c = this.callParent(arguments);
        }
        return c;
    }

    
    
    
    
    
});


Ext.define('Ext.menu.Menu', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.menu',
    requires: [
        'Ext.layout.container.Fit',
        'Ext.layout.container.VBox',
        'Ext.menu.CheckItem',
        'Ext.menu.Item',
        'Ext.menu.KeyNav',
        'Ext.menu.Manager',
        'Ext.menu.Separator'
    ],

    
    
    
    enableKeyNav: true,

    
    allowOtherMenus: false,

    
    ariaRole: 'menu',

    

    
    defaultAlign: 'tl-bl?',

    
    floating: true,

    
    constrain: true,

    
    hidden: true,

    hideMode: 'visibility',

    
    ignoreParentClicks: false,

    
    isMenu: true,

    

    
    showSeparator : true,

    
    minWidth: undefined,
    
    defaultMinWidth: 120,

    

    initComponent: function() {
        var me = this,
            prefix = Ext.baseCSSPrefix,
            cls = [prefix + 'menu'],
            bodyCls = me.bodyCls ? [me.bodyCls] : [],
            isFloating = me.floating !== false;

        me.addEvents(
            
            'click',

            
            'mouseenter',

            
            'mouseleave',

            
            'mouseover'
        );

        Ext.menu.Manager.register(me);

        
        if (me.plain) {
            cls.push(prefix + 'menu-plain');
        }
        me.cls = cls.join(' ');

        
        bodyCls.unshift(prefix + 'menu-body');
        me.bodyCls = bodyCls.join(' ');

        
        
        
        
        if (!me.layout) {
            me.layout = {
                type: 'vbox',
                align: 'stretchmax',
                overflowHandler: 'Scroller'
            };
        }
        
        
        if (isFloating && me.minWidth === undefined) {
            me.minWidth = me.defaultMinWidth;
        }

        
        if (!isFloating && me.initialConfig.hidden !== true) {
            me.hidden = false;
        }

        me.callParent(arguments);

        me.on('beforeshow', function() {
            var hasItems = !!me.items.length;
            
            
            
            if (hasItems && me.rendered) {
                me.el.setStyle('visibility', null);
            }
            return hasItems;
        });
    },

    beforeRender: function() {
        this.callParent(arguments);

        
        
        if (!this.getSizeModel().width.shrinkWrap) {
            this.layout.align = 'stretch';
        }
    },

    onBoxReady: function() {
        var me = this,
            separatorSpec;

        me.callParent(arguments);

        
        if (me.showSeparator) {
            separatorSpec = {
                cls: Ext.baseCSSPrefix + 'menu-icon-separator',
                html: '&#160;'
            };
            if ((!Ext.isStrict && Ext.isIE) || Ext.isIE6) {
                separatorSpec.style = 'height:' + me.el.getHeight() + 'px';
            }
            me.iconSepEl = me.layout.getElementTarget().insertFirst(separatorSpec);
        }

        me.mon(me.el, {
            click: me.onClick,
            mouseover: me.onMouseOver,
            scope: me
        });
        me.mouseMonitor = me.el.monitorMouseLeave(100, me.onMouseLeave, me);

        if (me.enableKeyNav) {
            me.keyNav = new Ext.menu.KeyNav(me);
        }
    },

    getBubbleTarget: function() {
        
        
        
        return this.parentMenu || this.ownerButton || this.callParent(arguments);
    },

    
    canActivateItem: function(item) {
        return item && !item.isDisabled() && item.isVisible() && (item.canActivate || item.getXTypes().indexOf('menuitem') < 0);
    },

    
    deactivateActiveItem: function(andBlurFocusedItem) {
        var me = this,
            activeItem = me.activeItem,
            focusedItem = me.focusedItem;

        if (activeItem) {
            activeItem.deactivate();
            if (!activeItem.activated) {
                delete me.activeItem;
            }
        }

        
        
        if (focusedItem && andBlurFocusedItem) {
            focusedItem.blur();
            delete me.focusedItem;
        }
    },

    
    getFocusEl: function() {
        return this.focusedItem || this.el;
    },

    
    hide: function() {
        this.deactivateActiveItem(true);
        this.callParent(arguments);
    },

    
    getItemFromEvent: function(e) {
        return this.getChildByElement(e.getTarget());
    },

    lookupComponent: function(cmp) {
        var me = this;

        if (typeof cmp == 'string') {
            cmp = me.lookupItemFromString(cmp);
        } else if (Ext.isObject(cmp)) {
            cmp = me.lookupItemFromObject(cmp);
        }

        
        
        cmp.minWidth = cmp.minWidth || me.minWidth;

        return cmp;
    },

    
    lookupItemFromObject: function(cmp) {
        var me = this,
            prefix = Ext.baseCSSPrefix,
            cls;

        if (!cmp.isComponent) {
            if (!cmp.xtype) {
                cmp = Ext.create('Ext.menu.' + (Ext.isBoolean(cmp.checked) ? 'Check': '') + 'Item', cmp);
            } else {
                cmp = Ext.ComponentManager.create(cmp, cmp.xtype);
            }
        }

        if (cmp.isMenuItem) {
            cmp.parentMenu = me;
        }

        if (!cmp.isMenuItem && !cmp.dock) {
            cls = [prefix + 'menu-item', prefix + 'menu-item-cmp'];

            if (!me.plain && (cmp.indent === true || cmp.iconCls === 'no-icon')) {
                cls.push(prefix + 'menu-item-indent');
            }

            if (cmp.rendered) {
                cmp.el.addCls(cls);
            } else {
                cmp.cls = (cmp.cls ? cmp.cls : '') + ' ' + cls.join(' ');
            }
        }
        return cmp;
    },

    
    lookupItemFromString: function(cmp) {
        return (cmp == 'separator' || cmp == '-') ?
            new Ext.menu.Separator()
            : new Ext.menu.Item({
                canActivate: false,
                hideOnClick: false,
                plain: true,
                text: cmp
            });
    },

    onClick: function(e) {
        var me = this,
            item;

        if (me.disabled) {
            e.stopEvent();
            return;
        }

        item = (e.type === 'click') ? me.getItemFromEvent(e) : me.activeItem;
        if (item && item.isMenuItem) {
            if (!item.menu || !me.ignoreParentClicks) {
                item.onClick(e);
            } else {
                e.stopEvent();
            }
        }
        
        if (!item || item.disabled) {
            item = undefined;
        }
        me.fireEvent('click', me, item, e);
    },

    onDestroy: function() {
        var me = this;

        Ext.menu.Manager.unregister(me);
        delete me.parentMenu;
        delete me.ownerButton;
        if (me.rendered) {
            me.el.un(me.mouseMonitor);
            Ext.destroy(me.keyNav);
            delete me.keyNav;
        }
        me.callParent(arguments);
    },

    onMouseLeave: function(e) {
        var me = this;

        me.deactivateActiveItem();

        if (me.disabled) {
            return;
        }

        me.fireEvent('mouseleave', me, e);
    },

    onMouseOver: function(e) {
        var me = this,
            fromEl = e.getRelatedTarget(),
            mouseEnter = !me.el.contains(fromEl),
            item = me.getItemFromEvent(e),
            parentMenu = me.parentMenu,
            parentItem = me.parentItem;

        if (mouseEnter && parentMenu) {
            parentMenu.setActiveItem(parentItem);
            parentItem.cancelDeferHide();
            parentMenu.mouseMonitor.mouseenter();
        }

        if (me.disabled) {
            return;
        }

        
        if (item && !item.activated) {
            me.setActiveItem(item);
            if (item.activated && item.expandMenu) {
                item.expandMenu();
            }
        }
        if (mouseEnter) {
            me.fireEvent('mouseenter', me, e);
        }
        me.fireEvent('mouseover', me, item, e);
    },

    setActiveItem: function(item) {
        var me = this;

        if (item && (item != me.activeItem)) {
            me.deactivateActiveItem();
            if (me.canActivateItem(item)) {
                if (item.activate) {
                    item.activate();
                    if (item.activated) {
                        me.activeItem = item;
                        me.focusedItem = item;
                        me.focus();
                    }
                } else {
                    item.focus();
                    me.focusedItem = item;
                }
            }
            item.el.scrollIntoView(me.layout.getRenderTarget());
        }
    },

    
    showBy: function(cmp, pos, off) {
        var me = this;

        if (me.floating && cmp) {
            me.show();

            
            
            
            me.setPagePosition(me.el.getAlignToXY(cmp.el || cmp, pos || me.defaultAlign, off));
            me.setVerticalPosition();
        }
        return me;
    },

    show: function() {
        var me = this,
            parentEl, viewHeight, result,
            maxWas = me.maxHeight;

        
        if (!me.rendered){
            me.doAutoRender();
        }

        
        if (me.floating) {
            
            parentEl = Ext.fly(me.el.getScopeParent());
            viewHeight = parentEl.getViewSize().height;
            me.maxHeight  =  Math.min(maxWas || viewHeight, viewHeight);
        }

        result = me.callParent(arguments);
        me.maxHeight = maxWas;
        return result;
    },

    afterComponentLayout: function(width, height, oldWidth, oldHeight){
        var me = this;
        me.callParent(arguments);
        
        if (me.showSeparator){
            me.iconSepEl.setHeight(me.componentLayout.lastComponentSize.contentHeight);
        }
    },

    
    
    
    setVerticalPosition: function(){
        var me = this,
            max,
            y = me.el.getY(),
            returnY = y,
            height = me.getHeight(),
            viewportHeight = Ext.Element.getViewportHeight().height,
            parentEl = Ext.fly(me.el.getScopeParent()),
            viewHeight = parentEl.getViewSize().height,
            normalY = y - parentEl.getScroll().top; 

        parentEl = null;

        if (me.floating) {
            max = me.maxHeight ? me.maxHeight : viewHeight - normalY;
            if (height > viewHeight) {
                returnY = y - normalY;
            } else if (max < height) {
                returnY = y - (height - max);
            } else if((y + height) > viewportHeight){ 
                returnY = viewportHeight - height;
            }
        }
        me.el.setY(returnY);
    }
});

 Ext.define('Ext.menu.ColorPicker', {
     extend: 'Ext.menu.Menu',

     alias: 'widget.colormenu',

     requires: [
        'Ext.picker.Color'
     ],

    
    hideOnClick : true,

    
    pickerId : null,

    

    

    

    initComponent : function(){
        var me = this,
            cfg = Ext.apply({}, me.initialConfig);

        
        delete cfg.listeners;
        Ext.apply(me, {
            plain: true,
            showSeparator: false,
            items: Ext.applyIf({
                cls: Ext.baseCSSPrefix + 'menu-color-item',
                id: me.pickerId,
                xtype: 'colorpicker'
            }, cfg)
        });

        me.callParent(arguments);

        me.picker = me.down('colorpicker');

        
        me.relayEvents(me.picker, ['select']);

        if (me.hideOnClick) {
            me.on('select', me.hidePickerOnSelect, me);
        }
    },

    
    hidePickerOnSelect: function() {
        Ext.menu.Manager.hideAll();
    }
 });

 Ext.define('Ext.menu.DatePicker', {
     extend: 'Ext.menu.Menu',

     alias: 'widget.datemenu',

     requires: [
        'Ext.picker.Date'
     ],

    
    hideOnClick : true,

    
    pickerId : null,

    

    

    initComponent : function(){
        var me = this,
            cfg = Ext.apply({}, me.initialConfig);
            
        
        delete cfg.listeners;
            
        Ext.apply(me, {
            showSeparator: false,
            plain: true,
            border: false,
            bodyPadding: 0, 
            items: Ext.applyIf({
                cls: Ext.baseCSSPrefix + 'menu-date-item',
                id: me.pickerId,
                xtype: 'datepicker'
            }, cfg)
        });

        me.callParent(arguments);

        me.picker = me.down('datepicker');
        
        me.relayEvents(me.picker, ['select']);

        if (me.hideOnClick) {
            me.on('select', me.hidePickerOnSelect, me);
        }
    },

    hidePickerOnSelect: function() {
        Ext.menu.Manager.hideAll();
    }
 });

Ext.define('Ext.panel.Table', {
    extend: 'Ext.panel.Panel',

    alias: 'widget.tablepanel',

    uses: [
        'Ext.selection.RowModel',
        'Ext.selection.CellModel',
        'Ext.selection.CheckboxModel',
        'Ext.grid.PagingScroller',
        'Ext.grid.header.Container',
        'Ext.grid.Lockable'
    ],

    extraBaseCls: Ext.baseCSSPrefix + 'grid',
    extraBodyCls: Ext.baseCSSPrefix + 'grid-body',

    layout: 'fit',
    
    hasView: false,

    
    
    viewType: null,

    

    

    
    selType: 'rowmodel',

    

    

    

    

    
    scroll: true,

    

    

    

    

    

    

    deferRowRender: true,
     
    
    sortableColumns: true,

    
    enableLocking: false,

    
    
    scrollerOwner: true,

    
    enableColumnMove: true,
    
    
    sealedColumns: false,

    
    enableColumnResize: true,

    
    enableColumnHide: true,

    

    
    rowLines: true,

    

    
    
    

    

    initComponent: function() {

        var me          = this,
            scroll      = me.scroll,
            vertical    = false,
            horizontal  = false,
            headerCtCfg = me.columns || me.colModel,
            view,
            border = me.border,
            i, len;

        if (me.columnLines) {
            me.addCls(Ext.baseCSSPrefix + 'grid-with-col-lines');
        }

        if (me.rowLines) {
            me.addCls(Ext.baseCSSPrefix + 'grid-with-row-lines');
        }

        
        me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');


        
        
        if (headerCtCfg instanceof Ext.grid.header.Container) {
            me.headerCt = headerCtCfg;
            me.headerCt.border = border;
            me.columns = me.headerCt.items.items;
        } else {
            if (Ext.isArray(headerCtCfg)) {
                headerCtCfg = {
                    items: headerCtCfg,
                    border: border
                };
            }
            Ext.apply(headerCtCfg, {
                forceFit: me.forceFit,
                sortable: me.sortableColumns,
                enableColumnMove: me.enableColumnMove,
                enableColumnResize: me.enableColumnResize,
                enableColumnHide: me.enableColumnHide,
                border:  border,
                sealed: me.sealedColumns
            });
            me.columns = headerCtCfg.items;

             
             
             if (me.enableLocking || Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
                 me.self.mixin('lockable', Ext.grid.Lockable);
                 me.injectLockable();
             }
        }

        me.scrollTask = new Ext.util.DelayedTask(me.syncHorizontalScroll, me);

        me.addEvents(
            
            'reconfigure',
            
            'viewready'
        );

        me.bodyCls = me.bodyCls || '';
        me.bodyCls += (' ' + me.extraBodyCls);
        
        me.cls = me.cls || '';
        me.cls += (' ' + me.extraBaseCls);

        
        delete me.autoScroll;

        
        
        if (!me.hasView) {

            
            
            if (!me.headerCt) {
                me.headerCt = new Ext.grid.header.Container(headerCtCfg);
            }

            
            me.columns = me.headerCt.items.items;

            
            if (me.store.buffered && !me.store.remoteSort) {
                for (i = 0, len = me.columns.length; i < len; i++) {
                    me.columns[i].sortable = false;
                }
            }

            if (me.hideHeaders) {
                me.headerCt.height = 0;
                me.headerCt.addCls(Ext.baseCSSPrefix + 'grid-header-ct-hidden');
                me.addCls(Ext.baseCSSPrefix + 'grid-header-hidden');
                
                
                if (Ext.isIEQuirks) {
                    me.headerCt.style = {
                        display: 'none'
                    };
                }
            }

            
            if (scroll === true || scroll === 'both') {
                vertical = horizontal = true;
            } else if (scroll === 'horizontal') {
                horizontal = true;
            } else if (scroll === 'vertical') {
                vertical = true;
            }

            me.relayHeaderCtEvents(me.headerCt);
            me.features = me.features || [];
            if (!Ext.isArray(me.features)) {
                me.features = [me.features];
            }
            me.dockedItems = [].concat(me.dockedItems || []);
            me.dockedItems.unshift(me.headerCt);
            me.viewConfig = me.viewConfig || {};

            
            if (me.store && me.store.buffered) {
                me.viewConfig.preserveScrollOnRefresh = true;
            } else if (me.invalidateScrollerOnRefresh !== undefined) {
                me.viewConfig.preserveScrollOnRefresh = !me.invalidateScrollerOnRefresh;
            }

            
            
            view = me.getView();

            me.items = [view];
            me.hasView = true;

            if (vertical) {
                
                
                if (me.store.buffered) {
                    me.verticalScroller = new Ext.grid.PagingScroller(Ext.apply({
                        panel: me,
                        store: me.store,
                        view: me.view
                    }, me.verticalScroller));
                }
            }

            if (horizontal) {
                
                
                if (!me.hideHeaders) {
                    view.on({
                        scroll: {
                            fn: me.onHorizontalScroll,
                            element: 'el',
                            scope: me
                        }
                    });
                }
            }

            me.mon(view.store, {
                load: me.onStoreLoad,
                scope: me
            });
            me.mon(view, {
                viewready: me.onViewReady,
                refresh: me.onRestoreHorzScroll,
                scope: me
            });
        }

        
        this.relayEvents(me.view, [
            
            'beforeitemmousedown',
            
            'beforeitemmouseup',
            
            'beforeitemmouseenter',
            
            'beforeitemmouseleave',
            
            'beforeitemclick',
            
            'beforeitemdblclick',
            
            'beforeitemcontextmenu',
            
            'itemmousedown',
            
            'itemmouseup',
            
            'itemmouseenter',
            
            'itemmouseleave',
            
            'itemclick',
            
            'itemdblclick',
            
            'itemcontextmenu',
            
            'beforecontainermousedown',
            
            'beforecontainermouseup',
            
            'beforecontainermouseover',
            
            'beforecontainermouseout',
            
            'beforecontainerclick',
            
            'beforecontainerdblclick',
            
            'beforecontainercontextmenu',
            
            'containermouseup',
            
            'containermouseover',
            
            'containermouseout',
            
            'containerclick',
            
            'containerdblclick',
            
            'containercontextmenu',
            
            'selectionchange',
            
            'beforeselect',
            
            'select',
            
            'beforedeselect',
            
            'deselect'
        ]);

        me.callParent(arguments);
        me.addStateEvents(['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange']);

        if (me.headerCt) {
            me.headerCt.on('afterlayout', me.onRestoreHorzScroll, me);
        }
    },

    relayHeaderCtEvents: function (headerCt) {
        this.relayEvents(headerCt, [
            
            'columnresize',
            
            'columnmove',
            
            'columnhide',
            
            'columnshow',
            
            'sortchange'
        ]);
    },

    getState: function(){
        var me = this,
            state = me.callParent(),
            sorter = me.store.sorters.first();

        state = me.addPropertyToState(state, 'columns', (me.headerCt || me).getColumnsState());

        if (sorter) {
            state = me.addPropertyToState(state, 'sort', {
                property: sorter.property,
                direction: sorter.direction,
                root: sorter.root
            });
        }
        return state;
    },

    applyState: function(state) {
        var me = this,
            sorter = state.sort,
            store = me.store,
            columns = state.columns;

        delete state.columns;

        
        
        me.callParent(arguments);

        if (columns) {
            (me.headerCt || me).applyColumnsState(columns);
        }

        if (sorter) {
            if (store.remoteSort) {
                
                store.sort({
                    property: sorter.property,
                    direction: sorter.direction,
                    root: sorter.root
                }, null, false);
            } else {
                store.sort(sorter.property, sorter.direction);
            }
        }
    },

    
    getStore: function(){
        return this.store;
    },

    
    getView: function() {
        var me = this,
            sm;

        if (!me.view) {
            sm = me.getSelectionModel();
            me.view = Ext.widget(Ext.apply({}, me.viewConfig, {

                
                grid: me,
                deferInitialRefresh: me.deferRowRender !== false,
                scroll: me.scroll,
                xtype: me.viewType,
                store: me.store,
                headerCt: me.headerCt,
                selModel: sm,
                features: me.features,
                panel: me,
                emptyText : me.emptyText ? '<div class="' + Ext.baseCSSPrefix + 'grid-empty">' + me.emptyText + '</div>' : ''
            }));

            
            me.view.getComponentLayout().headerCt = me.headerCt;

            me.mon(me.view, {
                uievent: me.processEvent,
                scope: me
            });
            sm.view = me.view;
            me.headerCt.view = me.view;
            me.relayEvents(me.view, [
                
                'cellclick',
                
                'celldblclick'
            ]);
        }
        return me.view;
    },

    
    setAutoScroll: Ext.emptyFn,

    
    processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
        var me = this,
            header;

        if (cellIndex !== -1) {
            header = me.headerCt.getGridColumns()[cellIndex];
            return header.processEvent.apply(header, arguments);
        }
    },

    
    determineScrollbars: function () {
    },

    
    invalidateScroller: function () {
    },

    scrollByDeltaY: function(yDelta, animate) {
        this.getView().scrollBy(0, yDelta, animate);
    },

    scrollByDeltaX: function(xDelta, animate) {
        this.getView().scrollBy(xDelta, 0, animate);
    },

    afterCollapse: function() {
        var me = this;
        me.saveScrollPos();
        me.saveScrollPos();
        me.callParent(arguments);
    },

    afterExpand: function() {
        var me = this;
        me.callParent(arguments);
        me.restoreScrollPos();
        me.restoreScrollPos();
    },

    saveScrollPos: Ext.emptyFn,

    restoreScrollPos: Ext.emptyFn,
    
    onHeaderResize: function(){
        this.delayScroll();
    },

    
    onHeaderMove: function(headerCt, header, colsToMove, fromIdx, toIdx) {
        var me = this;

        
        
        if (me.optimizedColumnMove === false) {
            me.view.refresh();
        }

        
        else {
            me.view.moveColumn(fromIdx, toIdx, colsToMove);
        }
        me.delayScroll();
    },

    
    onHeaderHide: function(headerCt, header) {
        this.delayScroll();
    },

    onHeaderShow: function(headerCt, header) {
        this.delayScroll();
    },
    
    delayScroll: function(){
        var target = this.getScrollTarget().el;
        if (target) {
            this.scrollTask.delay(10, null, null, [target.dom.scrollLeft]);
        }
    },

    
    onViewReady: function() {
         this.fireEvent('viewready', this);   
    },

    
    onRestoreHorzScroll: function() {
        var left = this.scrollLeftPos;
        if (left) {
            
            this.syncHorizontalScroll(left, true);
        }
    },

    getScrollerOwner: function() {
        var rootCmp = this;
        if (!this.scrollerOwner) {
            rootCmp = this.up('[scrollerOwner]');
        }
        return rootCmp;
    },

    
    getLhsMarker: function() {
        var me = this;
        return me.lhsMarker || (me.lhsMarker = Ext.DomHelper.append(me.el, {
            cls: Ext.baseCSSPrefix + 'grid-resize-marker'
        }, true));
    },

    
    getRhsMarker: function() {
        var me = this;

        return me.rhsMarker || (me.rhsMarker = Ext.DomHelper.append(me.el, {
            cls: Ext.baseCSSPrefix + 'grid-resize-marker'
        }, true));
    },

    
    getSelectionModel: function(){
        if (!this.selModel) {
            this.selModel = {};
        }

        var mode = 'SINGLE',
            type;
        if (this.simpleSelect) {
            mode = 'SIMPLE';
        } else if (this.multiSelect) {
            mode = 'MULTI';
        }

        Ext.applyIf(this.selModel, {
            allowDeselect: this.allowDeselect,
            mode: mode
        });

        if (!this.selModel.events) {
            type = this.selModel.selType || this.selType;
            this.selModel = Ext.create('selection.' + type, this.selModel);
        }

        if (!this.selModel.hasRelaySetup) {
            this.relayEvents(this.selModel, [
                'selectionchange', 'beforeselect', 'beforedeselect', 'select', 'deselect'
            ]);
            this.selModel.hasRelaySetup = true;
        }

        
        
        if (this.disableSelection) {
            this.selModel.locked = true;
        }
        return this.selModel;
    },
    
    getScrollTarget: function(){
        var owner = this.getScrollerOwner(),
            items = owner.query('tableview');
            
        return items[1] || items[0];
    },

    onHorizontalScroll: function(event, target) {
        this.syncHorizontalScroll(target.scrollLeft);
    },
    
    syncHorizontalScroll: function(left, setBody) {
        var me = this,
            scrollTarget;
            
        setBody = setBody === true;
        
        
        if (me.rendered && (setBody || left !== me.scrollLeftPos)) {
            
            
            if (setBody) {   
                scrollTarget = me.getScrollTarget();
                scrollTarget.el.dom.scrollLeft = left;
            }
            me.headerCt.el.dom.scrollLeft = left;
            me.scrollLeftPos = left;
        }
    },

    
    onStoreLoad: Ext.emptyFn,

    getEditorParent: function() {
        return this.body;
    },

    bindStore: function(store) {
        var me = this;
        me.store = store;
        me.getView().bindStore(store);
    },
    
    beforeDestroy: function(){
        Ext.destroy(this.verticalScroller);
        this.callParent();    
    },

    
    reconfigure: function(store, columns) {
        var me = this,
            headerCt = me.headerCt;

        if (me.lockable) {
            me.reconfigureLockable(store, columns);
        } else {
            Ext.suspendLayouts();
            if (columns) {
                
                delete me.scrollLeftPos;
                headerCt.removeAll();
                headerCt.add(columns);
            }
            if (store) {
                store = Ext.StoreManager.lookup(store);
                me.bindStore(store);
            } else {
                me.getView().refresh();
            }
            headerCt.setSortState();
            Ext.resumeLayouts(true);
        }
        me.fireEvent('reconfigure', me, store, columns);
    }
});


Ext.define('Ext.tab.Panel', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.tabpanel',
    alternateClassName: ['Ext.TabPanel'],

    requires: ['Ext.layout.container.Card', 'Ext.tab.Bar'],

    
    tabPosition : 'top',

    

    

    

    

    
    removePanelHeader: true,

    
    plain: false,

    
    itemCls: Ext.baseCSSPrefix + 'tabpanel-child',

    
    minTabWidth: undefined,

    
    maxTabWidth: undefined,

    
    deferredRender : true,

    
    initComponent: function() {
        var me = this,
            dockedItems = [].concat(me.dockedItems || []),
            activeTab = me.activeTab || (me.activeTab = 0);

        
        me.layout = new Ext.layout.container.Card(Ext.apply({
            owner: me,
            deferredRender: me.deferredRender,
            itemCls: me.itemCls,
            activeItem: me.activeTab
        }, me.layout));

        
        me.tabBar = new Ext.tab.Bar(Ext.apply({
            dock: me.tabPosition,
            plain: me.plain,
            border: me.border,
            cardLayout: me.layout,
            tabPanel: me
        }, me.tabBar));

        dockedItems.push(me.tabBar);
        me.dockedItems = dockedItems;

        me.addEvents(
            
            'beforetabchange',

            
            'tabchange'
        );

        me.callParent(arguments);

        
        me.activeTab = me.getComponent(activeTab);

        
        if (me.activeTab) {
            me.activeTab.tab.activate(true);

            
            me.tabBar.activeTab = me.activeTab.tab;
        }
    },

    
    setActiveTab: function(card) {
        var me = this,
            previous;

        card = me.getComponent(card);
        if (card) {
            previous = me.getActiveTab();

            if (previous !== card && me.fireEvent('beforetabchange', me, card, previous) === false) {
                return false;
            }

            
            
            if (!card.isComponent) {
                Ext.suspendLayouts();
                card = me.add(card);
                Ext.resumeLayouts();
            }

            
            
            me.activeTab = card;

            
            
            
            Ext.suspendLayouts();
            me.layout.setActiveItem(card);

            
            card = me.activeTab = me.layout.getActiveItem();

            
            if (card && card !== previous) {

                
                me.tabBar.setActiveTab(card.tab);
                Ext.resumeLayouts(true);

                
                if (previous !== card) {
                    me.fireEvent('tabchange', me, card, previous);
                }
            }
            
            else {
                Ext.resumeLayouts(true);
            }
            return card;
        }
    },

    
    getActiveTab: function() {
        var me = this,
            
            result = me.getComponent(me.activeTab);

        
        if (result && me.items.indexOf(result) != -1) {
            me.activeTab = result;
        } else {
            me.activeTab = null;
        }

        return me.activeTab;
    },

    
    getTabBar: function() {
        return this.tabBar;
    },

    
    onAdd: function(item, index) {
        var me = this,
            cfg = item.tabConfig || {},
            defaultConfig = {
                xtype: 'tab',
                card: item,
                disabled: item.disabled,
                closable: item.closable,
                hidden: item.hidden && !item.hiddenByLayout, 
                tooltip: item.tooltip,
                tabBar: me.tabBar,
                closeText: item.closeText
            };

        cfg = Ext.applyIf(cfg, defaultConfig);

        
        item.tab = me.tabBar.insert(index, cfg);

        item.on({
            scope : me,
            enable: me.onItemEnable,
            disable: me.onItemDisable,
            beforeshow: me.onItemBeforeShow,
            iconchange: me.onItemIconChange,
            iconclschange: me.onItemIconClsChange,
            titlechange: me.onItemTitleChange
        });

        if (item.isPanel) {
            if (me.removePanelHeader) {
                if (item.rendered) {
                    if (item.header) {
                        item.header.hide();
                    }
                } else {
                    item.header = false;
                }
            }
            if (item.isPanel && me.border) {
                item.setBorder(false);
            }
        }
    },

    
    onItemEnable: function(item){
        item.tab.enable();
    },

    
    onItemDisable: function(item){
        item.tab.disable();
    },

    
    onItemBeforeShow: function(item) {
        if (item !== this.activeTab) {
            this.setActiveTab(item);
            return false;
        }
    },

    
    onItemIconChange: function(item, newIcon) {
        item.tab.setIcon(newIcon);
    },
    
    
    onItemIconClsChange: function(item, newIconCls) {
        item.tab.setIconCls(newIconCls);
    },

    
    onItemTitleChange: function(item, newTitle) {
        item.tab.setText(newTitle);
    },

    
    doRemove: function(item, autoDestroy) {
        var me = this,
            toActivate;

        
        if (me.destroying || me.items.getCount() == 1) {
            me.activeTab = null;
        }

        
        
        else if ((toActivate = me.tabBar.items.indexOf(me.tabBar.findNextActivatable(item.tab))) !== -1) {
             me.setActiveTab(toActivate);
        }
        this.callParent(arguments);

        
        delete item.tab.card;
        delete item.tab;
    },

    
    onRemove: function(item, destroying) {
        var me = this;

        item.un({
            scope : me,
            enable: me.onItemEnable,
            disable: me.onItemDisable,
            beforeshow: me.onItemBeforeShow
        });
        if (!me.destroying && item.tab.ownerCt === me.tabBar) {
            me.tabBar.remove(item.tab);
        }
    }
});


Ext.define('Ext.tip.Tip', {
    extend: 'Ext.panel.Panel',

    alternateClassName: 'Ext.Tip',

    
    
    
    minWidth : 40,
    
    maxWidth : 300,
    
    shadow : "sides",

    
    defaultAlign : "tl-bl?",
    
    constrainPosition : true,

    
    autoRender: true,
    hidden: true,
    baseCls: Ext.baseCSSPrefix + 'tip',
    floating: {
        shadow: true,
        shim: true,
        constrain: true
    },
    focusOnToFront: false,

    
    closeAction: 'hide',

    ariaRole: 'tooltip',

    
    alwaysFramed: true,

    frameHeader: false,

    initComponent: function() {
        var me = this;

        me.floating = Ext.apply({}, {shadow: me.shadow}, me.self.prototype.floating);
        me.callParent(arguments);

        
        me.constrain = me.constrain || me.constrainPosition;
    },

    
    showAt : function(xy){
        var me = this;
        this.callParent(arguments);
        
        if (me.isVisible()) {
            me.setPagePosition(xy[0], xy[1]);
            if (me.constrainPosition || me.constrain) {
                me.doConstrain();
            }
            me.toFront(true);
        }
    },

    
    showBy : function(el, pos) {
        this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign));
    },

    
    initDraggable : function(){
        var me = this;
        me.draggable = {
            el: me.getDragEl(),
            delegate: me.header.el,
            constrain: me,
            constrainTo: me.el.getScopeParent()
        };
        
        Ext.Component.prototype.initDraggable.call(me);
    },

    
    ghost: undefined,
    unghost: undefined
});


Ext.define('Ext.slider.Tip', {
    extend: 'Ext.tip.Tip',
    minWidth: 10,
    alias: 'widget.slidertip',
    
    
    offsets : null,
    
    
    align: null,
    
    
    position: '',
    
    defaultVerticalPosition: 'left',
    
    defaultHorizontalPosition: 'top',

    isSliderTip: true,

    init: function(slider) {
        var me = this,
            align,
            offsets;
        
        if (!me.position) {
            me.position = slider.vertical ? me.defaultVerticalPosition : me.defaultHorizontalPosition;
        }
            
        switch (me.position) {
            case 'top':
                offsets = [0, -10];
                align = 'b-t?';
                break;
            case 'bottom':
                offsets = [0, 10];
                align = 't-b?';
                break;
            case 'left':
                offsets = [-10, 0];
                align = 'r-l?';
                break;
            case 'right':
                offsets = [10, 0];
                align = 'l-r?';
        }
        
        if (!me.align) {
            me.align = align;
        }
        
        if (!me.offsets) {
            me.offsets = offsets;
        }

        slider.on({
            scope    : me,
            dragstart: me.onSlide,
            drag     : me.onSlide,
            dragend  : me.hide,
            destroy  : me.destroy
        });
    },
    
    onSlide : function(slider, e, thumb) {
        var me = this;
        me.show();
        me.update(me.getText(thumb));
        me.el.alignTo(thumb.el, me.align, me.offsets);
    },

    
    getText : function(thumb) {
        return String(thumb.value);
    }
});

Ext.define('Ext.slider.Multi', {
    extend: 'Ext.form.field.Base',
    alias: 'widget.multislider',
    alternateClassName: 'Ext.slider.MultiSlider',

    requires: [
        'Ext.slider.Thumb',
        'Ext.slider.Tip',
        'Ext.Number',
        'Ext.util.Format',
        'Ext.Template',
        'Ext.layout.component.field.Slider'
    ],

    childEls: [
        'endEl', 'innerEl'
    ],

    
    fieldSubTpl: [
        '<div id="{id}" class="' + Ext.baseCSSPrefix + 'slider {fieldCls} {vertical}" aria-valuemin="{minValue}" aria-valuemax="{maxValue}" aria-valuenow="{value}" aria-valuetext="{value}">',
            '<div id="{cmpId}-endEl" class="' + Ext.baseCSSPrefix + 'slider-end" role="presentation">',
                '<div id="{cmpId}-innerEl" class="' + Ext.baseCSSPrefix + 'slider-inner" role="presentation">',
                    '{%this.renderThumbs(out, values)%}',
                '</div>',
            '</div>',
        '</div>',
        {
            renderThumbs: function(out, values) {
                var me = values.$comp,
                    i = 0,
                    thumbs = me.thumbs,
                    len = thumbs.length,
                    thumb,
                    thumbConfig;

                for (; i < len; i++) {
                    thumb = thumbs[i];
                    thumbConfig = thumb.getElConfig();
                    thumbConfig.id = me.id + '-thumb-' + i;
                    Ext.DomHelper.generateMarkup(thumbConfig, out);
                }
            },
            disableFormats: true
        }
    ],

    

    

    
    vertical: false,

    
    minValue: 0,

    
    maxValue: 100,

    
    decimalPrecision: 0,

    
    keyIncrement: 1,

    
    increment: 0,

    

    
    clickRange: [5,15],

    
    clickToChange : true,

    
    animate: true,

    
    dragging: false,

    
    constrainThumbs: true,

    componentLayout: 'sliderfield',

    
    useTips : true,

    
    tipText : null,

    ariaRole: 'slider',

    
    initValue: function() {
        var me = this,
            extValue = Ext.value,
            
            values = extValue(me.values, [extValue(me.value, extValue(me.minValue, 0))]),
            i = 0,
            len = values.length;

        
        me.originalValue = values;

        
        for (; i < len; i++) {
            me.addThumb(values[i]);
        }
    },

    
    initComponent : function() {
        var me = this,
            tipPlug,
            hasTip,
            p, pLen, plugins;

        
        me.thumbs = [];

        me.keyIncrement = Math.max(me.increment, me.keyIncrement);

        me.addEvents(
            
            'beforechange',

            
            'change',

            
            'changecomplete',

            
            'dragstart',

            
            'drag',

            
            'dragend'
        );

        
        if (me.increment) {
            me.maxValue = Ext.Number.snapInRange(me.maxValue, me.increment, me.minValue);
            me.value = me.normalizeValue(me.value);
        }

        me.callParent();

        
        if (me.useTips) {
            if (Ext.isObject(me.useTips)) {
                tipPlug = Ext.apply({}, me.useTips);
            } else {
                tipPlug = me.tipText ? {getText: me.tipText} : {};    
            }

            plugins = me.plugins = me.plugins || [];
            pLen    = plugins.length;
            
            for (p = 0; p < pLen; p++) {
                if (plugins[p].isSliderTip) {
                    hasTip = true;
                    break;
                }
            }

            if (!hasTip) {
                me.plugins.push(new Ext.slider.Tip(tipPlug));
            }
        }
    },

    
    addThumb: function(value) {
        var me = this,
            thumb = new Ext.slider.Thumb({
                ownerCt     : me,
                ownerLayout : me.getComponentLayout(),
                value       : value,
                slider      : me,
                index       : me.thumbs.length,
                constrain   : me.constrainThumbs,
                disabled    : !!me.readOnly
            });

        me.thumbs.push(thumb);

        
        if (me.rendered) {
            thumb.render();
        }

        return thumb;
    },

    
    promoteThumb: function(topThumb) {
        var thumbs = this.thumbs,
            ln = thumbs.length,
            zIndex, thumb, i;

        for (i = 0; i < ln; i++) {
            thumb = thumbs[i];

            if (thumb == topThumb) {
                thumb.bringToFront();
            } else {
                thumb.sendToBack();
            }
        }
    },

    
    getSubTplData : function() {
        var me = this;

        return Ext.apply(me.callParent(), {
            $comp: me,
            vertical: me.vertical ? Ext.baseCSSPrefix + 'slider-vert' : Ext.baseCSSPrefix + 'slider-horz',
            minValue: me.minValue,
            maxValue: me.maxValue,
            value: me.value
        });
    },

    onRender : function() {
        var me = this,
            thumbs = me.thumbs,
            len = thumbs.length,
            i = 0,
            thumb;

        me.callParent(arguments);

        for (i = 0; i < len; i++) {
            thumb = thumbs[i];
            thumb.el = me.el.getById(me.id + '-thumb-' + i);
            thumb.onRender();
        }
    },

    
    initEvents : function() {
        var me = this;
        me.mon(me.el, {
            scope    : me,
            mousedown: me.onMouseDown,
            keydown  : me.onKeyDown
        });
    },

    
    getTrackpoint : function(xy) {
        var me = this,
            result,
            positionProperty,
            sliderTrack = me.innerEl,
            trackLength;

        if (me.vertical) {
            positionProperty = 'top';
            trackLength = sliderTrack.getHeight();
        } else {
            positionProperty = 'left';
            trackLength = sliderTrack.getWidth();
        }
        result = Ext.Number.constrain(sliderTrack.translatePoints(xy)[positionProperty], 0, trackLength);
        return me.vertical ? trackLength - result : result;
    },

    
    onMouseDown : function(e) {
        var me = this,
            thumbClicked = false,
            i = 0,
            thumbs = me.thumbs,
            len = thumbs.length,
            trackPoint;

        if (me.disabled) {
            return;
        }

        
        for (; i < len; i++) {
            thumbClicked = thumbClicked || e.target == thumbs[i].el.dom;
        }

        if (me.clickToChange && !thumbClicked) {
            trackPoint = me.getTrackpoint(e.getXY());
            if (trackPoint !== undefined) {
                me.onClickChange(trackPoint);
            }
        }
        me.focus();
    },

    
    onClickChange : function(trackPoint) {
        var me = this,
            thumb, index;

        
        

        
        thumb = me.getNearest(trackPoint);
        if (!thumb.disabled) {
            index = thumb.index;
            me.setValue(index, Ext.util.Format.round(me.reversePixelValue(trackPoint), me.decimalPrecision), undefined, true);
        }
    },

    
    getNearest: function(trackPoint) {
        var me = this,
            clickValue = me.reversePixelValue(trackPoint),
            nearestDistance = (me.maxValue - me.minValue) + 5, 
            nearest = null,
            thumbs = me.thumbs,
            i = 0,
            len = thumbs.length,
            thumb,
            value,
            dist;

        for (; i < len; i++) {
            thumb = me.thumbs[i];
            value = thumb.value;
            dist  = Math.abs(value - clickValue);

            if (Math.abs(dist <= nearestDistance)) {
                nearest = thumb;
                nearestDistance = dist;
            }
        }
        return nearest;
    },

    
    onKeyDown : function(e) {
        
        var me = this,
            k,
            val;

        if(me.disabled || me.thumbs.length !== 1) {
            e.preventDefault();
            return;
        }
        k = e.getKey();

        switch(k) {
            case e.UP:
            case e.RIGHT:
                e.stopEvent();
                val = e.ctrlKey ? me.maxValue : me.getValue(0) + me.keyIncrement;
                me.setValue(0, val, undefined, true);
            break;
            case e.DOWN:
            case e.LEFT:
                e.stopEvent();
                val = e.ctrlKey ? me.minValue : me.getValue(0) - me.keyIncrement;
                me.setValue(0, val, undefined, true);
            break;
            default:
                e.preventDefault();
        }
    },

    
    normalizeValue : function(v) {
        var me = this,
            Num = Ext.Number,
            snapFn = Num[me.zeroBasedSnapping ? 'snap' : 'snapInRange'];

        v = snapFn.call(Num, v, me.increment, me.minValue, me.maxValue);
        v = Ext.util.Format.round(v, me.decimalPrecision);
        v = Ext.Number.constrain(v, me.minValue, me.maxValue);
        return v;
    },

    
    setMinValue : function(val) {
        var me = this,
            i = 0,
            thumbs = me.thumbs,
            len = thumbs.length,
            t;

        me.minValue = val;
        if (me.rendered) {
            me.inputEl.dom.setAttribute('aria-valuemin', val);
        }

        for (; i < len; ++i) {
            t = thumbs[i];
            t.value = t.value < val ? val : t.value;
        }
        me.syncThumbs();
    },

    
    setMaxValue : function(val) {
        var me = this,
            i = 0,
            thumbs = me.thumbs,
            len = thumbs.length,
            t;

        me.maxValue = val;
        if (me.rendered) {
            me.inputEl.dom.setAttribute('aria-valuemax', val);
        }

        for (; i < len; ++i) {
            t = thumbs[i];
            t.value = t.value > val ? val : t.value;
        }
        me.syncThumbs();
    },

    
    setValue : function(index, value, animate, changeComplete) {
        var me = this,
            thumb = me.thumbs[index];

        
        value = me.normalizeValue(value);

        if (value !== thumb.value && me.fireEvent('beforechange', me, value, thumb.value, thumb) !== false) {
            thumb.value = value;
            if (me.rendered) {
                
                
                me.inputEl.set({
                    'aria-valuenow': value,
                    'aria-valuetext': value
                });

                thumb.move(me.calculateThumbPosition(value), Ext.isDefined(animate) ? animate !== false : me.animate);

                me.fireEvent('change', me, value, thumb);
                me.checkDirty();
                if (changeComplete) {
                    me.fireEvent('changecomplete', me, value, thumb);
                }
            }
        }
    },

    
    calculateThumbPosition : function(v) {
        return (v - this.minValue) / (this.maxValue - this.minValue) * 100;
    },

    
    getRatio : function() {
        var me = this,
            trackLength = this.vertical ? this.innerEl.getHeight() : this.innerEl.getWidth(),
            valueRange = this.maxValue - this.minValue;
        return valueRange === 0 ? trackLength : (trackLength / valueRange);
    },

    
    reversePixelValue : function(pos) {
        return this.minValue + (pos / this.getRatio());
    },

    
    reversePercentageValue : function(pos) {
        return this.minValue + (this.maxValue - this.minValue) * (pos / 100);
    },

    
    onDisable: function() {
        var me = this,
            i = 0,
            thumbs = me.thumbs,
            len = thumbs.length,
            thumb,
            el,
            xy;

        me.callParent();

        for (; i < len; i++) {
            thumb = thumbs[i];
            el = thumb.el;

            thumb.disable();

            if(Ext.isIE) {
                
                
                xy = el.getXY();
                el.hide();

                me.innerEl.addCls(me.disabledCls).dom.disabled = true;

                if (!me.thumbHolder) {
                    me.thumbHolder = me.endEl.createChild({cls: Ext.baseCSSPrefix + 'slider-thumb ' + me.disabledCls});
                }

                me.thumbHolder.show().setXY(xy);
            }
        }
    },

    
    onEnable: function() {
        var me = this,
            i = 0,
            thumbs = me.thumbs,
            len = thumbs.length,
            thumb,
            el;

        this.callParent();

        for (; i < len; i++) {
            thumb = thumbs[i];
            el = thumb.el;

            thumb.enable();

            if (Ext.isIE) {
                me.innerEl.removeCls(me.disabledCls).dom.disabled = false;

                if (me.thumbHolder) {
                    me.thumbHolder.hide();
                }

                el.show();
                me.syncThumbs();
            }
        }
    },

    
    syncThumbs : function() {
        if (this.rendered) {
            var thumbs = this.thumbs,
                length = thumbs.length,
                i = 0;

            for (; i < length; i++) {
                thumbs[i].move(this.calculateThumbPosition(thumbs[i].value));
            }
        }
    },

    
    getValue : function(index) {
        return Ext.isNumber(index) ? this.thumbs[index].value : this.getValues();
    },

    
    getValues: function() {
        var values = [],
            i = 0,
            thumbs = this.thumbs,
            len = thumbs.length;

        for (; i < len; i++) {
            values.push(thumbs[i].value);
        }

        return values;
    },

    getSubmitValue: function() {
        var me = this;
        return (me.disabled || !me.submitValue) ? null : me.getValue();
    },

    reset: function() {
        var me = this,
            arr = [].concat(me.originalValue),
            a     = 0,
            aLen  = arr.length,
            val;

        for (; a < aLen; a++) {
            val = arr[a];

            me.setValue(a, val);
        }

        me.clearInvalid();
        
        delete me.wasValid;
    },
    
    setReadOnly: function(readOnly){
        var me = this,
            thumbs = me.thumbs,
            len = thumbs.length,
            i = 0;
            
        me.callParent(arguments); 
        readOnly = me.readOnly;
        
        for (; i < len; ++i) {
            if (readOnly) {
                thumbs[i].disable();
            } else {
                thumbs[i].enable();
            }
            
        }
           
    },

    
    beforeDestroy : function() {
        var me     = this,
            thumbs = me.thumbs,
            t      = 0,
            tLen   = thumbs.length,
            thumb;

        Ext.destroy(me.innerEl, me.endEl, me.focusEl);

        for (; t < tLen; t++) {
            thumb = thumbs[t];

            Ext.destroy(thumb);
        }

        me.callParent();
    }
});


Ext.define('Ext.slider.Single', {
    extend: 'Ext.slider.Multi',
    alias: ['widget.slider', 'widget.sliderfield'],
    alternateClassName: ['Ext.Slider', 'Ext.form.SliderField', 'Ext.slider.SingleSlider', 'Ext.slider.Slider'],

    
    getValue: function() {
        
        return this.callParent([0]);
    },

    
    setValue: function(value, animate) {
        var args = arguments,
            len  = args.length;

        
        
        
        if (len == 1 || (len <= 3 && typeof args[1] != 'number')) {
            args = Ext.toArray(args);
            args.unshift(0);
        }
        return this.callParent(args);
    },

    
    getNearest : function(){
        
        return this.thumbs[0];
    }
});


Ext.define('Ext.tip.ToolTip', {
    extend: 'Ext.tip.Tip',
    alias: 'widget.tooltip',
    alternateClassName: 'Ext.ToolTip',
    
    
    
    autoHide: true,
    
    
    showDelay: 500,
    
    hideDelay: 200,
    
    dismissDelay: 5000,
    
    
    trackMouse: false,
    
    
    anchorToTarget: true,
    
    anchorOffset: 0,
    

    
    targetCounter: 0,
    quickShowInterval: 250,

    
    initComponent: function() {
        var me = this;
        me.callParent(arguments);
        me.lastActive = new Date();
        me.setTarget(me.target);
        me.origAnchor = me.anchor;
    },

    
    onRender: function(ct, position) {
        var me = this;
        me.callParent(arguments);
        me.anchorCls = Ext.baseCSSPrefix + 'tip-anchor-' + me.getAnchorPosition();
        me.anchorEl = me.el.createChild({
            cls: Ext.baseCSSPrefix + 'tip-anchor ' + me.anchorCls
        });
    },

    
    setTarget: function(target) {
        var me = this,
            t = Ext.get(target),
            tg;

        if (me.target) {
            tg = Ext.get(me.target);
            me.mun(tg, 'mouseover', me.onTargetOver, me);
            me.mun(tg, 'mouseout', me.onTargetOut, me);
            me.mun(tg, 'mousemove', me.onMouseMove, me);
        }

        me.target = t;
        if (t) {

            me.mon(t, {
                
                
                freezeEvent: true,

                mouseover: me.onTargetOver,
                mouseout: me.onTargetOut,
                mousemove: me.onMouseMove,
                scope: me
            });
        }
        if (me.anchor) {
            me.anchorTarget = me.target;
        }
    },

    
    onMouseMove: function(e) {
        var me = this,
            t = me.delegate ? e.getTarget(me.delegate) : me.triggerElement = true,
            xy;
        if (t) {
            me.targetXY = e.getXY();
            if (t === me.triggerElement) {
                if (!me.hidden && me.trackMouse) {
                    xy = me.getTargetXY();
                    if (me.constrainPosition) {
                        xy = me.el.adjustForConstraints(xy, me.el.getScopeParent());
                    }
                    me.setPagePosition(xy);
                }
            } else {
                me.hide();
                me.lastActive = new Date(0);
                me.onTargetOver(e);
            }
        } else if ((!me.closable && me.isVisible()) && me.autoHide !== false) {
            me.hide();
        }
    },

    
    getTargetXY: function() {
        var me = this,
            mouseOffset,
            offsets, xy, dw, dh, de, bd, scrollX, scrollY, axy, sz, constrainPosition;
        if (me.delegate) {
            me.anchorTarget = me.triggerElement;
        }
        if (me.anchor) {
            me.targetCounter++;
            offsets = me.getOffsets();
            xy = (me.anchorToTarget && !me.trackMouse) ? me.el.getAlignToXY(me.anchorTarget, me.getAnchorAlign()) : me.targetXY;
            dw = Ext.Element.getViewWidth() - 5;
            dh = Ext.Element.getViewHeight() - 5;
            de = document.documentElement;
            bd = document.body;
            scrollX = (de.scrollLeft || bd.scrollLeft || 0) + 5;
            scrollY = (de.scrollTop || bd.scrollTop || 0) + 5;
            axy = [xy[0] + offsets[0], xy[1] + offsets[1]];
            sz = me.getSize();
            constrainPosition = me.constrainPosition;

            me.anchorEl.removeCls(me.anchorCls);

            if (me.targetCounter < 2 && constrainPosition) {
                if (axy[0] < scrollX) {
                    if (me.anchorToTarget) {
                        me.defaultAlign = 'l-r';
                        if (me.mouseOffset) {
                            me.mouseOffset[0] *= -1;
                        }
                    }
                    me.anchor = 'left';
                    return me.getTargetXY();
                }
                if (axy[0] + sz.width > dw) {
                    if (me.anchorToTarget) {
                        me.defaultAlign = 'r-l';
                        if (me.mouseOffset) {
                            me.mouseOffset[0] *= -1;
                        }
                    }
                    me.anchor = 'right';
                    return me.getTargetXY();
                }
                if (axy[1] < scrollY) {
                    if (me.anchorToTarget) {
                        me.defaultAlign = 't-b';
                        if (me.mouseOffset) {
                            me.mouseOffset[1] *= -1;
                        }
                    }
                    me.anchor = 'top';
                    return me.getTargetXY();
                }
                if (axy[1] + sz.height > dh) {
                    if (me.anchorToTarget) {
                        me.defaultAlign = 'b-t';
                        if (me.mouseOffset) {
                            me.mouseOffset[1] *= -1;
                        }
                    }
                    me.anchor = 'bottom';
                    return me.getTargetXY();
                }
            }

            me.anchorCls = Ext.baseCSSPrefix + 'tip-anchor-' + me.getAnchorPosition();
            me.anchorEl.addCls(me.anchorCls);
            me.targetCounter = 0;
            return axy;
        } else {
            mouseOffset = me.getMouseOffset();
            return (me.targetXY) ? [me.targetXY[0] + mouseOffset[0], me.targetXY[1] + mouseOffset[1]] : mouseOffset;
        }
    },

    getMouseOffset: function() {
        var me = this,
        offset = me.anchor ? [0, 0] : [15, 18];
        if (me.mouseOffset) {
            offset[0] += me.mouseOffset[0];
            offset[1] += me.mouseOffset[1];
        }
        return offset;
    },

    
    getAnchorPosition: function() {
        var me = this,
            m;
        if (me.anchor) {
            me.tipAnchor = me.anchor.charAt(0);
        } else {
            m = me.defaultAlign.match(/^([a-z]+)-([a-z]+)(\?)?$/);
            me.tipAnchor = m[1].charAt(0);
        }

        switch (me.tipAnchor) {
        case 't':
            return 'top';
        case 'b':
            return 'bottom';
        case 'r':
            return 'right';
        }
        return 'left';
    },

    
    getAnchorAlign: function() {
        switch (this.anchor) {
        case 'top':
            return 'tl-bl';
        case 'left':
            return 'tl-tr';
        case 'right':
            return 'tr-tl';
        default:
            return 'bl-tl';
        }
    },

    
    getOffsets: function() {
        var me = this,
            mouseOffset,
            offsets,
            ap = me.getAnchorPosition().charAt(0);
        if (me.anchorToTarget && !me.trackMouse) {
            switch (ap) {
            case 't':
                offsets = [0, 9];
                break;
            case 'b':
                offsets = [0, -13];
                break;
            case 'r':
                offsets = [ - 13, 0];
                break;
            default:
                offsets = [9, 0];
                break;
            }
        } else {
            switch (ap) {
            case 't':
                offsets = [ - 15 - me.anchorOffset, 30];
                break;
            case 'b':
                offsets = [ - 19 - me.anchorOffset, -13 - me.el.dom.offsetHeight];
                break;
            case 'r':
                offsets = [ - 15 - me.el.dom.offsetWidth, -13 - me.anchorOffset];
                break;
            default:
                offsets = [25, -13 - me.anchorOffset];
                break;
            }
        }
        mouseOffset = me.getMouseOffset();
        offsets[0] += mouseOffset[0];
        offsets[1] += mouseOffset[1];

        return offsets;
    },

    
    onTargetOver: function(e) {
        var me = this,
            t;

        if (me.disabled || e.within(me.target.dom, true)) {
            return;
        }
        t = e.getTarget(me.delegate);
        if (t) {
            me.triggerElement = t;
            me.clearTimer('hide');
            me.targetXY = e.getXY();
            me.delayShow();
        }
    },

    
    delayShow: function() {
        var me = this;
        if (me.hidden && !me.showTimer) {
            if (Ext.Date.getElapsed(me.lastActive) < me.quickShowInterval) {
                me.show();
            } else {
                me.showTimer = Ext.defer(me.show, me.showDelay, me);
            }
        }
        else if (!me.hidden && me.autoHide !== false) {
            me.show();
        }
    },
    
    onShowVeto: function(){
        this.callParent();
        this.clearTimer('show');
    },

    
    onTargetOut: function(e) {
        var me = this;

        
        
        if (me.disabled || e.within(me.target.dom, true)) {
            return;
        }
        me.clearTimer('show');
        if (me.autoHide !== false) {
            me.delayHide();
        }
    },

    
    delayHide: function() {
        var me = this;
        if (!me.hidden && !me.hideTimer) {
            me.hideTimer = Ext.defer(me.hide, me.hideDelay, me);
        }
    },

    
    hide: function() {
        var me = this;
        me.clearTimer('dismiss');
        me.lastActive = new Date();
        if (me.anchorEl) {
            me.anchorEl.hide();
        }
        me.callParent(arguments);
        delete me.triggerElement;
    },

    
    show: function() {
        var me = this;

        
        
        this.callParent();
        if (this.hidden === false) {
            me.setPagePosition(-10000, -10000);

            if (me.anchor) {
                me.anchor = me.origAnchor;
            }
            
            if (!me.calledFromShowAt) {
                me.showAt(me.getTargetXY());
            }

            if (me.anchor) {
                me.syncAnchor();
                me.anchorEl.show();
            } else {
                me.anchorEl.hide();
            }
        }
    },

    
    showAt: function(xy) {
        var me = this;
        me.lastActive = new Date();
        me.clearTimers();
        me.calledFromShowAt = true;

        
        if (!me.isVisible()) {
            this.callParent(arguments);
        }

        
        if (me.isVisible()) {
            me.setPagePosition(xy[0], xy[1]);
            if (me.constrainPosition || me.constrain) {
                me.doConstrain();
            }
            me.toFront(true);
            me.el.sync(true);
            if (me.dismissDelay && me.autoHide !== false) {
                me.dismissTimer = Ext.defer(me.hide, me.dismissDelay, me);
            }
            if (me.anchor) {
                me.syncAnchor();
                if (!me.anchorEl.isVisible()) {
                    me.anchorEl.show();
                }
            } else {
                me.anchorEl.hide();
            }
        }
        delete me.calledFromShowAt;
    },

    
    syncAnchor: function() {
        var me = this,
            anchorPos,
            targetPos,
            offset;
        switch (me.tipAnchor.charAt(0)) {
        case 't':
            anchorPos = 'b';
            targetPos = 'tl';
            offset = [20 + me.anchorOffset, 1];
            break;
        case 'r':
            anchorPos = 'l';
            targetPos = 'tr';
            offset = [ - 1, 12 + me.anchorOffset];
            break;
        case 'b':
            anchorPos = 't';
            targetPos = 'bl';
            offset = [20 + me.anchorOffset, -1];
            break;
        default:
            anchorPos = 'r';
            targetPos = 'tl';
            offset = [1, 12 + me.anchorOffset];
            break;
        }
        me.anchorEl.alignTo(me.el, anchorPos + '-' + targetPos, offset);
        me.anchorEl.setStyle('z-index', parseInt(me.el.getZIndex(), 10) || 0 + 1).setVisibilityMode(Ext.Element.DISPLAY);
    },

    
    setPagePosition: function(x, y) {
        var me = this;
        me.callParent(arguments);
        if (me.anchor) {
            me.syncAnchor();
        }
    },

    
    clearTimer: function(name) {
        name = name + 'Timer';
        clearTimeout(this[name]);
        delete this[name];
    },

    
    clearTimers: function() {
        var me = this;
        me.clearTimer('show');
        me.clearTimer('dismiss');
        me.clearTimer('hide');
    },

    
    onShow: function() {
        var me = this;
        me.callParent();
        me.mon(Ext.getDoc(), 'mousedown', me.onDocMouseDown, me);
    },

    
    onHide: function() {
        var me = this;
        me.callParent();
        me.mun(Ext.getDoc(), 'mousedown', me.onDocMouseDown, me);
    },

    
    onDocMouseDown: function(e) {
        var me = this;
        if (!me.closable && !e.within(me.el.dom)) {
            me.disable();
            Ext.defer(me.doEnable, 100, me);
        }
    },

    
    doEnable: function() {
        if (!this.isDestroyed) {
            this.enable();
        }
    },

    
    onDisable: function() {
        this.callParent();
        this.clearTimers();
        this.hide();
    },

    beforeDestroy: function() {
        var me = this;
        me.clearTimers();
        Ext.destroy(me.anchorEl);
        delete me.anchorEl;
        delete me.target;
        delete me.anchorTarget;
        delete me.triggerElement;
        me.callParent();
    },

    
    onDestroy: function() {
        Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
        this.callParent();
    }
});


Ext.define('Ext.chart.Tip', {

    

    requires: ['Ext.tip.ToolTip', 'Ext.chart.TipSurface'],

    

    constructor: function(config) {
        var me = this,
            surface,
            sprites,
            tipSurface;
        if (config.tips) {
            me.tipTimeout = null;
            me.tipConfig = Ext.apply({}, config.tips, {
                renderer: Ext.emptyFn,
                constrainPosition: true,
                autoHide: true
            });
            me.tooltip = new Ext.tip.ToolTip(me.tipConfig);
            me.chart.surface.on('mousemove', me.tooltip.onMouseMove, me.tooltip);
            me.chart.surface.on('mouseleave', function() {
                me.hideTip();
            });
            if (me.tipConfig.surface) {
                
                surface = me.tipConfig.surface;
                sprites = surface.sprites;
                tipSurface = new Ext.chart.TipSurface({
                    id: 'tipSurfaceComponent',
                    sprites: sprites
                });
                if (surface.width && surface.height) {
                    tipSurface.setSize(surface.width, surface.height);
                }
                me.tooltip.add(tipSurface);
                me.spriteTip = tipSurface;
            }
        }
    },

    showTip: function(item) {
        var me = this,
            tooltip,
            spriteTip,
            tipConfig,
            trackMouse,
            sprite,
            surface,
            surfaceExt,
            pos,
            x,
            y;
        if (!me.tooltip) {
            return;
        }
        clearTimeout(me.tipTimeout);
        tooltip = me.tooltip;
        spriteTip = me.spriteTip;
        tipConfig = me.tipConfig;
        trackMouse = tooltip.trackMouse;
        if (!trackMouse) {
            tooltip.trackMouse = true;
            sprite = item.sprite;
            surface = sprite.surface;
            surfaceExt = Ext.get(surface.getId());
            if (surfaceExt) {
                pos = surfaceExt.getXY();
                x = pos[0] + (sprite.attr.x || 0) + (sprite.attr.translation && sprite.attr.translation.x || 0);
                y = pos[1] + (sprite.attr.y || 0) + (sprite.attr.translation && sprite.attr.translation.y || 0);
                tooltip.targetXY = [x, y];
            }
        }
        if (spriteTip) {
            tipConfig.renderer.call(tooltip, item.storeItem, item, spriteTip.surface);
        } else {
            tipConfig.renderer.call(tooltip, item.storeItem, item);
        }
        tooltip.show();
        tooltip.trackMouse = trackMouse;
    },

    hideTip: function(item) {
        var tooltip = this.tooltip;
        if (!tooltip) {
            return;
        }
        clearTimeout(this.tipTimeout);
        this.tipTimeout = setTimeout(function() {
            tooltip.hide();
        }, 0);
    }
});

Ext.define('Ext.chart.series.Series', {

    

    mixins: {
        observable: 'Ext.util.Observable',
        labels: 'Ext.chart.Label',
        highlights: 'Ext.chart.Highlight',
        tips: 'Ext.chart.Tip',
        callouts: 'Ext.chart.Callout'
    },

    

    

    

    
    type: null,

    
    title: null,

    
    showInLegend: true,

    
    renderer: function(sprite, record, attributes, index, store) {
        return attributes;
    },

    
    shadowAttributes: null,

    
    animating: false,

    

    constructor: function(config) {
        var me = this;
        if (config) {
            Ext.apply(me, config);
        }

        me.shadowGroups = [];

        me.mixins.labels.constructor.call(me, config);
        me.mixins.highlights.constructor.call(me, config);
        me.mixins.tips.constructor.call(me, config);
        me.mixins.callouts.constructor.call(me, config);

        me.addEvents({
            scope: me,
            itemmouseover: true,
            itemmouseout: true,
            itemmousedown: true,
            itemmouseup: true,
            mouseleave: true,
            afterdraw: true,

            
            titlechange: true
        });

        me.mixins.observable.constructor.call(me, config);

        me.on({
            scope: me,
            itemmouseover: me.onItemMouseOver,
            itemmouseout: me.onItemMouseOut,
            mouseleave: me.onMouseLeave
        });
        
        if (me.style) {
            Ext.apply(me.seriesStyle, me.style);
        }
    },
    
    
    eachRecord: function(fn, scope) {
        var chart = this.chart;
        (chart.substore || chart.store).each(fn, scope);
    },

    
    getRecordCount: function() {
        var chart = this.chart,
            store = chart.substore || chart.store;
        return store ? store.getCount() : 0;
    },

    
    isExcluded: function(index) {
        var excludes = this.__excludes;
        return !!(excludes && excludes[index]);
    },

    
    setBBox: function(noGutter) {
        var me = this,
            chart = me.chart,
            chartBBox = chart.chartBBox,
            gutterX = noGutter ? 0 : chart.maxGutter[0],
            gutterY = noGutter ? 0 : chart.maxGutter[1],
            clipBox, bbox;

        clipBox = {
            x: chartBBox.x,
            y: chartBBox.y,
            width: chartBBox.width,
            height: chartBBox.height
        };
        me.clipBox = clipBox;

        bbox = {
            x: (clipBox.x + gutterX) - (chart.zoom.x * chart.zoom.width),
            y: (clipBox.y + gutterY) - (chart.zoom.y * chart.zoom.height),
            width: (clipBox.width - (gutterX * 2)) * chart.zoom.width,
            height: (clipBox.height - (gutterY * 2)) * chart.zoom.height
        };
        me.bbox = bbox;
    },

    
    onAnimate: function(sprite, attr) {
        var me = this;
        sprite.stopAnimation();
        if (me.animating) {
            return sprite.animate(Ext.applyIf(attr, me.chart.animate));
        } else {
            me.animating = true;
            return sprite.animate(Ext.apply(Ext.applyIf(attr, me.chart.animate), {
                listeners: {
                    'afteranimate': function() {
                        me.animating = false;
                        me.fireEvent('afterrender');
                    }
                }
            }));
        }
    },

    
    getGutters: function() {
        return [0, 0];
    },

    
    onItemMouseOver: function(item) {
        var me = this;
        if (item.series === me) {
            if (me.highlight) {
                me.highlightItem(item);
            }
            if (me.tooltip) {
                me.showTip(item);
            }
        }
    },

    
    onItemMouseOut: function(item) {
        var me = this;
        if (item.series === me) {
            me.unHighlightItem();
            if (me.tooltip) {
                me.hideTip(item);
            }
        }
    },

    
    onMouseLeave: function() {
        var me = this;
        me.unHighlightItem();
        if (me.tooltip) {
            me.hideTip();
        }
    },

    
    getItemForPoint: function(x, y) {
        
        if (!this.items || !this.items.length || this.seriesIsHidden) {
            return null;
        }
        var me = this,
            items = me.items,
            bbox = me.bbox,
            item, i, ln;
        
        if (!Ext.draw.Draw.withinBox(x, y, bbox)) {
            return null;
        }
        for (i = 0, ln = items.length; i < ln; i++) {
            if (items[i] && this.isItemInPoint(x, y, items[i], i)) {
                return items[i];
            }
        }

        return null;
    },

    isItemInPoint: function(x, y, item, i) {
        return false;
    },

    
    hideAll: function() {
        var me = this,
            items = me.items,
            item, len, i, j, l, sprite, shadows;

        me.seriesIsHidden = true;
        me._prevShowMarkers = me.showMarkers;

        me.showMarkers = false;
        
        me.hideLabels(0);
        
        for (i = 0, len = items.length; i < len; i++) {
            item = items[i];
            sprite = item.sprite;
            if (sprite) {
                sprite.setAttributes({
                    hidden: true
                }, true);
            }

            if (sprite && sprite.shadows) {
                shadows = sprite.shadows;
                for (j = 0, l = shadows.length; j < l; ++j) {
                    shadows[j].setAttributes({
                        hidden: true
                    }, true);
                }
            }
        }
    },

    
    showAll: function() {
        var me = this,
            prevAnimate = me.chart.animate;
        me.chart.animate = false;
        me.seriesIsHidden = false;
        me.showMarkers = me._prevShowMarkers;
        me.drawSeries();
        me.chart.animate = prevAnimate;
    },
    
    hide: function() {
        if (this.items) {
            var me = this,
                items = me.items,
                i, j, lsh, ln, shadows;
            
            if (items && items.length) {
                for (i = 0, ln = items.length; i < ln; ++i) {
                    if (items[i].sprite) {
                        items[i].sprite.hide(true);

                        shadows = items[i].shadows || items[i].sprite.shadows;
                        if (shadows) {
                            for (j = 0, lsh = shadows.length; j < lsh; ++j) {
                                shadows[j].hide(true);
                            }
                        }
                    }
                }
                me.hideLabels();
            }
        }
    },

    
    getLegendColor: function(index) {
        var me = this, fill, stroke;
        if (me.seriesStyle) {
            fill = me.seriesStyle.fill;
            stroke = me.seriesStyle.stroke;
            if (fill && fill != 'none') {
                return fill;
            }
            if(stroke){
                return stroke;
            }
        }
        return (me.colorArrayStyle)?me.colorArrayStyle[me.seriesIdx % me.colorArrayStyle.length]:'#000';
    },

    
    visibleInLegend: function(index){
        var excludes = this.__excludes;
        if (excludes) {
            return !excludes[index];
        }
        return !this.seriesIsHidden;
    },

    
    setTitle: function(index, title) {
        var me = this,
            oldTitle = me.title;

        if (Ext.isString(index)) {
            title = index;
            index = 0;
        }

        if (Ext.isArray(oldTitle)) {
            oldTitle[index] = title;
        } else {
            me.title = title;
        }

        me.fireEvent('titlechange', title, index);
    }
});


Ext.define('Ext.chart.series.Cartesian', {

    

    extend: 'Ext.chart.series.Series',

    alternateClassName: ['Ext.chart.CartesianSeries', 'Ext.chart.CartesianChart'],

    

    
    xField: null,

    
    yField: null,

    
    axis: 'left',

    getLegendLabels: function() {
        var me = this,
            labels = [],
            fields, i, ln,
            combinations = me.combinations,
            title,
            combo, label0, label1;

        fields = [].concat(me.yField);
        for (i = 0, ln = fields.length; i < ln; i++) {
            title = me.title;
            
            labels.push((Ext.isArray(title) ? title[i] : title) || fields[i]);
        }

        
        
        if (combinations) {
            combinations = Ext.Array.from(combinations);
            for (i = 0, ln = combinations.length; i < ln; i++) {
                combo = combinations[i];
                label0 = labels[combo[0]];
                label1 = labels[combo[1]];
                labels[combo[1]] = label0 + ' & ' + label1;
                labels.splice(combo[0], 1);
            }
        }

        return labels;
    },

    
    eachYValue: function(record, fn, scope) {
        var me = this,
            yValueAccessors = me.getYValueAccessors(),
            i, ln, accessor;
        
        for (i = 0, ln = yValueAccessors.length; i < ln; i++) {
            accessor = yValueAccessors[i];
            fn.call(scope, accessor(record), i);
        }
    },

    
    getYValueCount: function() {
        return this.getYValueAccessors().length;
    },

    combine: function(index1, index2) {
        var me = this,
            accessors = me.getYValueAccessors(),
            accessor1 = accessors[index1],
            accessor2 = accessors[index2];

        
        accessors[index2] = function(record) {
            return accessor1(record) + accessor2(record);
        };
        accessors.splice(index1, 1);

        me.callParent([index1, index2]);
    },

    clearCombinations: function() {
        
        delete this.yValueAccessors;
        this.callParent();
    },

    
    getYValueAccessors: function() {
        var me = this,
            accessors = me.yValueAccessors,
            yFields, yField, i, ln;
        if (!accessors) {
            accessors = me.yValueAccessors = [];
            yFields = [].concat(me.yField);
            
            for (i = 0, ln = yFields.length; i < ln; i++) {
                yField = yFields[i];
                accessors.push(function(record) {
                    return record.get(yField);
                });
            }
        }
        return accessors;
    },

    
    getMinMaxXValues: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            data = store.data.items,
            i, ln, record,
            min, max,
            xField = me.xField,
            xValue;

        if (me.getRecordCount() > 0) {
            min = Infinity;
            max = -min;
                
            for (i = 0, ln = data.length; i < ln; i++) {
                record = data[i];
                xValue = record.get(xField);
                if (xValue > max) {
                    max = xValue;
                }
                if (xValue < min) {
                    min = xValue;
                }
            }
        } else {
            min = max = 0;
        }
        return [min, max];
    },

    
    getMinMaxYValues: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            data = store.data.items,
            i, ln, record,
            stacked = me.stacked,
            min, max,
            positiveTotal, negativeTotal;

        function eachYValueStacked(yValue, i) {
            if (!me.isExcluded(i)) {
                if (yValue < 0) {
                    negativeTotal += yValue;
                } else {
                    positiveTotal += yValue;
                }
            }
        }

        function eachYValue(yValue, i) {
            if (!me.isExcluded(i)) {
                if (yValue > max) {
                    max = yValue;
                }
                if (yValue < min) {
                    min = yValue;
                }
            }
        }

        if (me.getRecordCount() > 0) {
            min = Infinity;
            max = -min;
            
            for (i = 0, ln = data.length; i < ln; i++) {
                record = data[i];
                if (stacked) {
                    positiveTotal = 0;
                    negativeTotal = 0;
                    me.eachYValue(record, eachYValueStacked);
                    if (positiveTotal > max) {
                        max = positiveTotal;
                    }
                    if (negativeTotal < min) {
                        min = negativeTotal;
                    }
                } else {
                    me.eachYValue(record, eachYValue);
                }
            }
        } else {
            min = max = 0;
        }
        return [min, max];
    },

    getAxesForXAndYFields: function() {
        var me = this,
            axes = me.chart.axes,
            axis = [].concat(me.axis),
            yFields = {}, yFieldList = [].concat(me.yField),
            xFields = {}, xFieldList = [].concat(me.xField),
            fields, xAxis, yAxis, i, ln, flipXY;

        
        flipXY = me.type === 'bar' && me.column === false;
        if(flipXY) {
            fields = yFieldList;
            yFieldList = xFieldList;
            xFieldList = fields;
        }
        if (Ext.Array.indexOf(axis, 'top') > -1) {
            xAxis = 'top';
        } else if (Ext.Array.indexOf(axis, 'bottom') > -1) {
            xAxis = 'bottom';
        } else {
            if (axes.get('top') && axes.get('bottom')) {
                for (i = 0, ln = xFieldList.length; i < ln; i++) {
                    xFields[xFieldList[i]] = true;
                }
                fields = [].concat(axes.get('bottom').fields);
                for (i = 0, ln = fields.length; i < ln; i++) {
                    if (xFields[fields[i]]) {
                        xAxis = 'bottom';
                        break
                    }
                }
                fields = [].concat(axes.get('top').fields);
                for (i = 0, ln = fields.length; i < ln; i++) {
                    if (xFields[fields[i]]) {
                        xAxis = 'top';
                        break
                    }
                }
            } else if (axes.get('top')) {
                xAxis = 'top';
            } else if (axes.get('bottom')) {
                xAxis = 'bottom';
            }
        }
        if (Ext.Array.indexOf(axis, 'left') > -1) {
            yAxis = 'left';
        } else if (Ext.Array.indexOf(axis, 'right') > -1) {
            yAxis = 'right';
        } else {
            if (axes.get('left') && axes.get('right')) {
                for (i = 0, ln = yFieldList.length; i < ln; i++) {
                    yFields[yFieldList[i]] = true;
                }
                fields = [].concat(axes.get('right').fields);
                for (i = 0, ln = fields.length; i < ln; i++) {
                    if (yFields[fields[i]]) {

                        break
                    }
                }
                fields = [].concat(axes.get('left').fields);
                for (i = 0, ln = fields.length; i < ln; i++) {
                    if (yFields[fields[i]]) {
                        yAxis = 'left';
                        break
                    }
                }
            } else if (axes.get('left')) {
                yAxis = 'left';
            } else if (axes.get('right')) {
                yAxis = 'right';
            }
        }

        return flipXY ? {
            xAxis: yAxis,
            yAxis: xAxis
        }: {
            xAxis: xAxis,
            yAxis: yAxis
        };
    }


});


Ext.define('Ext.chart.series.Area', {

    

    extend: 'Ext.chart.series.Cartesian',

    alias: 'series.area',

    requires: ['Ext.chart.axis.Axis', 'Ext.draw.Color', 'Ext.fx.Anim'],

    

    type: 'area',

    
    stacked: true,

    
    style: {},

    constructor: function(config) {
        this.callParent(arguments);
        var me = this,
            surface = me.chart.surface,
            i, l;
        config.highlightCfg = Ext.Object.merge({}, {
            lineWidth: 3,
            stroke: '#55c',
            opacity: 0.8,
            color: '#f00'
        }, config.highlightCfg);

        Ext.apply(me, config, {
            __excludes: []
        });
        if (me.highlight) {
            me.highlightSprite = surface.add({
                type: 'path',
                path: ['M', 0, 0],
                zIndex: 1000,
                opacity: 0.3,
                lineWidth: 5,
                hidden: true,
                stroke: '#444'
            });
        }
        me.group = surface.getGroup(me.seriesId);
    },

    
    shrink: function(xValues, yValues, size) {
        var len = xValues.length,
            ratio = Math.floor(len / size),
            i, j,
            xSum = 0,
            yCompLen = this.areas.length,
            ySum = [],
            xRes = [],
            yRes = [];
        
        for (j = 0; j < yCompLen; ++j) {
            ySum[j] = 0;
        }
        for (i = 0; i < len; ++i) {
            xSum += +xValues[i];
            for (j = 0; j < yCompLen; ++j) {
                ySum[j] += +yValues[i][j];
            }
            if (i % ratio == 0) {
                
                xRes.push(xSum/ratio);
                for (j = 0; j < yCompLen; ++j) {
                    ySum[j] /= ratio;
                }
                yRes.push(ySum);
                
                xSum = 0;
                for (j = 0, ySum = []; j < yCompLen; ++j) {
                    ySum[j] = 0;
                }
            }
        }
        return {
            x: xRes,
            y: yRes
        };
    },

    
    getBounds: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            data = store.data.items,
            i, l, record,
            areas = [].concat(me.yField),
            areasLen = areas.length,
            xValues = [],
            yValues = [],
            infinity = Infinity,
            minX = infinity,
            minY = infinity,
            maxX = -infinity,
            maxY = -infinity,
            math = Math,
            mmin = math.min,
            mmax = math.max,
            boundAxis = me.getAxesForXAndYFields(),
            boundXAxis = boundAxis.xAxis,
            boundYAxis = boundAxis.yAxis,
            ends, allowDate,
            bbox, xScale, yScale, xValue, yValue, areaIndex, acumY, ln, sumValues, clipBox, areaElem, axis, out;

        me.setBBox();
        bbox = me.bbox;

        if (axis = chart.axes.get(boundXAxis)) {
            if (axis.type === 'Time') {
                allowDate = true;
            }
            ends = axis.applyData();
            minX = ends.from;
            maxX = ends.to;
        }

        if (axis = chart.axes.get(boundYAxis)) {
            ends = axis.applyData();
            minY = ends.from;
            maxY = ends.to;
        }

        
        if (me.xField && !Ext.isNumber(minX)) {
            axis = me.getMinMaxXValues();
            allowDate = true;
            minX = axis[0];
            maxX = axis[1];
        }

        if (me.yField && !Ext.isNumber(minY)) {
            axis = me.getMinMaxYValues();
            minY = axis[0];
            maxY = axis[1];
        }

        if (!Ext.isNumber(minY)) {
            minY = 0;
        }
        if (!Ext.isNumber(maxY)) {
            maxY = 0;
        }

        for (i = 0, l = data.length; i < l; i++) {
            record = data[i];
            xValue = record.get(me.xField);
            yValue = [];
            if (typeof xValue != 'number') {
                if (allowDate) {
                    xValue = +xValue;
                } else {
                    xValue = i;
                }
            }
            xValues.push(xValue);
            acumY = 0;
            for (areaIndex = 0; areaIndex < areasLen; areaIndex++) {
                
                if (me.__excludes[areaIndex]) {
                    continue;
                }
                areaElem = record.get(areas[areaIndex]);
                if (typeof areaElem == 'number') {
                    yValue.push(areaElem);
                }
            }
            yValues.push(yValue);
        }

        xScale = bbox.width / ((maxX - minX) || 1);
        yScale = bbox.height / ((maxY - minY) || 1);

        ln = xValues.length;
        if ((ln > bbox.width) && me.areas) {
            sumValues = me.shrink(xValues, yValues, bbox.width);
            xValues = sumValues.x;
            yValues = sumValues.y;
        }

        return {
            bbox: bbox,
            minX: minX,
            minY: minY,
            xValues: xValues,
            yValues: yValues,
            xScale: xScale,
            yScale: yScale,
            areasLen: areasLen
        };
    },

    
    getPaths: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            first = true,
            bounds = me.getBounds(),
            bbox = bounds.bbox,
            items = me.items = [],
            componentPaths = [],
            componentPath,
            count = 0,
            paths = [],
            i, ln, x, y, xValue, yValue, acumY, areaIndex, prevAreaIndex, areaElem, path;

        ln = bounds.xValues.length;
        
        for (i = 0; i < ln; i++) {
            xValue = bounds.xValues[i];
            yValue = bounds.yValues[i];
            x = bbox.x + (xValue - bounds.minX) * bounds.xScale;
            acumY = 0;
            count = 0;
            for (areaIndex = 0; areaIndex < bounds.areasLen; areaIndex++) {
                
                if (me.__excludes[areaIndex]) {
                    continue;
                }
                if (!componentPaths[areaIndex]) {
                    componentPaths[areaIndex] = [];
                }
                areaElem = yValue[count];
                acumY += areaElem;
                y = bbox.y + bbox.height - (acumY - bounds.minY) * bounds.yScale;
                if (!paths[areaIndex]) {
                    paths[areaIndex] = ['M', x, y];
                    componentPaths[areaIndex].push(['L', x, y]);
                } else {
                    paths[areaIndex].push('L', x, y);
                    componentPaths[areaIndex].push(['L', x, y]);
                }
                if (!items[areaIndex]) {
                    items[areaIndex] = {
                        pointsUp: [],
                        pointsDown: [],
                        series: me
                    };
                }
                items[areaIndex].pointsUp.push([x, y]);
                count++;
            }
        }

        
        for (areaIndex = 0; areaIndex < bounds.areasLen; areaIndex++) {
            
            if (me.__excludes[areaIndex]) {
                continue;
            }
            path = paths[areaIndex];
            
            if (areaIndex == 0 || first) {
                first = false;
                path.push('L', x, bbox.y + bbox.height,
                          'L', bbox.x, bbox.y + bbox.height,
                          'Z');
            }
            
            else {
                componentPath = componentPaths[prevAreaIndex];
                componentPath.reverse();
                path.push('L', x, componentPath[0][2]);
                for (i = 0; i < ln; i++) {
                    path.push(componentPath[i][0],
                              componentPath[i][1],
                              componentPath[i][2]);
                    items[areaIndex].pointsDown[ln -i -1] = [componentPath[i][1], componentPath[i][2]];
                }
                path.push('L', bbox.x, path[2], 'Z');
            }
            prevAreaIndex = areaIndex;
        }
        return {
            paths: paths,
            areasLen: bounds.areasLen
        };
    },

    
    drawSeries: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            surface = chart.surface,
            animate = chart.animate,
            group = me.group,
            endLineStyle = Ext.apply(me.seriesStyle, me.style),
            colorArrayStyle = me.colorArrayStyle,
            colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
            areaIndex, areaElem, paths, path, rendererAttributes;
        
        me.unHighlightItem();
        me.cleanHighlights();

        if (!store || !store.getCount() || me.seriesIsHidden) {
            me.hide();
            me.items = [];
            return;
        }

        paths = me.getPaths();

        if (!me.areas) {
            me.areas = [];
        }

        for (areaIndex = 0; areaIndex < paths.areasLen; areaIndex++) {
            
            if (me.__excludes[areaIndex]) {
                continue;
            }
            if (!me.areas[areaIndex]) {
                me.items[areaIndex].sprite = me.areas[areaIndex] = surface.add(Ext.apply({}, {
                    type: 'path',
                    group: group,
                    
                    path: paths.paths[areaIndex],
                    stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength],
                    fill: colorArrayStyle[areaIndex % colorArrayLength]
                }, endLineStyle || {}));
            }
            areaElem = me.areas[areaIndex];
            path = paths.paths[areaIndex];
            if (animate) {
                
                rendererAttributes = me.renderer(areaElem, false, {
                    path: path,
                    
                    fill: colorArrayStyle[areaIndex % colorArrayLength],
                    stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
                }, areaIndex, store);
                
                me.animation = me.onAnimate(areaElem, {
                    to: rendererAttributes
                });
            } else {
                rendererAttributes = me.renderer(areaElem, false, {
                    path: path,
                    
                    hidden: false,
                    fill: colorArrayStyle[areaIndex % colorArrayLength],
                    stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
                }, areaIndex, store);
                me.areas[areaIndex].setAttributes(rendererAttributes, true);
            }
        }
        me.renderLabels();
        me.renderCallouts();
    },

    
    onAnimate: function(sprite, attr) {
        sprite.show();
        return this.callParent(arguments);
    },

    
    onCreateLabel: function(storeItem, item, i, display) {
        var me = this,
            group = me.labelsGroup,
            config = me.label,
            bbox = me.bbox,
            endLabelStyle = Ext.apply(config, me.seriesLabelStyle);

        return me.chart.surface.add(Ext.apply({
            'type': 'text',
            'text-anchor': 'middle',
            'group': group,
            'x': item.point[0],
            'y': bbox.y + bbox.height / 2
        }, endLabelStyle || {}));
    },

    
    onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
        var me = this,
            chart = me.chart,
            resizing = chart.resizing,
            config = me.label,
            format = config.renderer,
            field = config.field,
            bbox = me.bbox,
            x = item.point[0],
            y = item.point[1],
            bb, width, height;

        label.setAttributes({
            text: format(storeItem.get(field[index])),
            hidden: true
        }, true);

        bb = label.getBBox();
        width = bb.width / 2;
        height = bb.height / 2;

        x = x - width < bbox.x? bbox.x + width : x;
        x = (x + width > bbox.x + bbox.width) ? (x - (x + width - bbox.x - bbox.width)) : x;
        y = y - height < bbox.y? bbox.y + height : y;
        y = (y + height > bbox.y + bbox.height) ? (y - (y + height - bbox.y - bbox.height)) : y;

        if (me.chart.animate && !me.chart.resizing) {
            label.show(true);
            me.onAnimate(label, {
                to: {
                    x: x,
                    y: y
                }
            });
        } else {
            label.setAttributes({
                x: x,
                y: y
            }, true);
            if (resizing) {
                me.animation.on('afteranimate', function() {
                    label.show(true);
                });
            } else {
                label.show(true);
            }
        }
    },

    
    onPlaceCallout : function(callout, storeItem, item, i, display, animate, index) {
        var me = this,
            chart = me.chart,
            surface = chart.surface,
            resizing = chart.resizing,
            config = me.callouts,
            items = me.items,
            prev = (i == 0) ? false : items[i -1].point,
            next = (i == items.length -1) ? false : items[i +1].point,
            cur = item.point,
            dir, norm, normal, a, aprev, anext,
            bbox = callout.label.getBBox(),
            offsetFromViz = 30,
            offsetToSide = 10,
            offsetBox = 3,
            boxx, boxy, boxw, boxh,
            p, clipRect = me.clipRect,
            x, y;

        
        if (!prev) {
            prev = cur;
        }
        if (!next) {
            next = cur;
        }
        a = (next[1] - prev[1]) / (next[0] - prev[0]);
        aprev = (cur[1] - prev[1]) / (cur[0] - prev[0]);
        anext = (next[1] - cur[1]) / (next[0] - cur[0]);

        norm = Math.sqrt(1 + a * a);
        dir = [1 / norm, a / norm];
        normal = [-dir[1], dir[0]];

        
        if (aprev > 0 && anext < 0 && normal[1] < 0 || aprev < 0 && anext > 0 && normal[1] > 0) {
            normal[0] *= -1;
            normal[1] *= -1;
        } else if (Math.abs(aprev) < Math.abs(anext) && normal[0] < 0 || Math.abs(aprev) > Math.abs(anext) && normal[0] > 0) {
            normal[0] *= -1;
            normal[1] *= -1;
        }

        
        x = cur[0] + normal[0] * offsetFromViz;
        y = cur[1] + normal[1] * offsetFromViz;

        
        boxx = x + (normal[0] > 0? 0 : -(bbox.width + 2 * offsetBox));
        boxy = y - bbox.height /2 - offsetBox;
        boxw = bbox.width + 2 * offsetBox;
        boxh = bbox.height + 2 * offsetBox;

        
        
        if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
            normal[0] *= -1;
        }
        if (boxy < clipRect[1] || (boxy + boxh) > (clipRect[1] + clipRect[3])) {
            normal[1] *= -1;
        }

        
        x = cur[0] + normal[0] * offsetFromViz;
        y = cur[1] + normal[1] * offsetFromViz;

        
        boxx = x + (normal[0] > 0? 0 : -(bbox.width + 2 * offsetBox));
        boxy = y - bbox.height /2 - offsetBox;
        boxw = bbox.width + 2 * offsetBox;
        boxh = bbox.height + 2 * offsetBox;

        
        callout.lines.setAttributes({
            path: ["M", cur[0], cur[1], "L", x, y, "Z"]
        }, true);
        
        callout.box.setAttributes({
            x: boxx,
            y: boxy,
            width: boxw,
            height: boxh
        }, true);
        
        callout.label.setAttributes({
            x: x + (normal[0] > 0? offsetBox : -(bbox.width + offsetBox)),
            y: y
        }, true);
        for (p in callout) {
            callout[p].show(true);
        }
    },

    isItemInPoint: function(x, y, item, i) {
        var me = this,
            pointsUp = item.pointsUp,
            pointsDown = item.pointsDown,
            abs = Math.abs,
            distChanged = false,
            last = false,
            dist = Infinity, p, pln, point;

        for (p = 0, pln = pointsUp.length; p < pln; p++) {
            point = [pointsUp[p][0], pointsUp[p][1]];
            
            distChanged = false;
            last = p == pln -1;

            if (dist > abs(x - point[0])) {
                dist = abs(x - point[0]);
                distChanged = true;
                if (last) {
                    ++p;
                }
            }
            
            if (!distChanged || (distChanged && last)) {
                point = pointsUp[p -1];
                if (y >= point[1] && (!pointsDown.length || y <= (pointsDown[p -1][1]))) {
                    item.storeIndex = p -1;
                    item.storeField = me.yField[i];
                    item.storeItem = me.chart.store.getAt(p -1);
                    item._points = pointsDown.length? [point, pointsDown[p -1]] : [point];
                    return true;
                } else {
                    break;
                }
            }
        }
        return false;
    },

    
    highlightSeries: function() {
        var area, to, fillColor;
        if (this._index !== undefined) {
            area = this.areas[this._index];
            if (area.__highlightAnim) {
                area.__highlightAnim.paused = true;
            }
            area.__highlighted = true;
            area.__prevOpacity = area.__prevOpacity || area.attr.opacity || 1;
            area.__prevFill = area.__prevFill || area.attr.fill;
            area.__prevLineWidth = area.__prevLineWidth || area.attr.lineWidth;
            fillColor = Ext.draw.Color.fromString(area.__prevFill);
            to = {
                lineWidth: (area.__prevLineWidth || 0) + 2
            };
            if (fillColor) {
                to.fill = fillColor.getLighter(0.2).toString();
            }
            else {
                to.opacity = Math.max(area.__prevOpacity - 0.3, 0);
            }
            if (this.chart.animate) {
                area.__highlightAnim = new Ext.fx.Anim(Ext.apply({
                    target: area,
                    to: to
                }, this.chart.animate));
            }
            else {
                area.setAttributes(to, true);
            }
        }
    },

    
    unHighlightSeries: function() {
        var area;
        if (this._index !== undefined) {
            area = this.areas[this._index];
            if (area.__highlightAnim) {
                area.__highlightAnim.paused = true;
            }
            if (area.__highlighted) {
                area.__highlighted = false;
                area.__highlightAnim = new Ext.fx.Anim({
                    target: area,
                    to: {
                        fill: area.__prevFill,
                        opacity: area.__prevOpacity,
                        lineWidth: area.__prevLineWidth
                    }
                });
            }
        }
    },

    
    highlightItem: function(item) {
        var me = this,
            points, path;
        if (!item) {
            this.highlightSeries();
            return;
        }
        points = item._points;
        path = points.length == 2? ['M', points[0][0], points[0][1], 'L', points[1][0], points[1][1]]
                : ['M', points[0][0], points[0][1], 'L', points[0][0], me.bbox.y + me.bbox.height];
        me.highlightSprite.setAttributes({
            path: path,
            hidden: false
        }, true);
    },

    
    unHighlightItem: function(item) {
        if (!item) {
            this.unHighlightSeries();
        }

        if (this.highlightSprite) {
            this.highlightSprite.hide(true);
        }
    },

    
    hideAll: function(index) {
        var me = this;
        index = (isNaN(me._index) ? index : me._index) || 0;
        me.__excludes[index] = true;
        me.areas[index].hide(true);
        me.redraw();
    },

    
    showAll: function(index) {
        var me = this;
        index = (isNaN(me._index) ? index : me._index) || 0;
        me.__excludes[index] = false;
        me.areas[index].show(true);
        me.redraw();
    },

    redraw: function() {
        
        
        
        var me = this,
            prevLegendConfig;
        prevLegendConfig = me.chart.legend.rebuild;
        me.chart.legend.rebuild = false;
        me.chart.redraw();
        me.chart.legend.rebuild = prevLegendConfig;
    },
    
    hide: function() {
        if (this.areas) {
            var me = this,
                areas = me.areas,
                i, j, l, ln, shadows;
            
            if (areas && areas.length) {
                for (i = 0, ln = areas.length; i < ln; ++i) {
                    if (areas[i]) {
                        areas[i].hide(true);
                    }
                }
                me.hideLabels();
            }
        }
    },

    
    getLegendColor: function(index) {
        var me = this;
        return me.colorArrayStyle[index % me.colorArrayStyle.length];
    }
});


Ext.define('Ext.chart.series.Bar', {

    

    extend: 'Ext.chart.series.Cartesian',

    alternateClassName: ['Ext.chart.BarSeries', 'Ext.chart.BarChart', 'Ext.chart.StackedBarChart'],

    requires: ['Ext.chart.axis.Axis', 'Ext.fx.Anim'],

    

    type: 'bar',

    alias: 'series.bar',
    
    column: false,

    
    style: {},

    
    gutter: 38.2,

    
    groupGutter: 38.2,

    
    xPadding: 0,

    
    yPadding: 10,

    constructor: function(config) {
        this.callParent(arguments);
        var me = this,
            surface = me.chart.surface,
            shadow = me.chart.shadow,
            i, l;
        config.highlightCfg = Ext.Object.merge({
            lineWidth: 3,
            stroke: '#55c',
            opacity: 0.8,
            color: '#f00'
        }, config.highlightCfg);
        Ext.apply(me, config, {
            shadowAttributes: [{
                "stroke-width": 6,
                "stroke-opacity": 0.05,
                stroke: 'rgb(200, 200, 200)',
                translate: {
                    x: 1.2,
                    y: 1.2
                }
            }, {
                "stroke-width": 4,
                "stroke-opacity": 0.1,
                stroke: 'rgb(150, 150, 150)',
                translate: {
                    x: 0.9,
                    y: 0.9
                }
            }, {
                "stroke-width": 2,
                "stroke-opacity": 0.15,
                stroke: 'rgb(100, 100, 100)',
                translate: {
                    x: 0.6,
                    y: 0.6
                }
            }]
        });

        me.group = surface.getGroup(me.seriesId + '-bars');
        if (shadow) {
            for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
                me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
            }
        }
    },

    
    getBarGirth: function() {
        var me = this,
            store = me.chart.getChartStore(),
            column = me.column,
            ln = store.getCount(),
            gutter = me.gutter / 100;

        return (me.chart.chartBBox[column ? 'width' : 'height'] - me[column ? 'xPadding' : 'yPadding'] * 2) / (ln * (gutter + 1) - gutter);
    },

    
    getGutters: function() {
        var me = this,
            column = me.column,
            gutter = Math.ceil(me[column ? 'xPadding' : 'yPadding'] + me.getBarGirth() / 2);
        return me.column ? [gutter, 0] : [0, gutter];
    },

    
    getBounds: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            data = store.data.items,
            i, ln, record,
            bars = [].concat(me.yField),
            barsLen = bars.length,
            groupBarsLen = barsLen,
            groupGutter = me.groupGutter / 100,
            column = me.column,
            xPadding = me.xPadding,
            yPadding = me.yPadding,
            stacked = me.stacked,
            barWidth = me.getBarGirth(),
            barWidthProperty = column ? 'width' : 'height',
            math = Math,
            mmin = math.min,
            mmax = math.max,
            mabs = math.abs,
            boundAxes = me.getAxesForXAndYFields(),
            boundYAxis = boundAxes.yAxis,
            ends, shrunkBarWidth, groupBarWidth, bbox, minY, maxY, axis, out,
            scale, zero, total, rec, j, plus, minus;

        me.setBBox(true);
        bbox = me.bbox;

        
        if (me.__excludes) {
            for (j = 0, total = me.__excludes.length; j < total; j++) {
                if (me.__excludes[j]) {
                    groupBarsLen--;
                }
            }
        }
        axis = chart.axes.get(boundYAxis);
        if (axis) {
            ends = axis.applyData();
            minY = ends.from;
            maxY = ends.to;
        }

        if (me.yField && !Ext.isNumber(minY)) {
            out = me.getMinMaxYValues();
            minY = out[0];
            maxY = out[1];
        }

        if (!Ext.isNumber(minY)) {
            minY = 0;
        }
        if (!Ext.isNumber(maxY)) {
            maxY = 0;
        }
        scale = (column ? bbox.height - yPadding * 2 : bbox.width - xPadding * 2) / (maxY - minY);
        shrunkBarWidth = barWidth;
        groupBarWidth = (barWidth / ((stacked ? 1 : groupBarsLen) * (groupGutter + 1) - groupGutter));
        
        if (barWidthProperty in me.style) {
            groupBarWidth = mmin(groupBarWidth, me.style[barWidthProperty]);
            shrunkBarWidth = groupBarWidth * ((stacked ? 1 : groupBarsLen) * (groupGutter + 1) - groupGutter);
        }
        zero = (column) ? bbox.y + bbox.height - yPadding : bbox.x + xPadding;

        if (stacked) {
            total = [[], []];
            for (i = 0, ln = data.length; i < ln; i++) {
                record = data[i];
                total[0][i] = total[0][i] || 0;
                total[1][i] = total[1][i] || 0;
                for (j = 0; j < barsLen; j++) {
                    if (me.__excludes && me.__excludes[j]) {
                        continue;
                    }
                    rec = record.get(bars[j]);
                    total[+(rec > 0)][i] += mabs(rec);
                }
            }
            total[+(maxY > 0)].push(mabs(maxY));
            total[+(minY > 0)].push(mabs(minY));
            minus = mmax.apply(math, total[0]);
            plus = mmax.apply(math, total[1]);
            scale = (column ? bbox.height - yPadding * 2 : bbox.width - xPadding * 2) / (plus + minus);
            zero = zero + minus * scale * (column ? -1 : 1);
        }
        else if (minY / maxY < 0) {
            zero = zero - minY * scale * (column ? -1 : 1);
        }
        return {
            bars: bars,
            bbox: bbox,
            shrunkBarWidth: shrunkBarWidth,
            barsLen: barsLen,
            groupBarsLen: groupBarsLen,
            barWidth: barWidth,
            groupBarWidth: groupBarWidth,
            scale: scale,
            zero: zero,
            xPadding: xPadding,
            yPadding: yPadding,
            signed: minY / maxY < 0,
            minY: minY,
            maxY: maxY
        };
    },

    
    getPaths: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            data = store.data.items,
            i, total, record,
            bounds = me.bounds = me.getBounds(),
            items = me.items = [],
            yFields = me.yField,
            gutter = me.gutter / 100,
            groupGutter = me.groupGutter / 100,
            animate = chart.animate,
            column = me.column,
            group = me.group,
            enableShadows = chart.shadow,
            shadowGroups = me.shadowGroups,
            shadowAttributes = me.shadowAttributes,
            shadowGroupsLn = shadowGroups.length,
            bbox = bounds.bbox,
            barWidth = bounds.barWidth,
            shrunkBarWidth = bounds.shrunkBarWidth,
            xPadding = me.xPadding,
            yPadding = me.yPadding,
            stacked = me.stacked,
            barsLen = bounds.barsLen,
            colors = me.colorArrayStyle,
            colorLength = colors && colors.length || 0,
            math = Math,
            mmax = math.max,
            mmin = math.min,
            mabs = math.abs,
            j, yValue, height, totalDim, totalNegDim, bottom, top, hasShadow, barAttr, attrs, counter,
            shadowIndex, shadow, sprite, offset, floorY;

        for (i = 0, total = data.length; i < total; i++) {
            record = data[i];
            bottom = bounds.zero;
            top = bounds.zero;
            totalDim = 0;
            totalNegDim = 0;
            hasShadow = false;
            for (j = 0, counter = 0; j < barsLen; j++) {
                
                if (me.__excludes && me.__excludes[j]) {
                    continue;
                }
                yValue = record.get(bounds.bars[j]);
                height = Math.round((yValue - mmax(bounds.minY, 0)) * bounds.scale);
                barAttr = {
                    fill: colors[(barsLen > 1 ? j : 0) % colorLength]
                };
                if (column) {
                    Ext.apply(barAttr, {
                        height: height,
                        width: mmax(bounds.groupBarWidth, 0),
                        x: (bbox.x + xPadding + (barWidth - shrunkBarWidth) * 0.5 + i * barWidth * (1 + gutter) + counter * bounds.groupBarWidth * (1 + groupGutter) * !stacked),
                        y: bottom - height
                    });
                }
                else {
                    
                    offset = (total - 1) - i;
                    Ext.apply(barAttr, {
                        height: mmax(bounds.groupBarWidth, 0),
                        width: height + (bottom == bounds.zero),
                        x: bottom + (bottom != bounds.zero),
                        y: (bbox.y + yPadding + (barWidth - shrunkBarWidth) * 0.5 + offset * barWidth * (1 + gutter) + counter * bounds.groupBarWidth * (1 + groupGutter) * !stacked + 1)
                    });
                }
                if (height < 0) {
                    if (column) {
                        barAttr.y = top;
                        barAttr.height = mabs(height);
                    } else {
                        barAttr.x = top + height;
                        barAttr.width = mabs(height);
                    }
                }
                if (stacked) {
                    if (height < 0) {
                        top += height * (column ? -1 : 1);
                    } else {
                        bottom += height * (column ? -1 : 1);
                    }
                    totalDim += mabs(height);
                    if (height < 0) {
                        totalNegDim += mabs(height);
                    }
                }
                barAttr.x = Math.floor(barAttr.x) + 1;
                floorY = Math.floor(barAttr.y);
                if (!Ext.isIE9 && barAttr.y > floorY) {
                    floorY--;
                }
                barAttr.y = floorY;
                barAttr.width = Math.floor(barAttr.width);
                barAttr.height = Math.floor(barAttr.height);
                items.push({
                    series: me,
                    yField: yFields[j],
                    storeItem: record,
                    value: [record.get(me.xField), yValue],
                    attr: barAttr,
                    point: column ? [barAttr.x + barAttr.width / 2, yValue >= 0 ? barAttr.y : barAttr.y + barAttr.height] :
                                    [yValue >= 0 ? barAttr.x + barAttr.width : barAttr.x, barAttr.y + barAttr.height / 2]
                });
                
                if (animate && chart.resizing) {
                    attrs = column ? {
                        x: barAttr.x,
                        y: bounds.zero,
                        width: barAttr.width,
                        height: 0
                    } : {
                        x: bounds.zero,
                        y: barAttr.y,
                        width: 0,
                        height: barAttr.height
                    };
                    if (enableShadows && (stacked && !hasShadow || !stacked)) {
                        hasShadow = true;
                        
                        for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
                            shadow = shadowGroups[shadowIndex].getAt(stacked ? i : (i * barsLen + j));
                            if (shadow) {
                                shadow.setAttributes(attrs, true);
                            }
                        }
                    }
                    
                    sprite = group.getAt(i * barsLen + j);
                    if (sprite) {
                        sprite.setAttributes(attrs, true);
                    }
                }
                counter++;
            }
            if (stacked && items.length) {
                items[i * counter].totalDim = totalDim;
                items[i * counter].totalNegDim = totalNegDim;
            }
        }
        if (stacked && counter == 0) {
            
            for (i = 0, total = data.length; i < total; i++) {
                for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
                    shadow = shadowGroups[shadowIndex].getAt(i);
                    if (shadow) {
                        shadow.hide(true);
                    }
                }
            }
        }
    },

    
    renderShadows: function(i, barAttr, baseAttrs, bounds) {
        var me = this,
            chart = me.chart,
            surface = chart.surface,
            animate = chart.animate,
            stacked = me.stacked,
            shadowGroups = me.shadowGroups,
            shadowAttributes = me.shadowAttributes,
            shadowGroupsLn = shadowGroups.length,
            store = chart.getChartStore(),
            column = me.column,
            items = me.items,
            shadows = [],
            zero = bounds.zero,
            shadowIndex, shadowBarAttr, shadow, totalDim, totalNegDim, j, rendererAttributes;

        if ((stacked && (i % bounds.groupBarsLen === 0)) || !stacked) {
            j = i / bounds.groupBarsLen;
            
            for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
                shadowBarAttr = Ext.apply({}, shadowAttributes[shadowIndex]);
                shadow = shadowGroups[shadowIndex].getAt(stacked ? j : i);
                Ext.copyTo(shadowBarAttr, barAttr, 'x,y,width,height');
                if (!shadow) {
                    shadow = surface.add(Ext.apply({
                        type: 'rect',
                        group: shadowGroups[shadowIndex]
                    }, Ext.apply({}, baseAttrs, shadowBarAttr)));
                }
                if (stacked) {
                    totalDim = items[i].totalDim;
                    totalNegDim = items[i].totalNegDim;
                    if (column) {
                        shadowBarAttr.y = zero + totalNegDim - totalDim - 1;
                        shadowBarAttr.height = totalDim;
                    }
                    else {
                        shadowBarAttr.x = zero - totalNegDim;
                        shadowBarAttr.width = totalDim;
                    }
                }
                
                rendererAttributes = me.renderer(shadow, store.getAt(j), shadowBarAttr, i, store);
                rendererAttributes.hidden = !!barAttr.hidden;
                if (animate) {
                    me.onAnimate(shadow, { to: rendererAttributes });
                }
                else {
                    shadow.setAttributes(rendererAttributes, true);
                }
                shadows.push(shadow);
            }
        }
        return shadows;
    },

    
    drawSeries: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            surface = chart.surface,
            animate = chart.animate,
            stacked = me.stacked,
            column = me.column,
            enableShadows = chart.shadow,
            shadowGroups = me.shadowGroups,
            shadowGroupsLn = shadowGroups.length,
            group = me.group,
            seriesStyle = me.seriesStyle,
            items, ln, i, j, baseAttrs, sprite, rendererAttributes, shadowIndex, shadowGroup,
            bounds, endSeriesStyle, barAttr, attrs, anim;

        if (!store || !store.getCount() || me.seriesIsHidden) {
            me.hide();
            me.items = [];
            return;
        }

        
        endSeriesStyle = Ext.apply({}, this.style, seriesStyle);
        delete endSeriesStyle.fill;
        delete endSeriesStyle.x;
        delete endSeriesStyle.y;
        delete endSeriesStyle.width;
        delete endSeriesStyle.height;
        
        me.unHighlightItem();
        me.cleanHighlights();
        
        me.getPaths();
        bounds = me.bounds;
        items = me.items;

        baseAttrs = column ? {
            y: bounds.zero,
            height: 0
        } : {
            x: bounds.zero,
            width: 0
        };
        ln = items.length;
        
        for (i = 0; i < ln; i++) {
            sprite = group.getAt(i);
            barAttr = items[i].attr;

            if (enableShadows) {
                items[i].shadows = me.renderShadows(i, barAttr, baseAttrs, bounds);
            }

            
            if (!sprite) {
                attrs = Ext.apply({}, baseAttrs, barAttr);
                attrs = Ext.apply(attrs, endSeriesStyle || {});
                sprite = surface.add(Ext.apply({}, {
                    type: 'rect',
                    group: group
                }, attrs));
            }
            if (animate) {
                rendererAttributes = me.renderer(sprite, store.getAt(i), barAttr, i, store);
                sprite._to = rendererAttributes;
                anim = me.onAnimate(sprite, { to: Ext.apply(rendererAttributes, endSeriesStyle) });
                if (enableShadows && stacked && (i % bounds.barsLen === 0)) {
                    j = i / bounds.barsLen;
                    for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
                        anim.on('afteranimate', function() {
                            this.show(true);
                        }, shadowGroups[shadowIndex].getAt(j));
                    }
                }
            }
            else {
                rendererAttributes = me.renderer(sprite, store.getAt(i), Ext.apply(barAttr, { hidden: false }), i, store);
                sprite.setAttributes(Ext.apply(rendererAttributes, endSeriesStyle), true);
            }
            items[i].sprite = sprite;
        }

        
        ln = group.getCount();
        for (j = i; j < ln; j++) {
            group.getAt(j).hide(true);
        }
        
        if (me.stacked) {
            
            i = store.getCount();    
        }
        
        
        if (enableShadows) {
            for (shadowIndex = 0; shadowIndex < shadowGroupsLn; shadowIndex++) {
                shadowGroup = shadowGroups[shadowIndex];
                ln = shadowGroup.getCount();
                for (j = i; j < ln; j++) {
                    shadowGroup.getAt(j).hide(true);
                }
            }
        }
        me.renderLabels();
    },

    
    onCreateLabel: function(storeItem, item, i, display) {
        var me = this,
            surface = me.chart.surface,
            group = me.labelsGroup,
            config = me.label,
            endLabelStyle = Ext.apply({}, config, me.seriesLabelStyle || {}),
            sprite;
        return surface.add(Ext.apply({
            type: 'text',
            group: group
        }, endLabelStyle || {}));
    },

    
    onPlaceLabel: function(label, storeItem, item, i, display, animate, j, index) {
        
        
        var me = this,
            opt = me.bounds,
            groupBarWidth = opt.groupBarWidth,
            column = me.column,
            chart = me.chart,
            chartBBox = chart.chartBBox,
            resizing = chart.resizing,
            xValue = item.value[0],
            yValue = item.value[1],
            attr = item.attr,
            config = me.label,
            rotate = config.orientation == 'vertical',
            field = [].concat(config.field),
            format = config.renderer,
            text = format(storeItem.get(field[index])),
            size = me.getLabelSize(text),
            width = size.width,
            height = size.height,
            zero = opt.zero,
            outside = 'outside',
            insideStart = 'insideStart',
            insideEnd = 'insideEnd',
            offsetX = 10,
            offsetY = 6,
            signed = opt.signed,
            x, y, finalAttr;

        label.setAttributes({
            text: text
        });

        label.isOutside = false;
        if (column) {
            if (display == outside) {
                if (height + offsetY + attr.height > (yValue >= 0 ? zero - chartBBox.y : chartBBox.y + chartBBox.height - zero)) {
                    display = insideEnd;
                }
            } else {
                if (height + offsetY > attr.height) {
                    display = outside;
                    label.isOutside = true;
                }
            }
            x = attr.x + groupBarWidth / 2;
            y = display == insideStart ?
                    (zero + ((height / 2 + 3) * (yValue >= 0 ? -1 : 1))) :
                    (yValue >= 0 ? (attr.y + ((height / 2 + 3) * (display == outside ? -1 : 1))) :
                                   (attr.y + attr.height + ((height / 2 + 3) * (display === outside ? 1 : -1))));
        }
        else {
            if (display == outside) {
                if (width + offsetX + attr.width > (yValue >= 0 ? chartBBox.x + chartBBox.width - zero : zero - chartBBox.x)) {
                    display = insideEnd;
                }
            }
            else {
                if (width + offsetX > attr.width) {
                    display = outside;
                    label.isOutside = true;
                }
            }
            x = display == insideStart ?
                (zero + ((width / 2 + 5) * (yValue >= 0 ? 1 : -1))) :
                (yValue >= 0 ? (attr.x + attr.width + ((width / 2 + 5) * (display === outside ? 1 : -1))) :
                (attr.x + ((width / 2 + 5) * (display === outside ? -1 : 1))));
            y = attr.y + groupBarWidth / 2;
        }
        
        finalAttr = {
            x: x,
            y: y
        };
        
        if (rotate) {
            finalAttr.rotate = {
                x: x,
                y: y,
                degrees: 270
            };
        }
        
        if (animate && resizing) {
            if (column) {
                x = attr.x + attr.width / 2;
                y = zero;
            } else {
                x = zero;
                y = attr.y + attr.height / 2;
            }
            label.setAttributes({
                x: x,
                y: y
            }, true);
            if (rotate) {
                label.setAttributes({
                    rotate: {
                        x: x,
                        y: y,
                        degrees: 270
                    }
                }, true);
            }
        }
        
        if (animate) {
            me.onAnimate(label, { to: finalAttr });
        }
        else {
            label.setAttributes(Ext.apply(finalAttr, {
                hidden: false
            }), true);
        }
    },

    
    getLabelSize: function(value) {
        var tester = this.testerLabel,
            config = this.label,
            endLabelStyle = Ext.apply({}, config, this.seriesLabelStyle || {}),
            rotated = config.orientation === 'vertical',
            bbox, w, h,
            undef;
        if (!tester) {
            tester = this.testerLabel = this.chart.surface.add(Ext.apply({
                type: 'text',
                opacity: 0
            }, endLabelStyle));
        }
        tester.setAttributes({
            text: value
        }, true);

        
        bbox = tester.getBBox();
        w = bbox.width;
        h = bbox.height;
        return {
            width: rotated ? h : w,
            height: rotated ? w : h
        };
    },

    
    onAnimate: function(sprite, attr) {
        sprite.show();
        return this.callParent(arguments);
    },

    isItemInPoint: function(x, y, item) {
        var bbox = item.sprite.getBBox();
        return bbox.x <= x && bbox.y <= y
            && (bbox.x + bbox.width) >= x
            && (bbox.y + bbox.height) >= y;
    },

    
    hideAll: function(index) {
        var axes      = this.chart.axes,
            axesItems = axes.items,
            ln        = axesItems.length,
            i         = 0;

        index = (isNaN(this._index) ? index : this._index) || 0;

        if (!this.__excludes) {
            this.__excludes = [];
        }

        this.__excludes[index] = true;
        this.drawSeries();

        for (i; i < ln; i++) {
            axesItems[i].drawAxis();
        }    
    },

    
    showAll: function(index) {
        var axes = this.chart.axes,
            axesItems = axes.items,
            ln        = axesItems.length,
            i         = 0;

        index = (isNaN(this._index) ? index : this._index) || 0;

        if (!this.__excludes) {
            this.__excludes = [];
        }

        this.__excludes[index] = false;
        this.drawSeries();

        for (i; i < ln; i++) {
            axesItems[i].drawAxis();
        }    
    },

    
    getLegendColor: function(index) {
        var me = this,
            colorLength = me.colorArrayStyle.length;

        if (me.style && me.style.fill) {
            return me.style.fill;
        } else {
            return me.colorArrayStyle[index % colorLength];
        }
    },

    highlightItem: function(item) {
        this.callParent(arguments);
        this.renderLabels();
    },

    unHighlightItem: function() {
        this.callParent(arguments);
        this.renderLabels();
    },

    cleanHighlights: function() {
        this.callParent(arguments);
        this.renderLabels();
    }
});


Ext.define('Ext.chart.series.Column', {

    

    alternateClassName: ['Ext.chart.ColumnSeries', 'Ext.chart.ColumnChart', 'Ext.chart.StackedColumnChart'],

    extend: 'Ext.chart.series.Bar',

    

    type: 'column',
    alias: 'series.column',

    column: true,

    
    xPadding: 10,

    
    yPadding: 0
});

Ext.define('Ext.chart.series.Gauge', {

    

    extend: 'Ext.chart.series.Series',

    

    type: "gauge",
    alias: 'series.gauge',

    rad: Math.PI / 180,

    
    highlightDuration: 150,

    
    angleField: false,

    
    needle: false,
    
    
    donut: false,

    
    showInLegend: false,

    
    style: {},
    
    constructor: function(config) {
        this.callParent(arguments);
        var me = this,
            chart = me.chart,
            surface = chart.surface,
            store = chart.store,
            shadow = chart.shadow, i, l, cfg;
        Ext.apply(me, config, {
            shadowAttributes: [{
                "stroke-width": 6,
                "stroke-opacity": 1,
                stroke: 'rgb(200, 200, 200)',
                translate: {
                    x: 1.2,
                    y: 2
                }
            },
            {
                "stroke-width": 4,
                "stroke-opacity": 1,
                stroke: 'rgb(150, 150, 150)',
                translate: {
                    x: 0.9,
                    y: 1.5
                }
            },
            {
                "stroke-width": 2,
                "stroke-opacity": 1,
                stroke: 'rgb(100, 100, 100)',
                translate: {
                    x: 0.6,
                    y: 1
                }
            }]
        });
        me.group = surface.getGroup(me.seriesId);
        if (shadow) {
            for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
                me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
            }
        }
        surface.customAttributes.segment = function(opt) {
            return me.getSegment(opt);
        };
    },
    
    
    initialize: function() {
        var me = this,
            store = me.chart.getChartStore(),
            data = store.data.items,
            i, ln, rec;
        
        me.yField = [];
        if (me.label.field) {
            for (i = 0, ln = data.length; i < ln; i++) {
                rec = data[i];
                me.yField.push(rec.get(me.label.field));
            }
        }
    },

    
    getSegment: function(opt) {
        var me = this,
            rad = me.rad,
            cos = Math.cos,
            sin = Math.sin,
            abs = Math.abs,
            x = me.centerX,
            y = me.centerY,
            x1 = 0, x2 = 0, x3 = 0, x4 = 0,
            y1 = 0, y2 = 0, y3 = 0, y4 = 0,
            delta = 1e-2,
            r = opt.endRho - opt.startRho,
            startAngle = opt.startAngle,
            endAngle = opt.endAngle,
            midAngle = (startAngle + endAngle) / 2 * rad,
            margin = opt.margin || 0,
            flag = abs(endAngle - startAngle) > 180,
            a1 = Math.min(startAngle, endAngle) * rad,
            a2 = Math.max(startAngle, endAngle) * rad,
            singleSlice = false;

        x += margin * cos(midAngle);
        y += margin * sin(midAngle);

        x1 = x + opt.startRho * cos(a1);
        y1 = y + opt.startRho * sin(a1);

        x2 = x + opt.endRho * cos(a1);
        y2 = y + opt.endRho * sin(a1);

        x3 = x + opt.startRho * cos(a2);
        y3 = y + opt.startRho * sin(a2);

        x4 = x + opt.endRho * cos(a2);
        y4 = y + opt.endRho * sin(a2);

        if (abs(x1 - x3) <= delta && abs(y1 - y3) <= delta) {
            singleSlice = true;
        }
        
        if (singleSlice) {
            return {
                path: [
                ["M", x1, y1],
                ["L", x2, y2],
                ["A", opt.endRho, opt.endRho, 0, +flag, 1, x4, y4],
                ["Z"]]
            };
        } else {
            return {
                path: [
                ["M", x1, y1],
                ["L", x2, y2],
                ["A", opt.endRho, opt.endRho, 0, +flag, 1, x4, y4],
                ["L", x3, y3],
                ["A", opt.startRho, opt.startRho, 0, +flag, 0, x1, y1],
                ["Z"]]
            };
        }
    },

    
    calcMiddle: function(item) {
        var me = this,
            rad = me.rad,
            slice = item.slice,
            x = me.centerX,
            y = me.centerY,
            startAngle = slice.startAngle,
            endAngle = slice.endAngle,
            radius = Math.max(('rho' in slice) ? slice.rho: me.radius, me.label.minMargin),
            donut = +me.donut,
            a1 = Math.min(startAngle, endAngle) * rad,
            a2 = Math.max(startAngle, endAngle) * rad,
            midAngle = -(a1 + (a2 - a1) / 2),
            xm = x + (item.endRho + item.startRho) / 2 * Math.cos(midAngle),
            ym = y - (item.endRho + item.startRho) / 2 * Math.sin(midAngle);

        item.middle = {
            x: xm,
            y: ym
        };
    },

    
    drawSeries: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            group = me.group,
            animate = me.chart.animate,
            axis = me.chart.axes.get(0),
            minimum = axis && axis.minimum || me.minimum || 0,
            maximum = axis && axis.maximum || me.maximum || 0,
            field = me.angleField || me.field || me.xField,
            surface = chart.surface,
            chartBBox = chart.chartBBox,
            rad = me.rad,
            donut = +me.donut,
            values = {},
            items = [],
            seriesStyle = me.seriesStyle,
            seriesLabelStyle = me.seriesLabelStyle,
            colorArrayStyle = me.colorArrayStyle,
            colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
            gutterX = chart.maxGutter[0],
            gutterY = chart.maxGutter[1],
            cos = Math.cos,
            sin = Math.sin,
            rendererAttributes, centerX, centerY, slice, slices, sprite, value,
            item, ln, record, i, j, startAngle, endAngle, middleAngle, sliceLength, path,
            p, spriteOptions, bbox, splitAngle, sliceA, sliceB;
        
        Ext.apply(seriesStyle, me.style || {});

        me.setBBox();
        bbox = me.bbox;

        
        if (me.colorSet) {
            colorArrayStyle = me.colorSet;
            colorArrayLength = colorArrayStyle.length;
        }
        
        
        if (!store || !store.getCount() || me.seriesIsHidden) {
            me.hide();
            me.items = [];
            return;
        }
        
        centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
        centerY = me.centerY = chartBBox.y + chartBBox.height;
        me.radius = Math.min(centerX - chartBBox.x, centerY - chartBBox.y);
        me.slices = slices = [];
        me.items = items = [];
        
        if (!me.value) {
            record = store.getAt(0);
            me.value = record.get(field);
        }
        
        value = me.value;
        if (me.needle) {
            sliceA = {
                series: me,
                value: value,
                startAngle: -180,
                endAngle: 0,
                rho: me.radius
            };
            splitAngle = -180 * (1 - (value - minimum) / (maximum - minimum));
            slices.push(sliceA);
        } else {
            splitAngle = -180 * (1 - (value - minimum) / (maximum - minimum));
            sliceA = {
                series: me,
                value: value,
                startAngle: -180,
                endAngle: splitAngle,
                rho: me.radius
            };
            sliceB = {
                series: me,
                value: me.maximum - value,
                startAngle: splitAngle,
                endAngle: 0,
                rho: me.radius
            };
            slices.push(sliceA, sliceB);
        }
        
        
        for (i = 0, ln = slices.length; i < ln; i++) {
            slice = slices[i];
            sprite = group.getAt(i);
            
            rendererAttributes = Ext.apply({
                segment: {
                    startAngle: slice.startAngle,
                    endAngle: slice.endAngle,
                    margin: 0,
                    rho: slice.rho,
                    startRho: slice.rho * +donut / 100,
                    endRho: slice.rho
                } 
            }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[i % colorArrayLength] } || {}));

            item = Ext.apply({},
            rendererAttributes.segment, {
                slice: slice,
                series: me,
                storeItem: record,
                index: i
            });
            items[i] = item;
            
            if (!sprite) {
                spriteOptions = Ext.apply({
                    type: "path",
                    group: group
                }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[i % colorArrayLength] } || {}));
                sprite = surface.add(Ext.apply(spriteOptions, rendererAttributes));
            }
            slice.sprite = slice.sprite || [];
            item.sprite = sprite;
            slice.sprite.push(sprite);
            if (animate) {
                rendererAttributes = me.renderer(sprite, record, rendererAttributes, i, store);
                sprite._to = rendererAttributes;
                me.onAnimate(sprite, {
                    to: rendererAttributes
                });
            } else {
                rendererAttributes = me.renderer(sprite, record, Ext.apply(rendererAttributes, {
                    hidden: false
                }), i, store);
                sprite.setAttributes(rendererAttributes, true);
            }
        }
        
        if (me.needle) {
            splitAngle = splitAngle * Math.PI / 180;
            
            if (!me.needleSprite) {
                me.needleSprite = me.chart.surface.add({
                    type: 'path',
                    path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle),
                                centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)),
                           'L', centerX + me.radius * cos(splitAngle),
                                centerY + -Math.abs(me.radius * sin(splitAngle))],
                    'stroke-width': 4,
                    'stroke': '#222'
                });
            } else {
                if (animate) {
                    me.onAnimate(me.needleSprite, {
                        to: {
                        path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle),
                                    centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)),
                               'L', centerX + me.radius * cos(splitAngle),
                                    centerY + -Math.abs(me.radius * sin(splitAngle))]
                        }
                    });
                } else {
                    me.needleSprite.setAttributes({
                        type: 'path',
                        path: ['M', centerX + (me.radius * +donut / 100) * cos(splitAngle),
                                    centerY + -Math.abs((me.radius * +donut / 100) * sin(splitAngle)),
                               'L', centerX + me.radius * cos(splitAngle),
                                    centerY + -Math.abs(me.radius * sin(splitAngle))]
                    });
                }
            }
            me.needleSprite.setAttributes({
                hidden: false    
            }, true);
        }
        
        delete me.value;
    },
    
    
    setValue: function (value) {
        this.value = value;
        this.drawSeries();
    },

    
    onCreateLabel: function(storeItem, item, i, display) {},

    
    onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {},

    
    onPlaceCallout: function() {},

    
    onAnimate: function(sprite, attr) {
        sprite.show();
        return this.callParent(arguments);
    },

    isItemInPoint: function(x, y, item, i) {
        var me = this,
            cx = me.centerX,
            cy = me.centerY,
            abs = Math.abs,
            dx = abs(x - cx),
            dy = abs(y - cy),
            startAngle = item.startAngle,
            endAngle = item.endAngle,
            rho = Math.sqrt(dx * dx + dy * dy),
            angle = Math.atan2(y - cy, x - cx) / me.rad;

        
        return (i === 0) && (angle >= startAngle && angle < endAngle && 
                             rho >= item.startRho && rho <= item.endRho);
    },
    
    
    showAll: function() {
        if (!isNaN(this._index)) {
            this.__excludes[this._index] = false;
            this.drawSeries();
        }
    },
    
    
    getLegendColor: function(index) {
        var me = this;
        return me.colorArrayStyle[index % me.colorArrayStyle.length];
    }
});



Ext.define('Ext.chart.series.Line', {

    

    extend: 'Ext.chart.series.Cartesian',

    alternateClassName: ['Ext.chart.LineSeries', 'Ext.chart.LineChart'],

    requires: ['Ext.chart.axis.Axis', 'Ext.chart.Shape', 'Ext.draw.Draw', 'Ext.fx.Anim'],

    

    type: 'line',

    alias: 'series.line',

    

    
    selectionTolerance: 20,

    
    showMarkers: true,

    
    markerConfig: {},

    
    style: {},

    
    smooth: false,

    
    defaultSmoothness: 3,

    
    fill: false,

    constructor: function(config) {
        this.callParent(arguments);
        var me = this,
            surface = me.chart.surface,
            shadow = me.chart.shadow,
            i, l;
        config.highlightCfg = Ext.Object.merge({ 'stroke-width': 3 }, config.highlightCfg);
        Ext.apply(me, config, {
            shadowAttributes: [{
                "stroke-width": 6,
                "stroke-opacity": 0.05,
                stroke: 'rgb(0, 0, 0)',
                translate: {
                    x: 1,
                    y: 1
                }
            }, {
                "stroke-width": 4,
                "stroke-opacity": 0.1,
                stroke: 'rgb(0, 0, 0)',
                translate: {
                    x: 1,
                    y: 1
                }
            }, {
                "stroke-width": 2,
                "stroke-opacity": 0.15,
                stroke: 'rgb(0, 0, 0)',
                translate: {
                    x: 1,
                    y: 1
                }
            }]
        });
        me.group = surface.getGroup(me.seriesId);
        if (me.showMarkers) {
            me.markerGroup = surface.getGroup(me.seriesId + '-markers');
        }
        if (shadow) {
            for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
                me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
            }
        }
    },

    
    shrink: function(xValues, yValues, size) {
        
        var len = xValues.length,
            ratio = Math.floor(len / size),
            i = 1,
            xSum = 0,
            ySum = 0,
            xRes = [+xValues[0]],
            yRes = [+yValues[0]];

        for (; i < len; ++i) {
            xSum += +xValues[i] || 0;
            ySum += +yValues[i] || 0;
            if (i % ratio == 0) {
                xRes.push(xSum/ratio);
                yRes.push(ySum/ratio);
                xSum = 0;
                ySum = 0;
            }
        }
        return {
            x: xRes,
            y: yRes
        };
    },

    
    drawSeries: function() {
        var me = this,
            chart = me.chart,
            chartAxes = chart.axes,
            store = chart.getChartStore(),
            data = store.data.items,
            record,
            storeCount = store.getCount(),
            surface = me.chart.surface,
            bbox = {},
            group = me.group,
            showMarkers = me.showMarkers,
            markerGroup = me.markerGroup,
            enableShadows = chart.shadow,
            shadowGroups = me.shadowGroups,
            shadowAttributes = me.shadowAttributes,
            smooth = me.smooth,
            lnsh = shadowGroups.length,
            dummyPath = ["M"],
            path = ["M"],
            renderPath = ["M"],
            smoothPath = ["M"],
            markerIndex = chart.markerIndex,
            axes = [].concat(me.axis),
            shadowBarAttr,
            xValues = [],
            xValueMap = {},
            yValues = [],
            yValueMap = {},
            onbreak = false,
            storeIndices = [],
            markerStyle = me.markerStyle,
            seriesStyle = me.seriesStyle,
            colorArrayStyle = me.colorArrayStyle,
            colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
            isNumber = Ext.isNumber,
            seriesIdx = me.seriesIdx, 
            boundAxes = me.getAxesForXAndYFields(),
            boundXAxis = boundAxes.xAxis,
            boundYAxis = boundAxes.yAxis,
            shadows, shadow, shindex, fromPath, fill, fillPath, rendererAttributes,
            x, y, prevX, prevY, firstX, firstY, markerCount, i, j, ln, axis, ends, marker, markerAux, item, xValue,
            yValue, coords, xScale, yScale, minX, maxX, minY, maxY, line, animation, endMarkerStyle,
            endLineStyle, type, count, opacity, lineOpacity, fillOpacity, fillDefaultValue;

        if (me.fireEvent('beforedraw', me) === false) {
            return;
        }

        
        if (!storeCount || me.seriesIsHidden) {
            me.hide();
            me.items = [];
            if (me.line) {
                me.line.hide(true);
                if (me.line.shadows) {
                    shadows = me.line.shadows;
                    for (j = 0, lnsh = shadows.length; j < lnsh; j++) {
                        shadow = shadows[j];
                        shadow.hide(true);
                    }
                }
                if (me.fillPath) {
                    me.fillPath.hide(true);
                }
            }
            me.line = null;
            me.fillPath = null;
            return;
        }

        
        endMarkerStyle = Ext.apply(markerStyle || {}, me.markerConfig, {
            fill: me.seriesStyle.fill || colorArrayStyle[seriesIdx % colorArrayStyle.length]
        });
        type = endMarkerStyle.type;
        delete endMarkerStyle.type;
        endLineStyle = seriesStyle;
        
        
        if (!endLineStyle['stroke-width']) {
            endLineStyle['stroke-width'] = 0.5;
        }
        
        
        opacity = 'opacity' in endLineStyle ? endLineStyle.opacity : 1;
        fillDefaultValue = 'opacity' in endLineStyle ? endLineStyle.opacity : 0.3;
        lineOpacity = 'lineOpacity' in endLineStyle ? endLineStyle.lineOpacity : opacity;
        fillOpacity = 'fillOpacity' in endLineStyle ? endLineStyle.fillOpacity : fillDefaultValue;

        
        
        if (markerIndex && markerGroup && markerGroup.getCount()) {
            for (i = 0; i < markerIndex; i++) {
                marker = markerGroup.getAt(i);
                markerGroup.remove(marker);
                markerGroup.add(marker);
                markerAux = markerGroup.getAt(markerGroup.getCount() - 2);
                marker.setAttributes({
                    x: 0,
                    y: 0,
                    translate: {
                        x: markerAux.attr.translation.x,
                        y: markerAux.attr.translation.y
                    }
                }, true);
            }
        }

        me.unHighlightItem();
        me.cleanHighlights();

        me.setBBox();
        bbox = me.bbox;
        me.clipRect = [bbox.x, bbox.y, bbox.width, bbox.height];

        if (axis = chartAxes.get(boundXAxis)) {
            ends = axis.applyData();
            minX = ends.from;
            maxX = ends.to;
        }

        if (axis = chartAxes.get(boundYAxis)) {
            ends = axis.applyData();
            minY = ends.from;
            maxY = ends.to;
        }

        
        if (me.xField && !Ext.isNumber(minX)) {
            axis = me.getMinMaxXValues();
            minX = axis[0];
            maxX = axis[1];
        }

        if (me.yField && !Ext.isNumber(minY)) {
            axis = me.getMinMaxYValues();
            minY = axis[0];
            maxY = axis[1];
        }
        
        if (isNaN(minX)) {
            minX = 0;
            xScale = bbox.width / ((storeCount - 1) || 1);
        }
        else {
            xScale = bbox.width / ((maxX - minX) || (storeCount -1) || 1);
        }

        if (isNaN(minY)) {
            minY = 0;
            yScale = bbox.height / ((storeCount - 1) || 1);
        }
        else {
            yScale = bbox.height / ((maxY - minY) || (storeCount - 1) || 1);
        }
        
        for (i = 0, ln = data.length; i < ln; i++) {
            record = data[i];
            xValue = record.get(me.xField);

            
            if (typeof xValue == 'string' || typeof xValue == 'object' && !Ext.isDate(xValue)
                
                || boundXAxis && chartAxes.get(boundXAxis) && chartAxes.get(boundXAxis).type == 'Category') {
                    if (xValue in xValueMap) {
                        xValue = xValueMap[xValue];
                    } else {
                        xValue = xValueMap[xValue] = i;
                    }
            }

            
            yValue = record.get(me.yField);
            
            if (typeof yValue == 'undefined' || (typeof yValue == 'string' && !yValue)) {
                continue;
            }
            
            if (typeof yValue == 'string' || typeof yValue == 'object' && !Ext.isDate(yValue)
                
                || boundYAxis && chartAxes.get(boundYAxis) && chartAxes.get(boundYAxis).type == 'Category') {
                yValue = i;
            }
            storeIndices.push(i);
            xValues.push(xValue);
            yValues.push(yValue);
        }

        ln = xValues.length;
        if (ln > bbox.width) {
            coords = me.shrink(xValues, yValues, bbox.width);
            xValues = coords.x;
            yValues = coords.y;
        }

        me.items = [];

        count = 0;
        ln = xValues.length;
        for (i = 0; i < ln; i++) {
            xValue = xValues[i];
            yValue = yValues[i];
            if (yValue === false) {
                if (path.length == 1) {
                    path = [];
                }
                onbreak = true;
                me.items.push(false);
                continue;
            } else {
                x = (bbox.x + (xValue - minX) * xScale).toFixed(2);
                y = ((bbox.y + bbox.height) - (yValue - minY) * yScale).toFixed(2);
                if (onbreak) {
                    onbreak = false;
                    path.push('M');
                }
                path = path.concat([x, y]);
            }
            if ((typeof firstY == 'undefined') && (typeof y != 'undefined')) {
                firstY = y;
                firstX = x;
            }
            
            if (!me.line || chart.resizing) {
                dummyPath = dummyPath.concat([x, bbox.y + bbox.height / 2]);
            }

            
            if (chart.animate && chart.resizing && me.line) {
                me.line.setAttributes({
                    path: dummyPath,
                    opacity: lineOpacity
                }, true);
                if (me.fillPath) {
                    me.fillPath.setAttributes({
                        path: dummyPath,
                        opacity: fillOpacity
                    }, true);
                }
                if (me.line.shadows) {
                    shadows = me.line.shadows;
                    for (j = 0, lnsh = shadows.length; j < lnsh; j++) {
                        shadow = shadows[j];
                        shadow.setAttributes({
                            path: dummyPath
                        }, true);
                    }
                }
            }
            if (showMarkers) {
                marker = markerGroup.getAt(count++);
                if (!marker) {
                    marker = Ext.chart.Shape[type](surface, Ext.apply({
                        group: [group, markerGroup],
                        x: 0, y: 0,
                        translate: {
                            x: +(prevX || x),
                            y: prevY || (bbox.y + bbox.height / 2)
                        },
                        value: '"' + xValue + ', ' + yValue + '"',
                        zIndex: 4000
                    }, endMarkerStyle));
                    marker._to = {
                        translate: {
                            x: +x,
                            y: +y
                        }
                    };
                } else {
                    marker.setAttributes({
                        value: '"' + xValue + ', ' + yValue + '"',
                        x: 0, y: 0,
                        hidden: false
                    }, true);
                    marker._to = {
                        translate: {
                            x: +x, 
                            y: +y
                        }
                    };
                }
            }
            me.items.push({
                series: me,
                value: [xValue, yValue],
                point: [x, y],
                sprite: marker,
                storeItem: store.getAt(storeIndices[i])
            });
            prevX = x;
            prevY = y;
        }

        if (path.length <= 1) {
            
            return;
        }

        if (me.smooth) {
            smoothPath = Ext.draw.Draw.smooth(path, isNumber(smooth) ? smooth : me.defaultSmoothness);
        }

        renderPath = smooth ? smoothPath : path;

        
        if (chart.markerIndex && me.previousPath) {
            fromPath = me.previousPath;
            if (!smooth) {
                Ext.Array.erase(fromPath, 1, 2);
            }
        } else {
            fromPath = path;
        }

        
        if (!me.line) {
            me.line = surface.add(Ext.apply({
                type: 'path',
                group: group,
                path: dummyPath,
                stroke: endLineStyle.stroke || endLineStyle.fill
            }, endLineStyle || {}));

            
            me.line.setAttributes({
                opacity: lineOpacity
            }, true);

            if (enableShadows) {
                me.line.setAttributes(Ext.apply({}, me.shadowOptions), true);
            }

            
            me.line.setAttributes({
                fill: 'none',
                zIndex: 3000
            });
            if (!endLineStyle.stroke && colorArrayLength) {
                me.line.setAttributes({
                    stroke: colorArrayStyle[seriesIdx % colorArrayLength]
                }, true);
            }
            if (enableShadows) {
                
                shadows = me.line.shadows = [];
                for (shindex = 0; shindex < lnsh; shindex++) {
                    shadowBarAttr = shadowAttributes[shindex];
                    shadowBarAttr = Ext.apply({}, shadowBarAttr, { path: dummyPath });
                    shadow = surface.add(Ext.apply({}, {
                        type: 'path',
                        group: shadowGroups[shindex]
                    }, shadowBarAttr));
                    shadows.push(shadow);
                }
            }
        }
        if (me.fill) {
            fillPath = renderPath.concat([
                ["L", x, bbox.y + bbox.height],
                ["L", firstX, bbox.y + bbox.height],
                ["L", firstX, firstY]
            ]);
            if (!me.fillPath) {
                me.fillPath = surface.add({
                    group: group,
                    type: 'path',
                    fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength],
                    path: dummyPath
                });
            }
        }
        markerCount = showMarkers && markerGroup.getCount();
        if (chart.animate) {
            fill = me.fill;
            line = me.line;
            
            rendererAttributes = me.renderer(line, false, { path: renderPath }, i, store);
            Ext.apply(rendererAttributes, endLineStyle || {}, {
                stroke: endLineStyle.stroke || endLineStyle.fill
            });
            
            delete rendererAttributes.fill;
            line.show(true);
            if (chart.markerIndex && me.previousPath) {
                me.animation = animation = me.onAnimate(line, {
                    to: rendererAttributes,
                    from: {
                        path: fromPath
                    }
                });
            } else {
                me.animation = animation = me.onAnimate(line, {
                    to: rendererAttributes
                });
            }
            
            if (enableShadows) {
                shadows = line.shadows;
                for(j = 0; j < lnsh; j++) {
                    shadows[j].show(true);
                    if (chart.markerIndex && me.previousPath) {
                        me.onAnimate(shadows[j], {
                            to: { path: renderPath },
                            from: { path: fromPath }
                        });
                    } else {
                        me.onAnimate(shadows[j], {
                            to: { path: renderPath }
                        });
                    }
                }
            }
            
            if (fill) {
                me.fillPath.show(true);
                me.onAnimate(me.fillPath, {
                    to: Ext.apply({}, {
                        path: fillPath,
                        fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength],
                        'stroke-width': 0,
                        opacity: fillOpacity
                    }, endLineStyle || {})
                });
            }
            
            if (showMarkers) {
                count = 0;
                for(i = 0; i < ln; i++) {
                    if (me.items[i]) {
                        item = markerGroup.getAt(count++);
                        if (item) {
                            rendererAttributes = me.renderer(item, store.getAt(i), item._to, i, store);
                            me.onAnimate(item, {
                                to: Ext.apply(rendererAttributes, endMarkerStyle || {})
                            });
                            item.show(true);
                        }
                    }
                }
                for(; count < markerCount; count++) {
                    item = markerGroup.getAt(count);
                    item.hide(true);
                }




            }
        } else {
            rendererAttributes = me.renderer(me.line, false, { path: renderPath, hidden: false }, i, store);
            Ext.apply(rendererAttributes, endLineStyle || {}, {
                stroke: endLineStyle.stroke || endLineStyle.fill
            });
            
            delete rendererAttributes.fill;
            me.line.setAttributes(rendererAttributes, true);
            me.line.setAttributes({
                opacity: lineOpacity
            }, true);
            
            if (enableShadows) {
                shadows = me.line.shadows;
                for(j = 0; j < lnsh; j++) {
                    shadows[j].setAttributes({
                        path: renderPath,
                        hidden: false
                    }, true);
                }
            }
            if (me.fill) {
                me.fillPath.setAttributes({
                    path: fillPath,
                    hidden: false,
                    opacity: fillOpacity
                }, true);
            }
            if (showMarkers) {
                count = 0;
                for(i = 0; i < ln; i++) {
                    if (me.items[i]) {
                        item = markerGroup.getAt(count++);
                        if (item) {
                            rendererAttributes = me.renderer(item, store.getAt(i), item._to, i, store);
                            item.setAttributes(Ext.apply(endMarkerStyle || {}, rendererAttributes || {}), true);
                            if (!item.attr.hidden) {
                                item.show(true);
                            }
                        }
                    }
                }
                for(; count < markerCount; count++) {
                    item = markerGroup.getAt(count);
                    item.hide(true);
                }
            }
        }

        if (chart.markerIndex) {
            if (me.smooth) {
                Ext.Array.erase(path, 1, 2);
            } else {
                Ext.Array.splice(path, 1, 0, path[1], path[2]);
            }
            me.previousPath = path;
        }
        me.renderLabels();
        me.renderCallouts();

        me.fireEvent('draw', me);
    },

    
    onCreateLabel: function(storeItem, item, i, display) {
        var me = this,
            group = me.labelsGroup,
            config = me.label,
            bbox = me.bbox,
            endLabelStyle = Ext.apply(config, me.seriesLabelStyle);

        return me.chart.surface.add(Ext.apply({
            'type': 'text',
            'text-anchor': 'middle',
            'group': group,
            'x': item.point[0],
            'y': bbox.y + bbox.height / 2
        }, endLabelStyle || {}));
    },

    
    onPlaceLabel: function(label, storeItem, item, i, display, animate) {
        var me = this,
            chart = me.chart,
            resizing = chart.resizing,
            config = me.label,
            format = config.renderer,
            field = config.field,
            bbox = me.bbox,
            x = item.point[0],
            y = item.point[1],
            radius = item.sprite.attr.radius,
            bb, width, height;

        label.setAttributes({
            text: format(storeItem.get(field)),
            hidden: true
        }, true);

        if (display == 'rotate') {
            label.setAttributes({
                'text-anchor': 'start',
                'rotation': {
                    x: x,
                    y: y,
                    degrees: -45
                }
            }, true);
            
            bb = label.getBBox();
            width = bb.width;
            height = bb.height;
            x = x < bbox.x? bbox.x : x;
            x = (x + width > bbox.x + bbox.width)? (x - (x + width - bbox.x - bbox.width)) : x;
            y = (y - height < bbox.y)? bbox.y + height : y;

        } else if (display == 'under' || display == 'over') {
            
            bb = item.sprite.getBBox();
            bb.width = bb.width || (radius * 2);
            bb.height = bb.height || (radius * 2);
            y = y + (display == 'over'? -bb.height : bb.height);
            
            bb = label.getBBox();
            width = bb.width/2;
            height = bb.height/2;
            x = x - width < bbox.x? bbox.x + width : x;
            x = (x + width > bbox.x + bbox.width) ? (x - (x + width - bbox.x - bbox.width)) : x;
            y = y - height < bbox.y? bbox.y + height : y;
            y = (y + height > bbox.y + bbox.height) ? (y - (y + height - bbox.y - bbox.height)) : y;
        }

        if (me.chart.animate && !me.chart.resizing) {
            label.show(true);
            me.onAnimate(label, {
                to: {
                    x: x,
                    y: y
                }
            });
        } else {
            label.setAttributes({
                x: x,
                y: y
            }, true);
            if (resizing && me.animation) {
                me.animation.on('afteranimate', function() {
                    label.show(true);
                });
            } else {
                label.show(true);
            }
        }
    },

    
    highlightItem: function() {
        var me = this;
        me.callParent(arguments);
        if (me.line && !me.highlighted) {
            if (!('__strokeWidth' in me.line)) {
                me.line.__strokeWidth = parseFloat(me.line.attr['stroke-width']) || 0;
            }
            if (me.line.__anim) {
                me.line.__anim.paused = true;
            }
            me.line.__anim = Ext.create('Ext.fx.Anim', {
                target: me.line,
                to: {
                    'stroke-width': me.line.__strokeWidth + 3
                }
            });
            me.highlighted = true;
        }
    },

    
    unHighlightItem: function() {
        var me = this;
        me.callParent(arguments);
        if (me.line && me.highlighted) {
            me.line.__anim = Ext.create('Ext.fx.Anim', {
                target: me.line,
                to: {
                    'stroke-width': me.line.__strokeWidth
                }
            });
            me.highlighted = false;
        }
    },

    
    onPlaceCallout : function(callout, storeItem, item, i, display, animate, index) {
        if (!display) {
            return;
        }

        var me = this,
            chart = me.chart,
            surface = chart.surface,
            resizing = chart.resizing,
            config = me.callouts,
            items = me.items,
            prev = i == 0? false : items[i -1].point,
            next = (i == items.length -1)? false : items[i +1].point,
            cur = [+item.point[0], +item.point[1]],
            dir, norm, normal, a, aprev, anext,
            offsetFromViz = config.offsetFromViz || 30,
            offsetToSide = config.offsetToSide || 10,
            offsetBox = config.offsetBox || 3,
            boxx, boxy, boxw, boxh,
            p, clipRect = me.clipRect,
            bbox = {
                width: config.styles.width || 10,
                height: config.styles.height || 10
            },
            x, y;

        
        if (!prev) {
            prev = cur;
        }
        if (!next) {
            next = cur;
        }
        a = (next[1] - prev[1]) / (next[0] - prev[0]);
        aprev = (cur[1] - prev[1]) / (cur[0] - prev[0]);
        anext = (next[1] - cur[1]) / (next[0] - cur[0]);

        norm = Math.sqrt(1 + a * a);
        dir = [1 / norm, a / norm];
        normal = [-dir[1], dir[0]];

        
        if (aprev > 0 && anext < 0 && normal[1] < 0
            || aprev < 0 && anext > 0 && normal[1] > 0) {
            normal[0] *= -1;
            normal[1] *= -1;
        } else if (Math.abs(aprev) < Math.abs(anext) && normal[0] < 0
                   || Math.abs(aprev) > Math.abs(anext) && normal[0] > 0) {
            normal[0] *= -1;
            normal[1] *= -1;
        }
        
        x = cur[0] + normal[0] * offsetFromViz;
        y = cur[1] + normal[1] * offsetFromViz;

        
        boxx = x + (normal[0] > 0? 0 : -(bbox.width + 2 * offsetBox));
        boxy = y - bbox.height /2 - offsetBox;
        boxw = bbox.width + 2 * offsetBox;
        boxh = bbox.height + 2 * offsetBox;

        
        
        if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
            normal[0] *= -1;
        }
        if (boxy < clipRect[1] || (boxy + boxh) > (clipRect[1] + clipRect[3])) {
            normal[1] *= -1;
        }

        
        x = cur[0] + normal[0] * offsetFromViz;
        y = cur[1] + normal[1] * offsetFromViz;

        
        boxx = x + (normal[0] > 0? 0 : -(bbox.width + 2 * offsetBox));
        boxy = y - bbox.height /2 - offsetBox;
        boxw = bbox.width + 2 * offsetBox;
        boxh = bbox.height + 2 * offsetBox;

        if (chart.animate) {
            
            me.onAnimate(callout.lines, {
                to: {
                    path: ["M", cur[0], cur[1], "L", x, y, "Z"]
                }
            });
            
            if (callout.panel) {
                callout.panel.setPosition(boxx, boxy, true);
            }
        }
        else {
            
            callout.lines.setAttributes({
                path: ["M", cur[0], cur[1], "L", x, y, "Z"]
            }, true);
            
            if (callout.panel) {
                callout.panel.setPosition(boxx, boxy);
            }
        }
        for (p in callout) {
            callout[p].show(true);
        }
    },

    isItemInPoint: function(x, y, item, i) {
        var me = this,
            items = me.items,
            tolerance = me.selectionTolerance,
            result = null,
            prevItem,
            nextItem,
            prevPoint,
            nextPoint,
            ln,
            x1,
            y1,
            x2,
            y2,
            xIntersect,
            yIntersect,
            dist1, dist2, dist, midx, midy,
            sqrt = Math.sqrt, abs = Math.abs;

        nextItem = items[i];
        prevItem = i && items[i - 1];

        if (i >= ln) {
            prevItem = items[ln - 1];
        }
        prevPoint = prevItem && prevItem.point;
        nextPoint = nextItem && nextItem.point;
        x1 = prevItem ? prevPoint[0] : nextPoint[0] - tolerance;
        y1 = prevItem ? prevPoint[1] : nextPoint[1];
        x2 = nextItem ? nextPoint[0] : prevPoint[0] + tolerance;
        y2 = nextItem ? nextPoint[1] : prevPoint[1];
        dist1 = sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
        dist2 = sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
        dist = Math.min(dist1, dist2);

        if (dist <= tolerance) {
            return dist == dist1? prevItem : nextItem;
        }
        return false;
    },

    
    toggleAll: function(show) {
        var me = this,
            i, ln, shadow, shadows;
        if (!show) {
            Ext.chart.series.Cartesian.prototype.hideAll.call(me);
        }
        else {
            Ext.chart.series.Cartesian.prototype.showAll.call(me);
        }
        if (me.line) {
            me.line.setAttributes({
                hidden: !show
            }, true);
            
            if (me.line.shadows) {
                for (i = 0, shadows = me.line.shadows, ln = shadows.length; i < ln; i++) {
                    shadow = shadows[i];
                    shadow.setAttributes({
                        hidden: !show
                    }, true);
                }
            }
        }
        if (me.fillPath) {
            me.fillPath.setAttributes({
                hidden: !show
            }, true);
        }
    },

    
    hideAll: function() {
        this.toggleAll(false);
    },

    
    showAll: function() {
        this.toggleAll(true);
    }
});


Ext.define('Ext.chart.series.Pie', {

    

    alternateClassName: ['Ext.chart.PieSeries', 'Ext.chart.PieChart'],

    extend: 'Ext.chart.series.Series',

    

    type: "pie",

    alias: 'series.pie',

    accuracy: 100000,

    rad: Math.PI * 2 / 100000,

    
    highlightDuration: 150,

    
    angleField: false,

    

    

    
    lengthField: false,

    
    donut: false,

    
    showInLegend: false,

    

    
    style: {},

    constructor: function(config) {
        this.callParent(arguments);
        var me = this,
            chart = me.chart,
            surface = chart.surface,
            store = chart.store,
            shadow = chart.shadow, i, l, cfg;
        config.highlightCfg = Ext.merge({
            segment: {
                margin: 20
            }
        }, config.highlightCfg);
        Ext.apply(me, config, {
            shadowAttributes: [{
                "stroke-width": 6,
                "stroke-opacity": 1,
                stroke: 'rgb(200, 200, 200)',
                translate: {
                    x: 1.2,
                    y: 2
                }
            },
            {
                "stroke-width": 4,
                "stroke-opacity": 1,
                stroke: 'rgb(150, 150, 150)',
                translate: {
                    x: 0.9,
                    y: 1.5
                }
            },
            {
                "stroke-width": 2,
                "stroke-opacity": 1,
                stroke: 'rgb(100, 100, 100)',
                translate: {
                    x: 0.6,
                    y: 1
                }
            }]
        });
        me.group = surface.getGroup(me.seriesId);
        if (shadow) {
            for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
                me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
            }
        }
        surface.customAttributes.segment = function(opt) {
            
            
            
            var ans = me.getSegment(opt);
            if (!ans.path || ans.path.length === 0) {
                ans.path = ['M', 0, 0];
            }
            return ans;
        };
        me.__excludes = me.__excludes || [];
    },

    
    initialize: function() {
        var me = this,
            store = me.chart.getChartStore(),
            data = store.data.items,
            i, ln, rec;
        
        me.yField = [];
        if (me.label.field) {
            for (i = 0, ln = data.length; i < ln; i++) {
                rec = data[i];
                me.yField.push(rec.get(me.label.field));
            }
        }
    },

    
    getSegment: function(opt) {
        var me = this,
            rad = me.rad,
            cos = Math.cos,
            sin = Math.sin,
            x = me.centerX,
            y = me.centerY,
            x1 = 0, x2 = 0, x3 = 0, x4 = 0,
            y1 = 0, y2 = 0, y3 = 0, y4 = 0,
            x5 = 0, y5 = 0, x6 = 0, y6 = 0,
            delta = 1e-2,
            startAngle = opt.startAngle,
            endAngle = opt.endAngle,
            midAngle = (startAngle + endAngle) / 2 * rad,
            margin = opt.margin || 0,
            a1 = Math.min(startAngle, endAngle) * rad,
            a2 = Math.max(startAngle, endAngle) * rad,
            c1 = cos(a1), s1 = sin(a1),
            c2 = cos(a2), s2 = sin(a2),
            cm = cos(midAngle), sm = sin(midAngle),
            flag = 0, hsqr2 = 0.7071067811865476; 

        if (a2 - a1 < delta) {
            return {path: ""};
        }

        if (margin !== 0) {
            x += margin * cm;
            y += margin * sm;
        }

        x2 = x + opt.endRho * c1;
        y2 = y + opt.endRho * s1;

        x4 = x + opt.endRho * c2;
        y4 = y + opt.endRho * s2;

        x6 = x + opt.endRho * cm;
        y6 = y + opt.endRho * sm;

        if (opt.startRho !== 0) {
            x1 = x + opt.startRho * c1;
            y1 = y + opt.startRho * s1;
    
            x3 = x + opt.startRho * c2;
            y3 = y + opt.startRho * s2;
    
            x5 = x + opt.startRho * cm;
            y5 = y + opt.startRho * sm;

            return {
                path: [
                    ["M", x2, y2],
                    ["A", opt.endRho, opt.endRho, 0, 0, 1, x6, y6], ["L", x6, y6],
                    ["A", opt.endRho, opt.endRho, 0, flag, 1, x4, y4], ["L", x4, y4],
                    ["L", x3, y3],
                    ["A", opt.startRho, opt.startRho, 0, flag, 0, x5, y5], ["L", x5, y5],
                    ["A", opt.startRho, opt.startRho, 0, 0, 0, x1, y1], ["L", x1, y1],
                    ["Z"]
                ]
            };
        } else {
            return {
                path: [
                    ["M", x, y],
                    ["L", x2, y2],
                    ["A", opt.endRho, opt.endRho, 0, 0, 1, x6, y6], ["L", x6, y6],
                    ["A", opt.endRho, opt.endRho, 0, flag, 1, x4, y4], ["L", x4, y4],
                    ["L", x, y],
                    ["Z"]
                ]
            };
        }
    },

    
    calcMiddle: function(item) {
        var me = this,
            rad = me.rad,
            slice = item.slice,
            x = me.centerX,
            y = me.centerY,
            startAngle = slice.startAngle,
            endAngle = slice.endAngle,
            donut = +me.donut,
            midAngle = -(startAngle + endAngle) * rad / 2,
            r = (item.endRho + item.startRho) / 2,
            xm = x + r * Math.cos(midAngle),
            ym = y - r * Math.sin(midAngle);

        item.middle = {
            x: xm,
            y: ym
        };
    },

    
    drawSeries: function() {
        var me = this,
            store = me.chart.getChartStore(),
            data = store.data.items,
            record,
            group = me.group,
            animate = me.chart.animate,
            field = me.angleField || me.field || me.xField,
            lenField = [].concat(me.lengthField),
            totalLenField = 0,
            chart = me.chart,
            surface = chart.surface,
            chartBBox = chart.chartBBox,
            enableShadows = chart.shadow,
            shadowGroups = me.shadowGroups,
            shadowAttributes = me.shadowAttributes,
            lnsh = shadowGroups.length,
            layers = lenField.length,
            rhoAcum = 0,
            donut = +me.donut,
            layerTotals = [],
            items = [],
            totalField = 0,
            maxLenField = 0,
            angle = 0,
            seriesStyle = me.seriesStyle,
            colorArrayStyle = me.colorArrayStyle,
            colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
            rendererAttributes,
            shadowAttr,
            shadows,
            shadow,
            shindex,
            centerX,
            centerY,
            deltaRho,
            first = 0,
            slice,
            slices,
            sprite,
            value,
            item,
            lenValue,
            ln,
            i,
            j,
            endAngle,
            path,
            p,
            spriteOptions, bbox;

        Ext.apply(seriesStyle, me.style || {});

        me.setBBox();
        bbox = me.bbox;

        
        if (me.colorSet) {
            colorArrayStyle = me.colorSet;
            colorArrayLength = colorArrayStyle.length;
        }

        
        if (!store || !store.getCount() || me.seriesIsHidden) {
            me.hide();
            me.items = [];
            return;
        }

        me.unHighlightItem();
        me.cleanHighlights();

        centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
        centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
        me.radius = Math.min(centerX - chartBBox.x, centerY - chartBBox.y);
        me.slices = slices = [];
        me.items = items = [];

        for (i = 0, ln = data.length; i < ln; i++) {
            record = data[i];
            if (this.__excludes && this.__excludes[i]) {
                
                continue;
            }
            totalField += +record.get(field);
            if (lenField[0]) {
                for (j = 0, totalLenField = 0; j < layers; j++) {
                    totalLenField += +record.get(lenField[j]);
                }
                layerTotals[i] = totalLenField;
                maxLenField = Math.max(maxLenField, totalLenField);
            }
        }

        totalField = totalField || 1;
        for (i = 0, ln = data.length; i < ln; i++) {
            record = data[i];
            if (this.__excludes && this.__excludes[i]) {
                value = 0;
            } else {
                value = record.get(field);
                if (first == 0) {
                    first = 1;
                }
            }

            
            if (first == 1) {
                first = 2;
                me.firstAngle = angle = me.accuracy * value / totalField / 2;
                for (j = 0; j < i; j++) {
                    slices[j].startAngle = slices[j].endAngle = me.firstAngle;
                }
            }

            endAngle = angle - me.accuracy * value / totalField;
            slice = {
                series: me,
                value: value,
                startAngle: angle,
                endAngle: endAngle,
                storeItem: record
            };
            if (lenField[0]) {
                lenValue = +layerTotals[i];
                
                slice.rho = Math.floor(me.radius / maxLenField * lenValue);
            } else {
                slice.rho = me.radius;
            }
            slices[i] = slice;
            
            (function () {
                angle = endAngle;
            })();
        }

        
        if (enableShadows) {
            for (i = 0, ln = slices.length; i < ln; i++) {
                slice = slices[i];
                slice.shadowAttrs = [];
                for (j = 0, rhoAcum = 0, shadows = []; j < layers; j++) {
                    sprite = group.getAt(i * layers + j);
                    deltaRho = lenField[j] ? store.getAt(i).get(lenField[j]) / layerTotals[i] * slice.rho: slice.rho;
                    
                    rendererAttributes = {
                        segment: {
                            startAngle: slice.startAngle,
                            endAngle: slice.endAngle,
                            margin: 0,
                            rho: slice.rho,
                            startRho: rhoAcum + (deltaRho * donut / 100),
                            endRho: rhoAcum + deltaRho
                        },
                        hidden: !slice.value && (slice.startAngle % me.accuracy) == (slice.endAngle % me.accuracy)
                    };
                    
                    for (shindex = 0, shadows = []; shindex < lnsh; shindex++) {
                        shadowAttr = shadowAttributes[shindex];
                        shadow = shadowGroups[shindex].getAt(i);
                        if (!shadow) {
                            shadow = chart.surface.add(Ext.apply({}, {
                                type: 'path',
                                group: shadowGroups[shindex],
                                strokeLinejoin: "round"
                            }, rendererAttributes, shadowAttr));
                        }
                        shadowAttr = me.renderer(shadow, store.getAt(i), Ext.apply({}, rendererAttributes, shadowAttr), i, store);
                        if (animate) {
                            me.onAnimate(shadow, {
                                to: shadowAttr
                            });
                        } else {
                            shadow.setAttributes(shadowAttr, true);
                        }
                        shadows.push(shadow);
                    }
                    slice.shadowAttrs[j] = shadows;
                }
            }
        }
        
        for (i = 0, ln = slices.length; i < ln; i++) {
            slice = slices[i];
            for (j = 0, rhoAcum = 0; j < layers; j++) {
                sprite = group.getAt(i * layers + j);
                deltaRho = lenField[j] ? store.getAt(i).get(lenField[j]) / layerTotals[i] * slice.rho: slice.rho;
                
                rendererAttributes = Ext.apply({
                    segment: {
                        startAngle: slice.startAngle,
                        endAngle: slice.endAngle,
                        margin: 0,
                        rho: slice.rho,
                        startRho: rhoAcum + (deltaRho * donut / 100),
                        endRho: rhoAcum + deltaRho
                    },
                    hidden: (!slice.value && (slice.startAngle % me.accuracy) == (slice.endAngle % me.accuracy))
                }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[(layers > 1? j : i) % colorArrayLength] } || {}));
                item = Ext.apply({},
                rendererAttributes.segment, {
                    slice: slice,
                    series: me,
                    storeItem: slice.storeItem,
                    index: i
                });
                me.calcMiddle(item);
                if (enableShadows) {
                    item.shadows = slice.shadowAttrs[j];
                }
                items[i] = item;
                
                if (!sprite) {
                    spriteOptions = Ext.apply({
                        type: "path",
                        group: group,
                        middle: item.middle
                    }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[(layers > 1? j : i) % colorArrayLength] } || {}));
                    sprite = surface.add(Ext.apply(spriteOptions, rendererAttributes));
                }
                slice.sprite = slice.sprite || [];
                item.sprite = sprite;
                slice.sprite.push(sprite);
                slice.point = [item.middle.x, item.middle.y];
                if (animate) {
                    rendererAttributes = me.renderer(sprite, store.getAt(i), rendererAttributes, i, store);
                    sprite._to = rendererAttributes;
                    sprite._animating = true;
                    me.onAnimate(sprite, {
                        to: rendererAttributes,
                        listeners: {
                            afteranimate: {
                                fn: function() {
                                    this._animating = false;
                                },
                                scope: sprite
                            }
                        }
                    });
                } else {
                    rendererAttributes = me.renderer(sprite, store.getAt(i), Ext.apply(rendererAttributes, {
                        hidden: false
                    }), i, store);
                    sprite.setAttributes(rendererAttributes, true);
                }
                rhoAcum += deltaRho;
            }
        }

        
        ln = group.getCount();
        for (i = 0; i < ln; i++) {
            if (!slices[(i / layers) >> 0] && group.getAt(i)) {
                group.getAt(i).hide(true);
            }
        }
        if (enableShadows) {
            lnsh = shadowGroups.length;
            for (shindex = 0; shindex < ln; shindex++) {
                if (!slices[(shindex / layers) >> 0]) {
                    for (j = 0; j < lnsh; j++) {
                        if (shadowGroups[j].getAt(shindex)) {
                            shadowGroups[j].getAt(shindex).hide(true);
                        }
                    }
                }
            }
        }
        me.renderLabels();
        me.renderCallouts();
    },

    
    onCreateLabel: function(storeItem, item, i, display) {
        var me = this,
            group = me.labelsGroup,
            config = me.label,
            centerX = me.centerX,
            centerY = me.centerY,
            middle = item.middle,
            endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config || {});

        return me.chart.surface.add(Ext.apply({
            'type': 'text',
            'text-anchor': 'middle',
            'group': group,
            'x': middle.x,
            'y': middle.y
        }, endLabelStyle));
    },

    
    onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
        var me = this,
            chart = me.chart,
            resizing = chart.resizing,
            config = me.label,
            format = config.renderer,
            field = [].concat(config.field),
            centerX = me.centerX,
            centerY = me.centerY,
            middle = item.middle,
            opt = {
                x: middle.x,
                y: middle.y
            },
            x = middle.x - centerX,
            y = middle.y - centerY,
            from = {},
            rho = 1,
            theta = Math.atan2(y, x || 1),
            dg = theta * 180 / Math.PI,
            prevDg;

        opt.hidden = false;

        if (this.__excludes && this.__excludes[i]) {
            opt.hidden = true;
        }

        function fixAngle(a) {
            if (a < 0) {
                a += 360;
            }
            return a % 360;
        }

        label.setAttributes({
            text: format(storeItem.get(field[index]))
        }, true);

        switch (display) {
        case 'outside':
            rho = Math.sqrt(x * x + y * y) * 2;
            
            opt.x = rho * Math.cos(theta) + centerX;
            opt.y = rho * Math.sin(theta) + centerY;
            break;

        case 'rotate':
            dg = fixAngle(dg);
            dg = (dg > 90 && dg < 270) ? dg + 180: dg;

            prevDg = label.attr.rotation.degrees;
            if (prevDg != null && Math.abs(prevDg - dg) > 180 * 0.5) {
                if (dg > prevDg) {
                    dg -= 360;
                } else {
                    dg += 360;
                }
                dg = dg % 360;
            } else {
                dg = fixAngle(dg);
            }
            
            opt.rotate = {
                degrees: dg,
                x: opt.x,
                y: opt.y
            };
            break;

        default:
            break;
        }
        
        opt.translate = {
            x: 0, y: 0
        };
        if (animate && !resizing && (display != 'rotate' || prevDg != null)) {
            me.onAnimate(label, {
                to: opt
            });
        } else {
            label.setAttributes(opt, true);
        }
        label._from = from;
    },

    
    onPlaceCallout: function(callout, storeItem, item, i, display, animate, index) {
        var me = this,
            chart = me.chart,
            centerX = me.centerX,
            centerY = me.centerY,
            middle = item.middle,
            opt = {
                x: middle.x,
                y: middle.y
            },
            x = middle.x - centerX,
            y = middle.y - centerY,
            rho = 1,
            rhoCenter,
            theta = Math.atan2(y, x || 1),
            bbox = callout.label.getBBox(),
            offsetFromViz = 20,
            offsetToSide = 10,
            offsetBox = 10,
            p;

        
        rho = item.endRho + offsetFromViz;
        rhoCenter = (item.endRho + item.startRho) / 2 + (item.endRho - item.startRho) / 3;
        
        opt.x = rho * Math.cos(theta) + centerX;
        opt.y = rho * Math.sin(theta) + centerY;

        x = rhoCenter * Math.cos(theta);
        y = rhoCenter * Math.sin(theta);

        if (chart.animate) {
            
            me.onAnimate(callout.lines, {
                to: {
                    path: ["M", x + centerX, y + centerY, "L", opt.x, opt.y, "Z", "M", opt.x, opt.y, "l", x > 0 ? offsetToSide: -offsetToSide, 0, "z"]
                }
            });
            
            me.onAnimate(callout.box, {
                to: {
                    x: opt.x + (x > 0 ? offsetToSide: -(offsetToSide + bbox.width + 2 * offsetBox)),
                    y: opt.y + (y > 0 ? ( - bbox.height - offsetBox / 2) : ( - bbox.height - offsetBox / 2)),
                    width: bbox.width + 2 * offsetBox,
                    height: bbox.height + 2 * offsetBox
                }
            });
            
            me.onAnimate(callout.label, {
                to: {
                    x: opt.x + (x > 0 ? (offsetToSide + offsetBox) : -(offsetToSide + bbox.width + offsetBox)),
                    y: opt.y + (y > 0 ? -bbox.height / 4: -bbox.height / 4)
                }
            });
        } else {
            
            callout.lines.setAttributes({
                path: ["M", x + centerX, y + centerY, "L", opt.x, opt.y, "Z", "M", opt.x, opt.y, "l", x > 0 ? offsetToSide: -offsetToSide, 0, "z"]
            },
            true);
            
            callout.box.setAttributes({
                x: opt.x + (x > 0 ? offsetToSide: -(offsetToSide + bbox.width + 2 * offsetBox)),
                y: opt.y + (y > 0 ? ( - bbox.height - offsetBox / 2) : ( - bbox.height - offsetBox / 2)),
                width: bbox.width + 2 * offsetBox,
                height: bbox.height + 2 * offsetBox
            },
            true);
            
            callout.label.setAttributes({
                x: opt.x + (x > 0 ? (offsetToSide + offsetBox) : -(offsetToSide + bbox.width + offsetBox)),
                y: opt.y + (y > 0 ? -bbox.height / 4: -bbox.height / 4)
            },
            true);
        }
        for (p in callout) {
            callout[p].show(true);
        }
    },

    
    onAnimate: function(sprite, attr) {
        sprite.show();
        return this.callParent(arguments);
    },

    isItemInPoint: function(x, y, item, i) {
        var me = this,
            cx = me.centerX,
            cy = me.centerY,
            abs = Math.abs,
            dx = abs(x - cx),
            dy = abs(y - cy),
            startAngle = item.startAngle,
            endAngle = item.endAngle,
            rho = Math.sqrt(dx * dx + dy * dy),
            angle = Math.atan2(y - cy, x - cx) / me.rad;

        
        if (angle > me.firstAngle) {
            angle -= me.accuracy;
        }
        return (angle <= startAngle && angle > endAngle
                && rho >= item.startRho && rho <= item.endRho);
    },

    
    hideAll: function(index) {
        var i, l, shadow, shadows, sh, lsh, sprite;
        index = (isNaN(this._index) ? index : this._index) || 0;
        this.__excludes = this.__excludes || [];
        this.__excludes[index] = true;
        sprite = this.slices[index].sprite;
        for (sh = 0, lsh = sprite.length; sh < lsh; sh++) {
            sprite[sh].setAttributes({
                hidden: true
            }, true);
        }
        if (this.slices[index].shadowAttrs) {
            for (i = 0, shadows = this.slices[index].shadowAttrs, l = shadows.length; i < l; i++) {
                shadow = shadows[i];
                for (sh = 0, lsh = shadow.length; sh < lsh; sh++) {
                    shadow[sh].setAttributes({
                        hidden: true
                    }, true);
                }
            }
        }
        this.drawSeries();
    },

    
    showAll: function(index) {
        index = (isNaN(this._index) ? index : this._index) || 0;
        this.__excludes[index] = false;
        this.drawSeries();
    },

    
    highlightItem: function(item) {
        var me = this,
            rad = me.rad,
            highlightSegment,
            animate,
            attrs,
            i,
            shadows,
            shadow,
            ln,
            to,
            itemHighlightSegment,
            prop,
            group,
            display,
            label,
            middle,
            r,
            x,
            y;
        item = item || this.items[this._index];

        
        
        
        
        this.unHighlightItem();

        if (!item || me.animating || (item.sprite && item.sprite._animating)) {
            return;
        }
        me.callParent([item]);
        if (!me.highlight) {
            return;
        }
        if ('segment' in me.highlightCfg) {
            highlightSegment = me.highlightCfg.segment;
            animate = me.chart.animate;
            
            if (me.labelsGroup) {
                group = me.labelsGroup;
                display = me.label.display;
                label = group.getAt(item.index);
                middle = (item.startAngle + item.endAngle) / 2 * rad;
                r = highlightSegment.margin || 0;
                x = r * Math.cos(middle);
                y = r * Math.sin(middle);

                
                
                
                
                
                if (Math.abs(x) < 1e-10) {
                    x = 0;
                }
                if (Math.abs(y) < 1e-10) {
                    y = 0;
                }

                if (animate) {
                    label.stopAnimation();
                    label.animate({
                        to: {
                            translate: {
                                x: x,
                                y: y
                            }
                        },
                        duration: me.highlightDuration
                    });
                }
                else {
                    label.setAttributes({
                        translate: {
                            x: x,
                            y: y
                        }
                    }, true);
                }
            }
            
            if (me.chart.shadow && item.shadows) {
                i = 0;
                shadows = item.shadows;
                ln = shadows.length;
                for (; i < ln; i++) {
                    shadow = shadows[i];
                    to = {};
                    itemHighlightSegment = item.sprite._from.segment;
                    for (prop in itemHighlightSegment) {
                        if (! (prop in highlightSegment)) {
                            to[prop] = itemHighlightSegment[prop];
                        }
                    }
                    attrs = {
                        segment: Ext.applyIf(to, me.highlightCfg.segment)
                    };
                    if (animate) {
                        shadow.stopAnimation();
                        shadow.animate({
                            to: attrs,
                            duration: me.highlightDuration
                        });
                    }
                    else {
                        shadow.setAttributes(attrs, true);
                    }
                }
            }
        }
    },

    
    unHighlightItem: function() {
        var me = this,
            items,
            animate,
            shadowsEnabled,
            group,
            len,
            i,
            j,
            display,
            shadowLen,
            p,
            to,
            ihs,
            hs,
            sprite,
            shadows,
            shadow,
            item,
            label,
            attrs;
        if (!me.highlight) {
            return;
        }

        if (('segment' in me.highlightCfg) && me.items) {
            items = me.items;
            animate = me.chart.animate;
            shadowsEnabled = !!me.chart.shadow;
            group = me.labelsGroup;
            len = items.length;
            i = 0;
            j = 0;
            display = me.label.display;

            for (; i < len; i++) {
                item = items[i];
                if (!item) {
                    continue;
                }
                sprite = item.sprite;
                if (sprite && sprite._highlighted) {
                    
                    if (group) {
                        label = group.getAt(item.index);
                        attrs = Ext.apply({
                            translate: {
                                x: 0,
                                y: 0
                            }
                        },
                        display == 'rotate' ? {
                            rotate: {
                                x: label.attr.x,
                                y: label.attr.y,
                                degrees: label.attr.rotation.degrees
                            }
                        }: {});
                        if (animate) {
                            label.stopAnimation();
                            label.animate({
                                to: attrs,
                                duration: me.highlightDuration
                            });
                        }
                        else {
                            label.setAttributes(attrs, true);
                        }
                    }
                    if (shadowsEnabled) {
                        shadows = item.shadows;
                        shadowLen = shadows.length;
                        for (; j < shadowLen; j++) {
                            to = {};
                            ihs = item.sprite._to.segment;
                            hs = item.sprite._from.segment;
                            Ext.apply(to, hs);
                            for (p in ihs) {
                                if (! (p in hs)) {
                                    to[p] = ihs[p];
                                }
                            }
                            shadow = shadows[j];
                            if (animate) {
                                shadow.stopAnimation();
                                shadow.animate({
                                    to: {
                                        segment: to
                                    },
                                    duration: me.highlightDuration
                                });
                            }
                            else {
                                shadow.setAttributes({ segment: to }, true);
                            }
                        }
                    }
                }
            }
        }
        me.callParent(arguments);
    },

    
    getLegendColor: function(index) {
        var me = this;
        return (me.colorSet && me.colorSet[index % me.colorSet.length]) || me.colorArrayStyle[index % me.colorArrayStyle.length];
    }
});



Ext.define('Ext.chart.series.Radar', {

    

    extend: 'Ext.chart.series.Series',

    requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],

    

    type: "radar",
    alias: 'series.radar',


    rad: Math.PI / 180,

    showInLegend: false,

    
    style: {},

    constructor: function(config) {
        this.callParent(arguments);
        var me = this,
            surface = me.chart.surface, i, l;
        me.group = surface.getGroup(me.seriesId);
        if (me.showMarkers) {
            me.markerGroup = surface.getGroup(me.seriesId + '-markers');
        }
    },

    
    drawSeries: function() {
        var me = this,
            store = me.chart.getChartStore(),
            data = store.data.items,
            d, record,
            group = me.group,
            sprite,
            chart = me.chart,
            seriesItems = chart.series.items,
            s, sLen, series,
            animate = chart.animate,
            field = me.field || me.yField,
            surface = chart.surface,
            chartBBox = chart.chartBBox,
            seriesIdx = me.seriesIdx,
            colorArrayStyle = me.colorArrayStyle,
            centerX, centerY,
            items,
            radius,
            maxValue = 0,
            fields = [],
            max = Math.max,
            cos = Math.cos,
            sin = Math.sin,
            pi2 = Math.PI * 2,
            l = store.getCount(),
            startPath, path, x, y, rho,
            i, nfields,
            seriesStyle = me.seriesStyle,
            seriesLabelStyle = me.seriesLabelStyle,
            first = chart.resizing || !me.radar,
            axis = chart.axes && chart.axes.get(0),
            aggregate = !(axis && axis.maximum);

        me.setBBox();
        
        maxValue = aggregate? 0 : (axis.maximum || 0);
        
        Ext.apply(seriesStyle, me.style || {});

        
        if (!store || !store.getCount() || me.seriesIsHidden) {
            me.hide();
            me.items = [];
            if (me.radar) {
                me.radar.hide(true);
            }
            me.radar = null;
            return;
        }
        
        if(!seriesStyle['stroke']){
            seriesStyle['stroke'] = colorArrayStyle[seriesIdx % colorArrayStyle.length];
        }

        me.unHighlightItem();
        me.cleanHighlights();

        centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
        centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
        me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
        me.items = items = [];

        if (aggregate) {
            
            for (s = 0, sLen = seriesItems.length; s < sLen; s++) {
                series = seriesItems[s];
                fields.push(series.yField);
            }
            
            for (d = 0; d < l; d++) {
                record = data[d];
                for (i = 0, nfields = fields.length; i < nfields; i++) {
                    maxValue = max(+record.get(fields[i]), maxValue);
                }
            }
        }
        
        maxValue = maxValue || 1;
        
        startPath = []; path = [];
        for (i = 0; i < l; i++) {
            record = data[i];
            rho = radius * record.get(field) / maxValue;
            x = rho * cos(i / l * pi2);
            y = rho * sin(i / l * pi2);
            if (i == 0) {
                path.push('M', x + centerX, y + centerY);
                startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
            } else {
                path.push('L', x + centerX, y + centerY);
                startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
            }
            items.push({
                sprite: false, 
                point: [centerX + x, centerY + y],
                storeItem: record,
                series: me
            });
        }
        path.push('Z');
        
        if (!me.radar) {
            me.radar = surface.add(Ext.apply({
                type: 'path',
                group: group,
                path: startPath
            }, seriesStyle || {}));
        }
        
        if (chart.resizing) {
            me.radar.setAttributes({
                path: startPath
            }, true);
        }
        
        if (chart.animate) {
            me.onAnimate(me.radar, {
                to: Ext.apply({
                    path: path
                }, seriesStyle || {})
            });
        } else {
            me.radar.setAttributes(Ext.apply({
                path: path
            }, seriesStyle || {}), true);
        }
        
        if (me.showMarkers) {
            me.drawMarkers();
        }
        me.renderLabels();
        me.renderCallouts();
    },

    
    drawMarkers: function() {
        var me = this,
            chart = me.chart,
            surface = chart.surface,
            markerStyle = Ext.apply({}, me.markerStyle || {}),
            endMarkerStyle = Ext.apply(markerStyle, me.markerConfig, {
                fill: me.colorArrayStyle[me.seriesIdx % me.colorArrayStyle.length]
            }),
            items = me.items,
            type = endMarkerStyle.type,
            markerGroup = me.markerGroup,
            centerX = me.centerX,
            centerY = me.centerY,
            item, i, l, marker;
        delete endMarkerStyle.type;

        for (i = 0, l = items.length; i < l; i++) {
            item = items[i];
            marker = markerGroup.getAt(i);
            if (!marker) {
                marker = Ext.chart.Shape[type](surface, Ext.apply({
                    group: markerGroup,
                    x: 0,
                    y: 0,
                    translate: {
                        x: centerX,
                        y: centerY
                    }
                }, endMarkerStyle));
            }
            else {
                marker.show();
            }
            item.sprite = marker;
            if (chart.resizing) {
                marker.setAttributes({
                    x: 0,
                    y: 0,
                    translate: {
                        x: centerX,
                        y: centerY
                    }
                }, true);
            }
            marker._to = {
                translate: {
                    x: item.point[0],
                    y: item.point[1]
                }
            };
            
            if (chart.animate) {
                me.onAnimate(marker, {
                    to: marker._to
                });
            }
            else {
                marker.setAttributes(Ext.apply(marker._to, endMarkerStyle || {}), true);
            }
        }
    },

    isItemInPoint: function(x, y, item) {
        var point,
            tolerance = 10,
            abs = Math.abs;
        point = item.point;
        return (abs(point[0] - x) <= tolerance &&
                abs(point[1] - y) <= tolerance);
    },

    
    onCreateLabel: function(storeItem, item, i, display) {
        var me = this,
            group = me.labelsGroup,
            config = me.label,
            centerX = me.centerX,
            centerY = me.centerY,
            point = item.point,
            endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);

        return me.chart.surface.add(Ext.apply({
            'type': 'text',
            'text-anchor': 'middle',
            'group': group,
            'x': centerX,
            'y': centerY
        }, config || {}));
    },

    
    onPlaceLabel: function(label, storeItem, item, i, display, animate) {
        var me = this,
            chart = me.chart,
            resizing = chart.resizing,
            config = me.label,
            format = config.renderer,
            field = config.field,
            centerX = me.centerX,
            centerY = me.centerY,
            opt = {
                x: item.point[0],
                y: item.point[1]
            },
            x = opt.x - centerX,
            y = opt.y - centerY;

        label.setAttributes({
            text: format(storeItem.get(field)),
            hidden: true
        },
        true);

        if (resizing) {
            label.setAttributes({
                x: centerX,
                y: centerY
            }, true);
        }

        if (animate) {
            label.show(true);
            me.onAnimate(label, {
                to: opt
            });
        } else {
            label.setAttributes(opt, true);
            label.show(true);
        }
    },

    
    toggleAll: function(show) {
        var me = this,
            i, ln, shadow, shadows;
        if (!show) {
            Ext.chart.series.Radar.superclass.hideAll.call(me);
        }
        else {
            Ext.chart.series.Radar.superclass.showAll.call(me);
        }
        if (me.radar) {
            me.radar.setAttributes({
                hidden: !show
            }, true);
            
            if (me.radar.shadows) {
                for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i < ln; i++) {
                    shadow = shadows[i];
                    shadow.setAttributes({
                        hidden: !show
                    }, true);
                }
            }
        }
    },

    
    hideAll: function() {
        this.toggleAll(false);
        this.hideMarkers(0);
    },

    
    showAll: function() {
        this.toggleAll(true);
    },

    
    hideMarkers: function(index) {
        var me = this,
            count = me.markerGroup && me.markerGroup.getCount() || 0,
            i = index || 0;
        for (; i < count; i++) {
            me.markerGroup.getAt(i).hide(true);
        }
    }
});



Ext.define('Ext.chart.series.Scatter', {

    

    extend: 'Ext.chart.series.Cartesian',

    requires: ['Ext.chart.axis.Axis', 'Ext.chart.Shape', 'Ext.fx.Anim'],

    

    type: 'scatter',
    alias: 'series.scatter',

    

    
    
    

    constructor: function(config) {
        this.callParent(arguments);
        var me = this,
            shadow = me.chart.shadow,
            surface = me.chart.surface, i, l;
        Ext.apply(me, config, {
            style: {},
            markerConfig: {},
            shadowAttributes: [{
                "stroke-width": 6,
                "stroke-opacity": 0.05,
                stroke: 'rgb(0, 0, 0)'
            }, {
                "stroke-width": 4,
                "stroke-opacity": 0.1,
                stroke: 'rgb(0, 0, 0)'
            }, {
                "stroke-width": 2,
                "stroke-opacity": 0.15,
                stroke: 'rgb(0, 0, 0)'
            }]
        });
        me.group = surface.getGroup(me.seriesId);
        if (shadow) {
            for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
                me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
            }
        }
    },

    
    getBounds: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            chartAxes = chart.axes,
            boundAxes = me.getAxesForXAndYFields(),
            boundXAxis = boundAxes.xAxis,
            boundYAxis = boundAxes.yAxis,
            bbox, xScale, yScale, ln, minX, minY, maxX, maxY, i, axis, ends;

        me.setBBox();
        bbox = me.bbox;

        if (axis = chartAxes.get(boundXAxis)) {
            ends = axis.applyData();
            minX = ends.from;
            maxX = ends.to;
        }

        if (axis = chartAxes.get(boundYAxis)) {
            ends = axis.applyData();
            minY = ends.from;
            maxY = ends.to;
        }

        
        if (me.xField && !Ext.isNumber(minX)) {
            axis = me.getMinMaxXValues();
            minX = axis[0];
            maxX = axis[1];
        }

        if (me.yField && !Ext.isNumber(minY)) {
            axis = me.getMinMaxYValues();
            minY = axis[0];
            maxY = axis[1];
        }

        if (isNaN(minX)) {
            minX = 0;
            maxX = store.getCount() - 1;
            xScale = bbox.width / (store.getCount() - 1);
        }
        else {
            xScale = bbox.width / (maxX - minX);
        }

        if (isNaN(minY)) {
            minY = 0;
            maxY = store.getCount() - 1;
            yScale = bbox.height / (store.getCount() - 1);
        }
        else {
            yScale = bbox.height / (maxY - minY);
        }

        return {
            bbox: bbox,
            minX: minX,
            minY: minY,
            xScale: xScale,
            yScale: yScale
        };
    },

    
    getPaths: function() {
        var me = this,
            chart = me.chart,
            enableShadows = chart.shadow,
            store = chart.getChartStore(),
            data = store.data.items,
            i, ln, record,
            group = me.group,
            bounds = me.bounds = me.getBounds(),
            bbox = me.bbox,
            xScale = bounds.xScale,
            yScale = bounds.yScale,
            minX = bounds.minX,
            minY = bounds.minY,
            boxX = bbox.x,
            boxY = bbox.y,
            boxHeight = bbox.height,
            items = me.items = [],
            attrs = [],
            x, y, xValue, yValue, sprite;

        for (i = 0, ln = data.length; i < ln; i++) {
            record = data[i];
            xValue = record.get(me.xField);
            yValue = record.get(me.yField);
            
            if (typeof yValue == 'undefined' || (typeof yValue == 'string' && !yValue)
                || xValue == null || yValue == null) {
                continue;
            }
            
            if (typeof xValue == 'string' || typeof xValue == 'object' && !Ext.isDate(xValue)) {
                xValue = i;
            }
            if (typeof yValue == 'string' || typeof yValue == 'object' && !Ext.isDate(yValue)) {
                yValue = i;
            }
            x = boxX + (xValue - minX) * xScale;
            y = boxY + boxHeight - (yValue - minY) * yScale;
            attrs.push({
                x: x,
                y: y
            });

            me.items.push({
                series: me,
                value: [xValue, yValue],
                point: [x, y],
                storeItem: record
            });

            
            if (chart.animate && chart.resizing) {
                sprite = group.getAt(i);
                if (sprite) {
                    me.resetPoint(sprite);
                    if (enableShadows) {
                        me.resetShadow(sprite);
                    }
                }
            }
        }
        return attrs;
    },

    
    resetPoint: function(sprite) {
        var bbox = this.bbox;
        sprite.setAttributes({
            translate: {
                x: (bbox.x + bbox.width) / 2,
                y: (bbox.y + bbox.height) / 2
            }
        }, true);
    },

    
    resetShadow: function(sprite) {
        var me = this,
            shadows = sprite.shadows,
            shadowAttributes = me.shadowAttributes,
            ln = me.shadowGroups.length,
            bbox = me.bbox,
            i, attr;
        for (i = 0; i < ln; i++) {
            attr = Ext.apply({}, shadowAttributes[i]);
            
            if (attr.translate) {
                attr.translate.x += (bbox.x + bbox.width) / 2;
                attr.translate.y += (bbox.y + bbox.height) / 2;
            }
            else {
                attr.translate = {
                    x: (bbox.x + bbox.width) / 2,
                    y: (bbox.y + bbox.height) / 2
                };
            }
            shadows[i].setAttributes(attr, true);
        }
    },

    
    createPoint: function(attr, type) {
        var me = this,
            chart = me.chart,
            group = me.group,
            bbox = me.bbox;

        return Ext.chart.Shape[type](chart.surface, Ext.apply({}, {
            x: 0,
            y: 0,
            group: group,
            translate: {
                x: (bbox.x + bbox.width) / 2,
                y: (bbox.y + bbox.height) / 2
            }
        }, attr));
    },

    
    createShadow: function(sprite, endMarkerStyle, type) {
        var me = this,
            chart = me.chart,
            shadowGroups = me.shadowGroups,
            shadowAttributes = me.shadowAttributes,
            lnsh = shadowGroups.length,
            bbox = me.bbox,
            i, shadow, shadows, attr;

        sprite.shadows = shadows = [];

        for (i = 0; i < lnsh; i++) {
            attr = Ext.apply({}, shadowAttributes[i]);
            if (attr.translate) {
                attr.translate.x += (bbox.x + bbox.width) / 2;
                attr.translate.y += (bbox.y + bbox.height) / 2;
            }
            else {
                Ext.apply(attr, {
                    translate: {
                        x: (bbox.x + bbox.width) / 2,
                        y: (bbox.y + bbox.height) / 2
                    }
                });
            }
            Ext.apply(attr, endMarkerStyle);
            shadow = Ext.chart.Shape[type](chart.surface, Ext.apply({}, {
                x: 0,
                y: 0,
                group: shadowGroups[i]
            }, attr));
            shadows.push(shadow);
        }
    },

    
    drawSeries: function() {
        var me = this,
            chart = me.chart,
            store = chart.getChartStore(),
            group = me.group,
            enableShadows = chart.shadow,
            shadowGroups = me.shadowGroups,
            shadowAttributes = me.shadowAttributes,
            lnsh = shadowGroups.length,
            sprite, attrs, attr, ln, i, endMarkerStyle, shindex, type, shadows,
            rendererAttributes, shadowAttribute;

        endMarkerStyle = Ext.apply(me.markerStyle, me.markerConfig);
        type = endMarkerStyle.type;
        delete endMarkerStyle.type;

        
        if (!store || !store.getCount()) {
            me.hide();
            me.items = [];
            return;
        }


        me.unHighlightItem();
        me.cleanHighlights();

        attrs = me.getPaths();
        ln = attrs.length;
        for (i = 0; i < ln; i++) {
            attr = attrs[i];
            sprite = group.getAt(i);
            Ext.apply(attr, endMarkerStyle);

            
            if (!sprite) {
                sprite = me.createPoint(attr, type);
                if (enableShadows) {
                    me.createShadow(sprite, endMarkerStyle, type);
                }
            }

            shadows = sprite.shadows;
            if (chart.animate) {
                rendererAttributes = me.renderer(sprite, store.getAt(i), { translate: attr }, i, store);
                sprite._to = rendererAttributes;
                me.onAnimate(sprite, {
                    to: rendererAttributes
                });
                
                for (shindex = 0; shindex < lnsh; shindex++) {
                    shadowAttribute = Ext.apply({}, shadowAttributes[shindex]);
                    rendererAttributes = me.renderer(shadows[shindex], store.getAt(i), Ext.apply({}, { 
                        hidden: false,
                        translate: {
                            x: attr.x + (shadowAttribute.translate? shadowAttribute.translate.x : 0),
                            y: attr.y + (shadowAttribute.translate? shadowAttribute.translate.y : 0)
                        }
                    }, shadowAttribute), i, store);
                    me.onAnimate(shadows[shindex], { to: rendererAttributes });
                }
            }
            else {
                rendererAttributes = me.renderer(sprite, store.getAt(i), { translate: attr }, i, store);
                sprite._to = rendererAttributes;
                sprite.setAttributes(rendererAttributes, true);
                
                for (shindex = 0; shindex < lnsh; shindex++) {
                    shadowAttribute = Ext.apply({}, shadowAttributes[shindex]);
                    rendererAttributes = me.renderer(shadows[shindex], store.getAt(i), Ext.apply({}, { 
                        hidden: false,
                        translate: {
                            x: attr.x + (shadowAttribute.translate? shadowAttribute.translate.x : 0),
                            y: attr.y + (shadowAttribute.translate? shadowAttribute.translate.y : 0)
                        } 
                    }, shadowAttribute), i, store);
                    shadows[shindex].setAttributes(rendererAttributes, true);
                }
            }
            me.items[i].sprite = sprite;
        }

        
        ln = group.getCount();
        for (i = attrs.length; i < ln; i++) {
            group.getAt(i).hide(true);
        }
        me.renderLabels();
        me.renderCallouts();
    },

    
    onCreateLabel: function(storeItem, item, i, display) {
        var me = this,
            group = me.labelsGroup,
            config = me.label,
            endLabelStyle = Ext.apply({}, config, me.seriesLabelStyle),
            bbox = me.bbox;

        return me.chart.surface.add(Ext.apply({
            type: 'text',
            group: group,
            x: item.point[0],
            y: bbox.y + bbox.height / 2
        }, endLabelStyle));
    },

    
    onPlaceLabel: function(label, storeItem, item, i, display, animate) {
        var me = this,
            chart = me.chart,
            resizing = chart.resizing,
            config = me.label,
            format = config.renderer,
            field = config.field,
            bbox = me.bbox,
            x = item.point[0],
            y = item.point[1],
            radius = item.sprite.attr.radius,
            bb, width, height, anim;

        label.setAttributes({
            text: format(storeItem.get(field)),
            hidden: true
        }, true);

        if (display == 'rotate') {
            label.setAttributes({
                'text-anchor': 'start',
                'rotation': {
                    x: x,
                    y: y,
                    degrees: -45
                }
            }, true);
            
            bb = label.getBBox();
            width = bb.width;
            height = bb.height;
            x = x < bbox.x? bbox.x : x;
            x = (x + width > bbox.x + bbox.width)? (x - (x + width - bbox.x - bbox.width)) : x;
            y = (y - height < bbox.y)? bbox.y + height : y;

        } else if (display == 'under' || display == 'over') {
            
            bb = item.sprite.getBBox();
            bb.width = bb.width || (radius * 2);
            bb.height = bb.height || (radius * 2);
            y = y + (display == 'over'? -bb.height : bb.height);
            
            bb = label.getBBox();
            width = bb.width/2;
            height = bb.height/2;
            x = x - width < bbox.x ? bbox.x + width : x;
            x = (x + width > bbox.x + bbox.width) ? (x - (x + width - bbox.x - bbox.width)) : x;
            y = y - height < bbox.y? bbox.y + height : y;
            y = (y + height > bbox.y + bbox.height) ? (y - (y + height - bbox.y - bbox.height)) : y;
        }

        if (!chart.animate) {
            label.setAttributes({
                x: x,
                y: y
            }, true);
            label.show(true);
        }
        else {
            if (resizing) {
                anim = item.sprite.getActiveAnimation();
                if (anim) {
                    anim.on('afteranimate', function() {
                        label.setAttributes({
                            x: x,
                            y: y
                        }, true);
                        label.show(true);
                    });
                }
                else {
                    label.show(true);
                }
            }
            else {
                me.onAnimate(label, {
                    to: {
                        x: x,
                        y: y
                    }
                });
            }
        }
    },

    
    onPlaceCallout: function(callout, storeItem, item, i, display, animate, index) {
        var me = this,
            chart = me.chart,
            surface = chart.surface,
            resizing = chart.resizing,
            config = me.callouts,
            items = me.items,
            cur = item.point,
            normal,
            bbox = callout.label.getBBox(),
            offsetFromViz = 30,
            offsetToSide = 10,
            offsetBox = 3,
            boxx, boxy, boxw, boxh,
            p, clipRect = me.bbox,
            x, y;

        
        normal = [Math.cos(Math.PI /4), -Math.sin(Math.PI /4)];
        x = cur[0] + normal[0] * offsetFromViz;
        y = cur[1] + normal[1] * offsetFromViz;

        
        boxx = x + (normal[0] > 0? 0 : -(bbox.width + 2 * offsetBox));
        boxy = y - bbox.height /2 - offsetBox;
        boxw = bbox.width + 2 * offsetBox;
        boxh = bbox.height + 2 * offsetBox;

        
        
        if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
            normal[0] *= -1;
        }
        if (boxy < clipRect[1] || (boxy + boxh) > (clipRect[1] + clipRect[3])) {
            normal[1] *= -1;
        }

        
        x = cur[0] + normal[0] * offsetFromViz;
        y = cur[1] + normal[1] * offsetFromViz;

        
        boxx = x + (normal[0] > 0? 0 : -(bbox.width + 2 * offsetBox));
        boxy = y - bbox.height /2 - offsetBox;
        boxw = bbox.width + 2 * offsetBox;
        boxh = bbox.height + 2 * offsetBox;

        if (chart.animate) {
            
            me.onAnimate(callout.lines, {
                to: {
                    path: ["M", cur[0], cur[1], "L", x, y, "Z"]
                }
            }, true);
            
            me.onAnimate(callout.box, {
                to: {
                    x: boxx,
                    y: boxy,
                    width: boxw,
                    height: boxh
                }
            }, true);
            
            me.onAnimate(callout.label, {
                to: {
                    x: x + (normal[0] > 0? offsetBox : -(bbox.width + offsetBox)),
                    y: y
                }
            }, true);
        } else {
            
            callout.lines.setAttributes({
                path: ["M", cur[0], cur[1], "L", x, y, "Z"]
            }, true);
            
            callout.box.setAttributes({
                x: boxx,
                y: boxy,
                width: boxw,
                height: boxh
            }, true);
            
            callout.label.setAttributes({
                x: x + (normal[0] > 0? offsetBox : -(bbox.width + offsetBox)),
                y: y
            }, true);
        }
        for (p in callout) {
            callout[p].show(true);
        }
    },

    
    onAnimate: function(sprite, attr) {
        sprite.show();
        return this.callParent(arguments);
    },

    isItemInPoint: function(x, y, item) {
        var point,
            tolerance = 10,
            abs = Math.abs;

        function dist(point) {
            var dx = abs(point[0] - x),
                dy = abs(point[1] - y);
            return Math.sqrt(dx * dx + dy * dy);
        }
        point = item.point;
        return (point[0] - tolerance <= x && point[0] + tolerance >= x &&
            point[1] - tolerance <= y && point[1] + tolerance >= y);
    }
});



Ext.define('Ext.tip.QuickTip', {
    extend: 'Ext.tip.ToolTip',
    alias: 'widget.quicktip',
    alternateClassName: 'Ext.QuickTip',

    

    
    interceptTitles : false,

    
    title: '&#160;',

    
    tagConfig : {
        namespace : "data-",
        attribute : "qtip",
        width : "qwidth",
        target : "target",
        title : "qtitle",
        hide : "hide",
        cls : "qclass",
        align : "qalign",
        anchor : "anchor"
    },

    
    initComponent : function(){
        var me = this;

        me.target = me.target || Ext.getDoc();
        me.targets = me.targets || {};
        me.callParent();
    },

    
    register : function(config){
        var configs = Ext.isArray(config) ? config : arguments,
            i = 0,
            len = configs.length,
            target, j, targetLen;

        for (; i < len; i++) {
            config = configs[i];
            target = config.target;
            if (target) {
                if (Ext.isArray(target)) {
                    for (j = 0, targetLen = target.length; j < targetLen; j++) {
                        this.targets[Ext.id(target[j])] = config;
                    }
                } else{
                    this.targets[Ext.id(target)] = config;
                }
            }
        }
    },

    
    unregister : function(el){
        delete this.targets[Ext.id(el)];
    },

    
    cancelShow: function(el){
        var me = this,
            activeTarget = me.activeTarget;

        el = Ext.get(el).dom;
        if (me.isVisible()) {
            if (activeTarget && activeTarget.el == el) {
                me.hide();
            }
        } else if (activeTarget && activeTarget.el == el) {
            me.clearTimer('show');
        }
    },

    
    getTipCfg: function(e) {
        var t = e.getTarget(),
            titleText = t.title,
            cfg;

        if (this.interceptTitles && titleText && Ext.isString(titleText)) {
            t.qtip = titleText;
            t.removeAttribute("title");
            e.preventDefault();
            return {
                text: titleText
            };
        }
        else {
            cfg = this.tagConfig;
            t = e.getTarget('[' + cfg.namespace + cfg.attribute + ']');
            if (t) {
                return {
                    target: t,
                    text: t.getAttribute(cfg.namespace + cfg.attribute)
                };
            }
        }
    },

    
    onTargetOver : function(e){
        var me = this,
            target = e.getTarget(me.delegate),
            hasShowDelay,
            delay,
            elTarget,
            cfg,
            ns,
            tipConfig,
            autoHide,
            targets, targetEl, value, key;

        if (me.disabled) {
            return;
        }

        
        
        
        me.targetXY = e.getXY();

        
        if(!target || target.nodeType !== 1 || target == document.documentElement || target == document.body){
            return;
        }

        if (me.activeTarget && ((target == me.activeTarget.el) || Ext.fly(me.activeTarget.el).contains(target))) {
            me.clearTimer('hide');
            me.show();
            return;
        }

        if (target) {
            targets = me.targets;

            for (key in targets) {
                if (targets.hasOwnProperty(key)) {
                    value = targets[key];

                    targetEl = Ext.fly(value.target);
                    if (targetEl && (targetEl.dom === target || targetEl.contains(target))) {
                        elTarget = targetEl.dom;
                        break;
                    }
                }
            }

            if (elTarget) {
                me.activeTarget = me.targets[elTarget.id];
                me.activeTarget.el = target;
                me.anchor = me.activeTarget.anchor;
                if (me.anchor) {
                    me.anchorTarget = target;
                }
                hasShowDelay = Ext.isDefined(me.activeTarget.showDelay);
                if (hasShowDelay) {
                    delay = me.showDelay;
                    me.showDelay = me.activeTarget.showDelay;
                }
                me.delayShow();
                if (hasShowDelay) {
                    me.showDelay = delay;
                }
                return;
            }
        }

        
        elTarget = Ext.fly(target, '_quicktip-target');
        cfg = me.tagConfig;
        ns = cfg.namespace;
        tipConfig = me.getTipCfg(e);

        if (tipConfig) {

            
            
            if (tipConfig.target) {
                target = tipConfig.target;
                elTarget = Ext.fly(target, '_quicktip-target');
            }
            autoHide = elTarget.getAttribute(ns + cfg.hide);

            me.activeTarget = {
                el: target,
                text: tipConfig.text,
                width: +elTarget.getAttribute(ns + cfg.width) || null,
                autoHide: autoHide != "user" && autoHide !== 'false',
                title: elTarget.getAttribute(ns + cfg.title),
                cls: elTarget.getAttribute(ns + cfg.cls),
                align: elTarget.getAttribute(ns + cfg.align)

            };
            me.anchor = elTarget.getAttribute(ns + cfg.anchor);
            if (me.anchor) {
                me.anchorTarget = target;
            }
            hasShowDelay = Ext.isDefined(me.activeTarget.showDelay);
            if (hasShowDelay) {
                delay = me.showDelay;
                me.showDelay = me.activeTarget.showDelay;
            }
            me.delayShow();
            if (hasShowDelay) {
                me.showDelay = delay;
            }
        }
    },

    
    onTargetOut : function(e){
        var me = this,
            active = me.activeTarget,
            hasHideDelay,
            delay;

        
        
        if (active && e.within(me.activeTarget.el) && !me.getTipCfg(e)) {
            return;
        }

        me.clearTimer('show');
        delete me.activeTarget;
        if (me.autoHide !== false) {
            hasHideDelay = active && Ext.isDefined(active.hideDelay);
            if (hasHideDelay) {
                delay = me.hideDelay;
                me.hideDelay = active.hideDelay;
            }
            me.delayHide();
            if (hasHideDelay) {
                me.hideDelay = delay;
            }
        }
    },

    
    showAt : function(xy){
        var me = this,
            target = me.activeTarget,
            cls;

        if (target) {
            if (!me.rendered) {
                me.render(Ext.getBody());
                me.activeTarget = target;
            }
            me.suspendLayouts();
            if (target.title) {
                me.setTitle(target.title);
                me.header.show();
            } else {
                me.header.hide();
            }
            me.update(target.text);
            me.autoHide = target.autoHide;
            me.dismissDelay = target.dismissDelay || me.dismissDelay;
            if (target.mouseOffset) {
                xy[0] += target.mouseOffset[0];
                xy[1] += target.mouseOffset[1];
            }

            cls = me.lastCls;
            if (cls) {
                me.removeCls(cls);
                delete me.lastCls;
            }

            cls = target.cls;
            if (cls) {
                me.addCls(cls);
                me.lastCls = cls;
            }

            me.setWidth(target.width);

            if (me.anchor) {
                me.constrainPosition = false;
            } else if (target.align) { 
                xy = me.el.getAlignToXY(target.el, target.align);
                me.constrainPosition = false;
            }else{
                me.constrainPosition = true;
            }
            me.resumeLayouts(true);
        }
        me.callParent([xy]);
    },

    
    hide: function(){
        delete this.activeTarget;
        this.callParent();
    }
});

Ext.define('Ext.tip.QuickTipManager', (function() {
    var tip,
        disabled = false;

    return {
        requires: ['Ext.tip.QuickTip'],
        singleton: true,
        alternateClassName: 'Ext.QuickTips',

        
        init : function (autoRender, config) {
            if (!tip) {
                if (!Ext.isReady) {
                    Ext.onReady(function(){
                        Ext.tip.QuickTipManager.init(autoRender, config);
                    });
                    return;
                }

                var tipConfig = Ext.apply({ disabled: disabled, id: 'ext-quicktips-tip' }, config),
                    className = tipConfig.className,
                    xtype = tipConfig.xtype;

                if (className) {
                    delete tipConfig.className;
                } else if (xtype) {
                    className = 'widget.' + xtype;
                    delete tipConfig.xtype;
                }

                if (autoRender !== false) {
                    tipConfig.renderTo = document.body;

                }

                tip = Ext.create(className || 'Ext.tip.QuickTip', tipConfig);
            }
        },

        
        destroy: function() {
            if (tip) {
                var undef;
                tip.destroy();
                tip = undef;
            }
        },

        
        ddDisable : function(){
            
            if(tip && !disabled){
                tip.disable();
            }
        },

        
        ddEnable : function(){
            
            if(tip && !disabled){
                tip.enable();
            }
        },

        
        enable : function(){
            if(tip){
                tip.enable();
            }
            disabled = false;
        },

        
        disable : function(){
            if(tip){
                tip.disable();
            }
            disabled = true;
        },

        
        isEnabled : function(){
            return tip !== undefined && !tip.disabled;
        },

        
        getQuickTip : function(){
            return tip;
        },

        
        register : function(){
            tip.register.apply(tip, arguments);
        },

        
        unregister : function(){
            tip.unregister.apply(tip, arguments);
        },

        
        tips : function(){
            tip.register.apply(tip, arguments);
        }
    };
}()));

Ext.define('Ext.app.Application', {
    extend: 'Ext.app.Controller',

    requires: [
        'Ext.ModelManager',
        'Ext.data.Model',
        'Ext.data.StoreManager',
        'Ext.tip.QuickTipManager',
        'Ext.ComponentManager',
        'Ext.app.EventBus'
    ],

    

    

    
    scope: undefined,

    
    enableQuickTips: true,

    
    appFolder: 'app',

    
    autoCreateViewport: false,
    
    
    
    
    constructor: function(config) {
        config = config || {};
        Ext.apply(this, config);

        var me = this,
            requires = config.requires || [],
            controllers, ln, i, controller,
            paths, path, ns;

        Ext.Loader.setPath(me.name, me.appFolder);

        if (me.paths) {
            paths = me.paths;

            for (ns in paths) {
                if (paths.hasOwnProperty(ns)) {
                    path = paths[ns];

                    Ext.Loader.setPath(ns, path);
                }
            }
        }

        me.callParent(arguments);

        me.eventbus = new Ext.app.EventBus;

        controllers = Ext.Array.from(me.controllers);
        ln = controllers && controllers.length;

        me.controllers = new Ext.util.MixedCollection();

        if (me.autoCreateViewport) {
            requires.push(me.getModuleClassName('Viewport', 'view'));
        }

        for (i = 0; i < ln; i++) {
            requires.push(me.getModuleClassName(controllers[i], 'controller'));
        }

        Ext.require(requires);

        Ext.onReady(function() {
            me.init(me);
            for (i = 0; i < ln; i++) {
                controller = me.getController(controllers[i]);
                controller.init(me);
            }

            me.onBeforeLaunch.call(me);
        }, me);
    },

    control: function(selectors, listeners, controller) {
        this.eventbus.control(selectors, listeners, controller);
    },

    
    launch: Ext.emptyFn,

    
    onBeforeLaunch: function() {
        var me = this,
            controllers, c, cLen, controller;

        if (me.enableQuickTips) {
            Ext.tip.QuickTipManager.init();
        }

        if (me.autoCreateViewport) {
            me.getView('Viewport').create();
        }

        me.launch.call(this.scope || this);
        me.launched = true;
        me.fireEvent('launch', this);

        controllers = me.controllers.items;
        cLen        = controllers.length;

        for (c = 0; c < cLen; c++) {
            controller = controllers[c];
            controller.onLaunch(this);
        }
    },

    getModuleClassName: function(name, module) {
        
        
        
        
        
        
        
        if (name.indexOf('.') !== -1 && (Ext.ClassManager.isCreated(name) || Ext.Loader.isAClassNameWithAKnownPrefix(name))) {
            return name;
        } else {
            return this.name + '.' + module + '.' + name;
        }
    },

    getController: function(name) {
        var controller = this.controllers.get(name);

        if (!controller) {
            controller = Ext.create(this.getModuleClassName(name, 'controller'), {
                application: this,
                id: name
            });

            this.controllers.add(controller);
        }

        return controller;
    },

    getStore: function(name) {
        var store = Ext.StoreManager.get(name);

        if (!store) {
            store = Ext.create(this.getModuleClassName(name, 'store'), {
                storeId: name
            });
        }

        return store;
    },

    getModel: function(model) {
        model = this.getModuleClassName(model, 'model');

        return Ext.ModelManager.getModel(model);
    },

    getView: function(view) {
        view = this.getModuleClassName(view, 'view');

        return Ext.ClassManager.get(view);
    }
});


Ext.define('Ext.form.field.HtmlEditor', {
    extend:'Ext.Component',
    mixins: {
        labelable: 'Ext.form.Labelable',
        field: 'Ext.form.field.Field'
    },
    alias: 'widget.htmleditor',
    alternateClassName: 'Ext.form.HtmlEditor',
    requires: [
        'Ext.tip.QuickTipManager',
        'Ext.picker.Color',
        'Ext.toolbar.Item',
        'Ext.toolbar.Toolbar',
        'Ext.util.Format',
        'Ext.layout.component.field.HtmlEditor'
    ],

    childEls: [
        'iframeEl', 'textareaEl'
    ],

    fieldSubTpl: [
        '{beforeTextAreaTpl}',
        '<textarea id="{cmpId}-textareaEl" name="{name}" tabIndex="-1" {inputAttrTpl}',
                 ' class="{textareaCls}" style="{size}" autocomplete="off">',
            '{[Ext.util.Format.htmlEncode(values.value)]}',
        '</textarea>',
        '{afterTextAreaTpl}',
        '{beforeIFrameTpl}',
        '<iframe id="{cmpId}-iframeEl" name="{iframeName}" frameBorder="0" {iframeAttrTpl}',
               ' style="overflow:auto;{size}" src="{iframeSrc}"></iframe>',
        '{afterIFrameTpl}',
        {
            disableFormats: true
        }
    ],

    subTplInsertions: [
        
        'beforeTextAreaTpl',

        
        'afterTextAreaTpl',

        
        'beforeIFrameTpl',

        
        'afterIFrameTpl',

        
        'iframeAttrTpl',

        
        'inputAttrTpl'
    ],

    
    enableFormat : true,
    
    enableFontSize : true,
    
    enableColors : true,
    
    enableAlignments : true,
    
    enableLists : true,
    
    enableSourceEdit : true,
    
    enableLinks : true,
    
    enableFont : true,
    
    
    createLinkText : 'Please enter the URL for the link:',
    
    
    defaultLinkValue : 'http:/'+'/',
    
    fontFamilies : [
        'Arial',
        'Courier New',
        'Tahoma',
        'Times New Roman',
        'Verdana'
    ],
    defaultFont: 'tahoma',
    
    defaultValue: (Ext.isOpera || Ext.isIE6) ? '&#160;' : '&#8203;',

    editorWrapCls: Ext.baseCSSPrefix + 'html-editor-wrap',

    componentLayout: 'htmleditor',

    
    initialized : false,
    activated : false,
    sourceEditMode : false,
    iframePad:3,
    hideMode:'offsets',

    afterBodyEl: '</div>',

    maskOnDisable: true,

    
    initComponent : function(){
        var me = this;

        me.addEvents(
            
            'initialize',
            
            'activate',
             
            'beforesync',
             
            'beforepush',
             
            'sync',
             
            'push',
             
            'editmodechange'
        );

        me.callParent(arguments);
        me.createToolbar(me);

        
        me.initLabelable();
        me.initField();
    },

    
    getRefItems: function() {
        return [ this.toolbar ];
    },

    
    createToolbar : function(editor){
        var me = this,
            items = [], i,
            tipsEnabled = Ext.tip.QuickTipManager && Ext.tip.QuickTipManager.isEnabled(),
            baseCSSPrefix = Ext.baseCSSPrefix,
            fontSelectItem, toolbar, undef;

        function btn(id, toggle, handler){
            return {
                itemId : id,
                cls : baseCSSPrefix + 'btn-icon',
                iconCls: baseCSSPrefix + 'edit-'+id,
                enableToggle:toggle !== false,
                scope: editor,
                handler:handler||editor.relayBtnCmd,
                clickEvent: 'mousedown',
                tooltip: tipsEnabled ? editor.buttonTips[id] || undef : undef,
                overflowText: editor.buttonTips[id].title || undef,
                tabIndex: -1
            };
        }


        if (me.enableFont && !Ext.isSafari2) {
            fontSelectItem = Ext.widget('component', {
                renderTpl: [
                    '<select id="{id}-selectEl" class="{cls}">',
                        '<tpl for="fonts">',
                            '<option value="{[values.toLowerCase()]}" style="font-family:{.}"<tpl if="values.toLowerCase()==parent.defaultFont"> selected</tpl>>{.}</option>',
                        '</tpl>',
                    '</select>'
                ],
                renderData: {
                    cls: baseCSSPrefix + 'font-select',
                    fonts: me.fontFamilies,
                    defaultFont: me.defaultFont
                },
                childEls: ['selectEl'],
                afterRender: function() {
                    me.fontSelect = this.selectEl;
                    Ext.Component.prototype.afterRender.apply(this, arguments);
                },
                onDisable: function() {
                    var selectEl = this.selectEl;
                    if (selectEl) {
                        selectEl.dom.disabled = true;
                    }
                    Ext.Component.prototype.onDisable.apply(this, arguments);
                },
                onEnable: function() {
                    var selectEl = this.selectEl;
                    if (selectEl) {
                        selectEl.dom.disabled = false;
                    }
                    Ext.Component.prototype.onEnable.apply(this, arguments);
                },
                listeners: {
                    change: function() {
                        me.relayCmd('fontname', me.fontSelect.dom.value);
                        me.deferFocus();
                    },
                    element: 'selectEl'
                }
            });

            items.push(
                fontSelectItem,
                '-'
            );
        }

        if (me.enableFormat) {
            items.push(
                btn('bold'),
                btn('italic'),
                btn('underline')
            );
        }

        if (me.enableFontSize) {
            items.push(
                '-',
                btn('increasefontsize', false, me.adjustFont),
                btn('decreasefontsize', false, me.adjustFont)
            );
        }

        if (me.enableColors) {
            items.push(
                '-', {
                    itemId: 'forecolor',
                    cls: baseCSSPrefix + 'btn-icon',
                    iconCls: baseCSSPrefix + 'edit-forecolor',
                    overflowText: editor.buttonTips.forecolor.title,
                    tooltip: tipsEnabled ? editor.buttonTips.forecolor || undef : undef,
                    tabIndex:-1,
                    menu : Ext.widget('menu', {
                        plain: true,
                        items: [{
                            xtype: 'colorpicker',
                            allowReselect: true,
                            focus: Ext.emptyFn,
                            value: '000000',
                            plain: true,
                            clickEvent: 'mousedown',
                            handler: function(cp, color) {
                                me.execCmd('forecolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
                                me.deferFocus();
                                this.up('menu').hide();
                            }
                        }]
                    })
                }, {
                    itemId: 'backcolor',
                    cls: baseCSSPrefix + 'btn-icon',
                    iconCls: baseCSSPrefix + 'edit-backcolor',
                    overflowText: editor.buttonTips.backcolor.title,
                    tooltip: tipsEnabled ? editor.buttonTips.backcolor || undef : undef,
                    tabIndex:-1,
                    menu : Ext.widget('menu', {
                        plain: true,
                        items: [{
                            xtype: 'colorpicker',
                            focus: Ext.emptyFn,
                            value: 'FFFFFF',
                            plain: true,
                            allowReselect: true,
                            clickEvent: 'mousedown',
                            handler: function(cp, color) {
                                if (Ext.isGecko) {
                                    me.execCmd('useCSS', false);
                                    me.execCmd('hilitecolor', color);
                                    me.execCmd('useCSS', true);
                                    me.deferFocus();
                                } else {
                                    me.execCmd(Ext.isOpera ? 'hilitecolor' : 'backcolor', Ext.isWebKit || Ext.isIE ? '#'+color : color);
                                    me.deferFocus();
                                }
                                this.up('menu').hide();
                            }
                        }]
                    })
                }
            );
        }

        if (me.enableAlignments) {
            items.push(
                '-',
                btn('justifyleft'),
                btn('justifycenter'),
                btn('justifyright')
            );
        }

        if (!Ext.isSafari2) {
            if (me.enableLinks) {
                items.push(
                    '-',
                    btn('createlink', false, me.createLink)
                );
            }

            if (me.enableLists) {
                items.push(
                    '-',
                    btn('insertorderedlist'),
                    btn('insertunorderedlist')
                );
            }
            if (me.enableSourceEdit) {
                items.push(
                    '-',
                    btn('sourceedit', true, function(btn){
                        me.toggleSourceEdit(!me.sourceEditMode);
                    })
                );
            }
        }
        
        
        for (i = 0; i < items.length; i++) {
            if (items[i].itemId !== 'sourceedit') {
                items[i].disabled = true;
            }
        }

        
        
        toolbar = Ext.widget('toolbar', {
            id: me.id + '-toolbar',
            ownerCt: me,
            cls: Ext.baseCSSPrefix + 'html-editor-tb',
            enableOverflow: true,
            items: items,
            ownerLayout: me.getComponentLayout(),

            
            listeners: {
                click: function(e){
                    e.preventDefault();
                },
                element: 'el'
            }
        });

        me.toolbar = toolbar;
    },
    
    getMaskTarget: function(){
        return this.bodyEl;    
    },

    
    setReadOnly: function(readOnly) {
        var me = this,
            textareaEl = me.textareaEl,
            iframeEl = me.iframeEl,
            body;

        me.readOnly = readOnly;

        if (textareaEl) {
            textareaEl.dom.readOnly = readOnly;
        }

        if (me.initialized) {
            body = me.getEditorBody();
            if (Ext.isIE) {
                
                iframeEl.setDisplayed(false);
                body.contentEditable = !readOnly;
                iframeEl.setDisplayed(true);
            } else {
                me.setDesignMode(!readOnly);
            }
            if (body) {
                body.style.cursor = readOnly ? 'default' : 'text';
            }
            me.disableItems(readOnly);
        }
    },

    
    getDocMarkup: function() {
        var me = this,
            h = me.iframeEl.getHeight() - me.iframePad * 2;
        return Ext.String.format('<html><head><style type="text/css">body{border:0;margin:0;padding:{0}px;height:{1}px;box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;cursor:text}</style></head><body></body></html>', me.iframePad, h);
    },

    
    getEditorBody: function() {
        var doc = this.getDoc();
        return doc.body || doc.documentElement;
    },

    
    getDoc: function() {
        return (!Ext.isIE && this.iframeEl.dom.contentDocument) || this.getWin().document;
    },

    
    getWin: function() {
        return Ext.isIE ? this.iframeEl.dom.contentWindow : window.frames[this.iframeEl.dom.name];
    },

    
    
    finishRenderChildren: function () {
        this.callParent();
        this.toolbar.finishRender();
    },

    
    onRender: function() {
        var me = this;

        me.callParent(arguments);

        
        
        me.inputEl = me.iframeEl;

        
        me.monitorTask = Ext.TaskManager.start({
            run: me.checkDesignMode,
            scope: me,
            interval: 100
        });
    },

    initRenderTpl: function() {
        var me = this;
        if (!me.hasOwnProperty('renderTpl')) {
            me.renderTpl = me.getTpl('labelableRenderTpl');
        }
        return me.callParent();
    },

    initRenderData: function() {
        this.beforeSubTpl = '<div class="' + this.editorWrapCls + '">' + Ext.DomHelper.markup(this.toolbar.getRenderTree());
        return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
    },

    getSubTplData: function() {
        return {
            $comp       : this,
            cmpId       : this.id,
            id          : this.getInputId(),
            textareaCls : Ext.baseCSSPrefix + 'hidden',
            value       : this.value,
            iframeName  : Ext.id(),
            iframeSrc   : Ext.SSL_SECURE_URL,
            size        : 'height:100px;width:100%'
        };
    },

    getSubTplMarkup: function() {
        return this.getTpl('fieldSubTpl').apply(this.getSubTplData());
    },

    initFrameDoc: function() {
        var me = this,
            doc, task;

        Ext.TaskManager.stop(me.monitorTask);

        doc = me.getDoc();
        me.win = me.getWin();

        doc.open();
        doc.write(me.getDocMarkup());
        doc.close();

        task = { 
            run: function() {
                var doc = me.getDoc();
                if (doc.body || doc.readyState === 'complete') {
                    Ext.TaskManager.stop(task);
                    me.setDesignMode(true);
                    Ext.defer(me.initEditor, 10, me);
                }
            },
            interval : 10,
            duration:10000,
            scope: me
        };
        Ext.TaskManager.start(task);
    },

    checkDesignMode: function() {
        var me = this,
            doc = me.getDoc();
        if (doc && (!doc.editorInitialized || me.getDesignMode() !== 'on')) {
            me.initFrameDoc();
        }
    },

    
    setDesignMode: function(mode) {
        var me = this,
            doc = me.getDoc();
        if (doc) {
            if (me.readOnly) {
                mode = false;
            }
            doc.designMode = (/on|true/i).test(String(mode).toLowerCase()) ?'on':'off';
        }
    },

    
    getDesignMode: function() {
        var doc = this.getDoc();
        return !doc ? '' : String(doc.designMode).toLowerCase();
    },

    disableItems: function(disabled) {
        var items = this.getToolbar().items.items,
            i,
            iLen  = items.length,
            item;

        for (i = 0; i < iLen; i++) {
            item = items[i];

            if (item.getItemId() !== 'sourceedit') {
                item.setDisabled(disabled);
            }
        }
    },

    
    toggleSourceEdit: function(sourceEditMode) {
        var me = this,
            iframe = me.iframeEl,
            textarea = me.textareaEl,
            hiddenCls = Ext.baseCSSPrefix + 'hidden',
            btn = me.getToolbar().getComponent('sourceedit');

        if (!Ext.isBoolean(sourceEditMode)) {
            sourceEditMode = !me.sourceEditMode;
        }
        me.sourceEditMode = sourceEditMode;

        if (btn.pressed !== sourceEditMode) {
            btn.toggle(sourceEditMode);
        }
        if (sourceEditMode) {
            me.disableItems(true);
            me.syncValue();
            iframe.addCls(hiddenCls);
            textarea.removeCls(hiddenCls);
            textarea.dom.removeAttribute('tabIndex');
            textarea.focus();
            me.inputEl = textarea;
        }
        else {
            if (me.initialized) {
                me.disableItems(me.readOnly);
            }
            me.pushValue();
            iframe.removeCls(hiddenCls);
            textarea.addCls(hiddenCls);
            textarea.dom.setAttribute('tabIndex', -1);
            me.deferFocus();
            me.inputEl = iframe;
        }
        me.fireEvent('editmodechange', me, sourceEditMode);
        me.updateLayout();
    },

    
    createLink : function() {
        var url = prompt(this.createLinkText, this.defaultLinkValue);
        if (url && url !== 'http:/'+'/') {
            this.relayCmd('createlink', url);
        }
    },

    clearInvalid: Ext.emptyFn,

    
    setValue: function(value) {
        var me = this,
            textarea = me.textareaEl;
        me.mixins.field.setValue.call(me, value);
        if (value === null || value === undefined) {
            value = '';
        }
        if (textarea) {
            textarea.dom.value = value;
        }
        me.pushValue();
        return this;
    },

    
    cleanHtml: function(html) {
        html = String(html);
        if (Ext.isWebKit) { 
            html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
        }

        
        if (html.charCodeAt(0) === parseInt(this.defaultValue.replace(/\D/g, ''), 10)) {
            html = html.substring(1);
        }
        return html;
    },

    
    syncValue : function(){
        var me = this,
            body, changed, html, bodyStyle, match;

        if (me.initialized) {
            body = me.getEditorBody();
            html = body.innerHTML;
            if (Ext.isWebKit) {
                bodyStyle = body.getAttribute('style'); 
                match = bodyStyle.match(/text-align:(.*?);/i);
                if (match && match[1]) {
                    html = '<div style="' + match[0] + '">' + html + '</div>';
                }
            }
            html = me.cleanHtml(html);
            if (me.fireEvent('beforesync', me, html) !== false) {
                if (me.textareaEl.dom.value != html) {
                    me.textareaEl.dom.value = html;
                    changed = true;
                }

                me.fireEvent('sync', me, html);

                if (changed) {
                    
                    
                    me.checkChange();
                }
            }
        }
    },

    
    getValue : function() {
        var me = this,
            value;
        if (!me.sourceEditMode) {
            me.syncValue();
        }
        value = me.rendered ? me.textareaEl.dom.value : me.value;
        me.value = value;
        return value;
    },

    
    pushValue: function() {
        var me = this,
            v;
        if(me.initialized){
            v = me.textareaEl.dom.value || '';
            if (!me.activated && v.length < 1) {
                v = me.defaultValue;
            }
            if (me.fireEvent('beforepush', me, v) !== false) {
                me.getEditorBody().innerHTML = v;
                if (Ext.isGecko) {
                    
                    me.setDesignMode(false);  
                    me.setDesignMode(true);
                }
                me.fireEvent('push', me, v);
            }
        }
    },

    
    deferFocus : function(){
         this.focus(false, true);
    },

    getFocusEl: function() {
        var me = this,
            win = me.win;
        return win && !me.sourceEditMode ? win : me.textareaEl;
    },

    
    initEditor : function(){
        
        try {
            var me = this,
                dbody = me.getEditorBody(),
                ss = me.textareaEl.getStyles('font-size', 'font-family', 'background-image', 'background-repeat', 'background-color', 'color'),
                doc,
                fn;

            ss['background-attachment'] = 'fixed'; 
            dbody.bgProperties = 'fixed'; 

            Ext.DomHelper.applyStyles(dbody, ss);

            doc = me.getDoc();

            if (doc) {
                try {
                    Ext.EventManager.removeAll(doc);
                } catch(e) {}
            }

            
            fn = Ext.Function.bind(me.onEditorEvent, me);
            Ext.EventManager.on(doc, {
                mousedown: fn,
                dblclick: fn,
                click: fn,
                keyup: fn,
                buffer:100
            });

            
            
            
            
            
            fn = me.onRelayedEvent;
            Ext.EventManager.on(doc, {
                mousedown: fn, 
                mousemove: fn, 
                mouseup: fn,   
                click: fn,     
                dblclick: fn,  
                scope: me
            });

            if (Ext.isGecko) {
                Ext.EventManager.on(doc, 'keypress', me.applyCommand, me);
            }
            if (me.fixKeys) {
                Ext.EventManager.on(doc, 'keydown', me.fixKeys, me);
            }

            
            Ext.EventManager.on(window, 'unload', me.beforeDestroy, me);
            doc.editorInitialized = true;

            me.initialized = true;
            me.pushValue();
            me.setReadOnly(me.readOnly);
            me.fireEvent('initialize', me);
        } catch(ex) {
            
        }
    },

    
    beforeDestroy : function(){
        var me = this,
            monitorTask = me.monitorTask,
            doc, prop;

        if (monitorTask) {
            Ext.TaskManager.stop(monitorTask);
        }
        if (me.rendered) {
            try {
                doc = me.getDoc();
                if (doc) {
                    
                    
                    
                    
                    
                    Ext.EventManager.removeAll(Ext.fly(doc));
                    for (prop in doc) {
                        if (doc.hasOwnProperty && doc.hasOwnProperty(prop)) {
                            delete doc[prop];
                        }
                    }
                }
            } catch(e) {
                
            }
            Ext.destroyMembers(me, 'toolbar', 'iframeEl', 'textareaEl');
        }
        me.callParent();
    },

    
    onRelayedEvent: function (event) {
        

        var iframeEl = this.iframeEl,
            iframeXY = iframeEl.getXY(),
            eventXY = event.getXY();

        
        
        event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];

        event.injectEvent(iframeEl); 

        event.xy = eventXY; 
    },

    
    onFirstFocus : function(){
        var me = this,
            selection, range;
        me.activated = true;
        me.disableItems(me.readOnly);
        if (Ext.isGecko) { 
            me.win.focus();
            selection = me.win.getSelection();
            if (!selection.focusNode || selection.focusNode.nodeType !== 3) {
                range = selection.getRangeAt(0);
                range.selectNodeContents(me.getEditorBody());
                range.collapse(true);
                me.deferFocus();
            }
            try {
                me.execCmd('useCSS', true);
                me.execCmd('styleWithCSS', false);
            } catch(e) {
                
            }
        }
        me.fireEvent('activate', me);
    },

    
    adjustFont: function(btn) {
        var adjust = btn.getItemId() === 'increasefontsize' ? 1 : -1,
            size = this.getDoc().queryCommandValue('FontSize') || '2',
            isPxSize = Ext.isString(size) && size.indexOf('px') !== -1,
            isSafari;
        size = parseInt(size, 10);
        if (isPxSize) {
            
            
            if (size <= 10) {
                size = 1 + adjust;
            }
            else if (size <= 13) {
                size = 2 + adjust;
            }
            else if (size <= 16) {
                size = 3 + adjust;
            }
            else if (size <= 18) {
                size = 4 + adjust;
            }
            else if (size <= 24) {
                size = 5 + adjust;
            }
            else {
                size = 6 + adjust;
            }
            size = Ext.Number.constrain(size, 1, 6);
        } else {
            isSafari = Ext.isSafari;
            if (isSafari) { 
                adjust *= 2;
            }
            size = Math.max(1, size + adjust) + (isSafari ? 'px' : 0);
        }
        this.execCmd('FontSize', size);
    },

    
    onEditorEvent: function(e) {
        this.updateToolbar();
    },

    
    updateToolbar: function() {
        var me = this,
            btns, doc, name, fontSelect;

        if (me.readOnly) {
            return;
        }

        if (!me.activated) {
            me.onFirstFocus();
            return;
        }

        btns = me.getToolbar().items.map;
        doc = me.getDoc();

        if (me.enableFont && !Ext.isSafari2) {
            name = (doc.queryCommandValue('FontName') || me.defaultFont).toLowerCase();
            fontSelect = me.fontSelect.dom;
            if (name !== fontSelect.value) {
                fontSelect.value = name;
            }
        }

        function updateButtons() {
            for (var i = 0, l = arguments.length, name; i < l; i++) {
                name = arguments[i];
                btns[name].toggle(doc.queryCommandState(name));
            }
        }
        if(me.enableFormat){
            updateButtons('bold', 'italic', 'underline');
        }
        if(me.enableAlignments){
            updateButtons('justifyleft', 'justifycenter', 'justifyright');
        }
        if(!Ext.isSafari2 && me.enableLists){
            updateButtons('insertorderedlist', 'insertunorderedlist');
        }

        Ext.menu.Manager.hideAll();

        me.syncValue();
    },

    
    relayBtnCmd: function(btn) {
        this.relayCmd(btn.getItemId());
    },

    
    relayCmd: function(cmd, value) {
        Ext.defer(function() {
            var me = this;
            me.focus();
            me.execCmd(cmd, value);
            me.updateToolbar();
        }, 10, this);
    },

    
    execCmd : function(cmd, value){
        var me = this,
            doc = me.getDoc(),
            undef;
        doc.execCommand(cmd, false, value === undef ? null : value);
        me.syncValue();
    },

    
    applyCommand : function(e){
        if (e.ctrlKey) {
            var me = this,
                c = e.getCharCode(), cmd;
            if (c > 0) {
                c = String.fromCharCode(c);
                switch (c) {
                    case 'b':
                        cmd = 'bold';
                    break;
                    case 'i':
                        cmd = 'italic';
                    break;
                    case 'u':
                        cmd = 'underline';
                    break;
                }
                if (cmd) {
                    me.win.focus();
                    me.execCmd(cmd);
                    me.deferFocus();
                    e.preventDefault();
                }
            }
        }
    },

    
    insertAtCursor : function(text){
        var me = this,
            range;

        if (me.activated) {
            me.win.focus();
            if (Ext.isIE) {
                range = me.getDoc().selection.createRange();
                if (range) {
                    range.pasteHTML(text);
                    me.syncValue();
                    me.deferFocus();
                }
            }else{
                me.execCmd('InsertHTML', text);
                me.deferFocus();
            }
        }
    },

    
    fixKeys: (function() { 
        if (Ext.isIE) {
            return function(e){
                var me = this,
                    k = e.getKey(),
                    doc = me.getDoc(),
                    readOnly = me.readOnly,
                    range, target;

                if (k === e.TAB) {
                    e.stopEvent();
                    if (!readOnly) {
                        range = doc.selection.createRange();
                        if(range){
                            range.collapse(true);
                            range.pasteHTML('&#160;&#160;&#160;&#160;');
                            me.deferFocus();
                        }
                    }
                }
                else if (k === e.ENTER) {
                    if (!readOnly) {
                        range = doc.selection.createRange();
                        if (range) {
                            target = range.parentElement();
                            if(!target || target.tagName.toLowerCase() !== 'li'){
                                e.stopEvent();
                                range.pasteHTML('<br />');
                                range.collapse(false);
                                range.select();
                            }
                        }
                    }
                }
            };
        }

        if (Ext.isOpera) {
            return function(e){
                var me = this;
                if (e.getKey() === e.TAB) {
                    e.stopEvent();
                    if (!me.readOnly) {
                        me.win.focus();
                        me.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
                        me.deferFocus();
                    }
                }
            };
        }

        if (Ext.isWebKit) {
            return function(e){
                var me = this,
                    k = e.getKey(),
                    readOnly = me.readOnly;

                if (k === e.TAB) {
                    e.stopEvent();
                    if (!readOnly) {
                        me.execCmd('InsertText','\t');
                        me.deferFocus();
                    }
                }
                else if (k === e.ENTER) {
                    e.stopEvent();
                    if (!readOnly) {
                        me.execCmd('InsertHtml','<br /><br />');
                        me.deferFocus();
                    }
                }
            };
        }

        return null; 
    }()),

    
    getToolbar : function(){
        return this.toolbar;
    },

    
    
    buttonTips : {
        bold : {
            title: 'Bold (Ctrl+B)',
            text: 'Make the selected text bold.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        italic : {
            title: 'Italic (Ctrl+I)',
            text: 'Make the selected text italic.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        underline : {
            title: 'Underline (Ctrl+U)',
            text: 'Underline the selected text.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        increasefontsize : {
            title: 'Grow Text',
            text: 'Increase the font size.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        decreasefontsize : {
            title: 'Shrink Text',
            text: 'Decrease the font size.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        backcolor : {
            title: 'Text Highlight Color',
            text: 'Change the background color of the selected text.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        forecolor : {
            title: 'Font Color',
            text: 'Change the color of the selected text.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        justifyleft : {
            title: 'Align Text Left',
            text: 'Align text to the left.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        justifycenter : {
            title: 'Center Text',
            text: 'Center text in the editor.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        justifyright : {
            title: 'Align Text Right',
            text: 'Align text to the right.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        insertunorderedlist : {
            title: 'Bullet List',
            text: 'Start a bulleted list.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        insertorderedlist : {
            title: 'Numbered List',
            text: 'Start a numbered list.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        createlink : {
            title: 'Hyperlink',
            text: 'Make the selected text a hyperlink.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        },
        sourceedit : {
            title: 'Source Edit',
            text: 'Switch to source editing mode.',
            cls: Ext.baseCSSPrefix + 'html-editor-tip'
        }
    }
    

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
});


Ext.define('Ext.panel.Tool', {
    extend: 'Ext.Component',
    requires: ['Ext.tip.QuickTipManager'],
    alias: 'widget.tool',

    baseCls: Ext.baseCSSPrefix + 'tool',
    disabledCls: Ext.baseCSSPrefix + 'tool-disabled',
    
    
    toolPressedCls: Ext.baseCSSPrefix + 'tool-pressed',
    
    toolOverCls: Ext.baseCSSPrefix + 'tool-over',

    ariaRole: 'button',

    childEls: [
        'toolEl'
    ],

    renderTpl: [
        '<img id="{id}-toolEl" src="{blank}" class="{baseCls}-{type}" role="presentation"/>'
    ],

    

    

    

    

     
    tooltipType: 'qtip',

    
    stopEvent: true,
    
    height: 15,
    width: 15,


    initComponent: function() {
        var me = this;
        me.addEvents(
            
            'click'
        );


        me.type = me.type || me.id;

        Ext.applyIf(me.renderData, {
            baseCls: me.baseCls,
            blank: Ext.BLANK_IMAGE_URL,
            type: me.type
        });

        
        me.tooltip = me.tooltip || me.qtip;
        me.callParent();
        me.on({
            element: 'toolEl',
            click: me.onClick,
            mousedown: me.onMouseDown,
            mouseover: me.onMouseOver,
            mouseout: me.onMouseOut,
            scope: me
        });
    },

    
    afterRender: function() {
        var me = this,
            attr;

        me.callParent(arguments);
        if (me.tooltip) {
            if (Ext.isObject(me.tooltip)) {
                Ext.tip.QuickTipManager.register(Ext.apply({
                    target: me.id
                }, me.tooltip));
            }
            else {
                attr = me.tooltipType == 'qtip' ? 'data-qtip' : 'title';
                me.toolEl.dom.setAttribute(attr, me.tooltip);
            }
        }
    },

    getFocusEl: function() {
        return this.el;
    },

    
    setType: function(type) {
        var me = this;

        me.type = type;
        if (me.rendered) {
            me.toolEl.dom.className = me.baseCls + '-' + type;
        }
        return me;
    },

    
    bindTo: function(component) {
        this.owner = component;
    },

    
    onClick: function(e, target) {
        var me = this,
            owner;

        if (me.disabled) {
            return false;
        }
        owner = me.owner || me.ownerCt;

        
        me.el.removeCls(me.toolPressedCls);
        me.el.removeCls(me.toolOverCls);

        if (me.stopEvent !== false) {
            e.stopEvent();
        }

        Ext.callback(me.handler, me.scope || me, [e, target, owner, me]);
        me.fireEvent('click', me, e);
        return true;
    },

    
    onDestroy: function(){
        if (Ext.isObject(this.tooltip)) {
            Ext.tip.QuickTipManager.unregister(this.id);
        }
        this.callParent();
    },

    
    onMouseDown: function() {
        if (this.disabled) {
            return false;
        }

        this.el.addCls(this.toolPressedCls);
    },

    
    onMouseOver: function() {
        if (this.disabled) {
            return false;
        }
        this.el.addCls(this.toolOverCls);
    },

    
    onMouseOut: function() {
        this.el.removeCls(this.toolOverCls);
    }
});


Ext.define('Ext.toolbar.Paging', {
    extend: 'Ext.toolbar.Toolbar',
    alias: 'widget.pagingtoolbar',
    alternateClassName: 'Ext.PagingToolbar',
    requires: ['Ext.toolbar.TextItem', 'Ext.form.field.Number'],
    mixins: {
        bindable: 'Ext.util.Bindable'    
    },
    

    
    displayInfo: false,

    
    prependButtons: false,

    
    
    displayMsg : 'Displaying {0} - {1} of {2}',
    

    
    
    emptyMsg : 'No data to display',
    

    
    
    beforePageText : 'Page',
    

    
    
    afterPageText : 'of {0}',
    

    
    
    firstText : 'First Page',
    

    
    
    prevText : 'Previous Page',
    

    
    
    nextText : 'Next Page',
    

    
    
    lastText : 'Last Page',
    

    
    
    refreshText : 'Refresh',
    

    
    inputItemWidth : 30,

    
    getPagingItems: function() {
        var me = this;

        return [{
            itemId: 'first',
            tooltip: me.firstText,
            overflowText: me.firstText,
            iconCls: Ext.baseCSSPrefix + 'tbar-page-first',
            disabled: true,
            handler: me.moveFirst,
            scope: me
        },{
            itemId: 'prev',
            tooltip: me.prevText,
            overflowText: me.prevText,
            iconCls: Ext.baseCSSPrefix + 'tbar-page-prev',
            disabled: true,
            handler: me.movePrevious,
            scope: me
        },
        '-',
        me.beforePageText,
        {
            xtype: 'numberfield',
            itemId: 'inputItem',
            name: 'inputItem',
            cls: Ext.baseCSSPrefix + 'tbar-page-number',
            allowDecimals: false,
            minValue: 1,
            hideTrigger: true,
            enableKeyEvents: true,
            keyNavEnabled: false,
            selectOnFocus: true,
            submitValue: false,
            
            isFormField: false,
            width: me.inputItemWidth,
            margins: '-1 2 3 2',
            listeners: {
                scope: me,
                keydown: me.onPagingKeyDown,
                blur: me.onPagingBlur
            }
        },{
            xtype: 'tbtext',
            itemId: 'afterTextItem',
            text: Ext.String.format(me.afterPageText, 1)
        },
        '-',
        {
            itemId: 'next',
            tooltip: me.nextText,
            overflowText: me.nextText,
            iconCls: Ext.baseCSSPrefix + 'tbar-page-next',
            disabled: true,
            handler: me.moveNext,
            scope: me
        },{
            itemId: 'last',
            tooltip: me.lastText,
            overflowText: me.lastText,
            iconCls: Ext.baseCSSPrefix + 'tbar-page-last',
            disabled: true,
            handler: me.moveLast,
            scope: me
        },
        '-',
        {
            itemId: 'refresh',
            tooltip: me.refreshText,
            overflowText: me.refreshText,
            iconCls: Ext.baseCSSPrefix + 'tbar-loading',
            handler: me.doRefresh,
            scope: me
        }];
    },

    initComponent : function(){
        var me = this,
            pagingItems = me.getPagingItems(),
            userItems   = me.items || me.buttons || [];

        if (me.prependButtons) {
            me.items = userItems.concat(pagingItems);
        } else {
            me.items = pagingItems.concat(userItems);
        }
        delete me.buttons;

        if (me.displayInfo) {
            me.items.push('->');
            me.items.push({xtype: 'tbtext', itemId: 'displayItem'});
        }

        me.callParent();

        me.addEvents(
            
            'change',

            
            'beforechange'
        );
        me.on('beforerender', me.onLoad, me, {single: true});

        me.bindStore(me.store || 'ext-empty-store', true);
    },
    
    updateInfo : function(){
        var me = this,
            displayItem = me.child('#displayItem'),
            store = me.store,
            pageData = me.getPageData(),
            count, msg;

        if (displayItem) {
            count = store.getCount();
            if (count === 0) {
                msg = me.emptyMsg;
            } else {
                msg = Ext.String.format(
                    me.displayMsg,
                    pageData.fromRecord,
                    pageData.toRecord,
                    pageData.total
                );
            }
            displayItem.setText(msg);
        }
    },

    
    onLoad : function(){
        var me = this,
            pageData,
            currPage,
            pageCount,
            afterText,
            count,
            isEmpty;

        count = me.store.getCount();
        isEmpty = count === 0;
        if (!isEmpty) {
            pageData = me.getPageData();
            currPage = pageData.currentPage;
            pageCount = pageData.pageCount;
            afterText = Ext.String.format(me.afterPageText, isNaN(pageCount) ? 1 : pageCount);
        } else {
            currPage = 0;
            pageCount = 0;
            afterText = Ext.String.format(me.afterPageText, 0);
        }

        Ext.suspendLayouts();
        me.child('#afterTextItem').setText(afterText);
        me.child('#inputItem').setDisabled(isEmpty).setValue(currPage);
        me.child('#first').setDisabled(currPage === 1 || isEmpty);
        me.child('#prev').setDisabled(currPage === 1  || isEmpty);
        me.child('#next').setDisabled(currPage === pageCount  || isEmpty);
        me.child('#last').setDisabled(currPage === pageCount  || isEmpty);
        me.child('#refresh').enable();
        me.updateInfo();
        Ext.resumeLayouts(true);

        if (me.rendered) {
            me.fireEvent('change', me, pageData);
        }
    },

    
    getPageData : function(){
        var store = this.store,
            totalCount = store.getTotalCount();

        return {
            total : totalCount,
            currentPage : store.currentPage,
            pageCount: Math.ceil(totalCount / store.pageSize),
            fromRecord: ((store.currentPage - 1) * store.pageSize) + 1,
            toRecord: Math.min(store.currentPage * store.pageSize, totalCount)

        };
    },

    
    onLoadError : function(){
        if (!this.rendered) {
            return;
        }
        this.child('#refresh').enable();
    },

    
    readPageFromInput : function(pageData){
        var v = this.child('#inputItem').getValue(),
            pageNum = parseInt(v, 10);

        if (!v || isNaN(pageNum)) {
            this.child('#inputItem').setValue(pageData.currentPage);
            return false;
        }
        return pageNum;
    },

    onPagingFocus : function(){
        this.child('#inputItem').select();
    },

    
    onPagingBlur : function(e){
        var curPage = this.getPageData().currentPage;
        this.child('#inputItem').setValue(curPage);
    },

    
    onPagingKeyDown : function(field, e){
        var me = this,
            k = e.getKey(),
            pageData = me.getPageData(),
            increment = e.shiftKey ? 10 : 1,
            pageNum;

        if (k == e.RETURN) {
            e.stopEvent();
            pageNum = me.readPageFromInput(pageData);
            if (pageNum !== false) {
                pageNum = Math.min(Math.max(1, pageNum), pageData.pageCount);
                if(me.fireEvent('beforechange', me, pageNum) !== false){
                    me.store.loadPage(pageNum);
                }
            }
        } else if (k == e.HOME || k == e.END) {
            e.stopEvent();
            pageNum = k == e.HOME ? 1 : pageData.pageCount;
            field.setValue(pageNum);
        } else if (k == e.UP || k == e.PAGE_UP || k == e.DOWN || k == e.PAGE_DOWN) {
            e.stopEvent();
            pageNum = me.readPageFromInput(pageData);
            if (pageNum) {
                if (k == e.DOWN || k == e.PAGE_DOWN) {
                    increment *= -1;
                }
                pageNum += increment;
                if (pageNum >= 1 && pageNum <= pageData.pageCount) {
                    field.setValue(pageNum);
                }
            }
        }
    },

    
    beforeLoad : function(){
        if(this.rendered && this.refresh){
            this.refresh.disable();
        }
    },

    
    moveFirst : function(){
        if (this.fireEvent('beforechange', this, 1) !== false){
            this.store.loadPage(1);
        }
    },

    
    movePrevious : function(){
        var me = this,
            prev = me.store.currentPage - 1;

        if (prev > 0) {
            if (me.fireEvent('beforechange', me, prev) !== false) {
                me.store.previousPage();
            }
        }
    },

    
    moveNext : function(){
        var me = this,
            total = me.getPageData().pageCount,
            next = me.store.currentPage + 1;

        if (next <= total) {
            if (me.fireEvent('beforechange', me, next) !== false) {
                me.store.nextPage();
            }
        }
    },

    
    moveLast : function(){
        var me = this,
            last = me.getPageData().pageCount;

        if (me.fireEvent('beforechange', me, last) !== false) {
            me.store.loadPage(last);
        }
    },

    
    doRefresh : function(){
        var me = this,
            current = me.store.currentPage;

        if (me.fireEvent('beforechange', me, current) !== false) {
            me.store.loadPage(current);
        }
    },
    
    getStoreListeners: function() {
        return {
            beforeload: this.beforeLoad,
            load: this.onLoad,
            exception: this.onLoadError
        };
    },

    
    unbind : function(store){
        this.bindStore(null);
    },

    
    bind : function(store){
        this.bindStore(store);
    },

    
    onDestroy : function(){
        this.unbind();
        this.callParent();
    }
});


Ext.define('Ext.tree.Column', {
    extend: 'Ext.grid.column.Column',
    alias: 'widget.treecolumn',

    tdCls: Ext.baseCSSPrefix + 'grid-cell-treecolumn',
    
    treePrefix: Ext.baseCSSPrefix + 'tree-',
    elbowPrefix: Ext.baseCSSPrefix + 'tree-elbow-',
    expanderCls: Ext.baseCSSPrefix + 'tree-expander',
    imgText: '<img src="{1}" class="{0}" />',
    checkboxText: '<input type="button" role="checkbox" class="{0}" {1} />',

    initComponent: function() {
        var me = this;
        
        me.origRenderer = me.renderer || me.defaultRenderer;
        me.origScope = me.scope || window;

        me.renderer = me.treeRenderer;
        me.scope = me;
        
        me.callParent();
    },
    
    treeRenderer: function(value, metaData, record, rowIdx, colIdx, store, view){
        var me = this,
            buf = [],
            format = Ext.String.format,
            depth = record.getDepth(),
            treePrefix  = me.treePrefix,
            elbowPrefix = me.elbowPrefix,
            expanderCls = me.expanderCls,
            imgText     = me.imgText,
            checkboxText= me.checkboxText,
            formattedValue = me.origRenderer.apply(me.origScope, arguments),
            blank = Ext.BLANK_IMAGE_URL,
            href = record.get('href'),
            target = record.get('hrefTarget'),
            cls = record.get('cls');

        while (record) {
            if (!record.isRoot() || (record.isRoot() && view.rootVisible)) {
                if (record.getDepth() === depth) {
                    buf.unshift(format(imgText,
                        treePrefix + 'icon ' + 
                        treePrefix + 'icon' + (record.get('icon') ? '-inline ' : (record.isLeaf() ? '-leaf ' : '-parent ')) +
                        (record.get('iconCls') || ''),
                        record.get('icon') || blank
                    ));
                    if (record.get('checked') !== null) {
                        buf.unshift(format(
                            checkboxText,
                            (treePrefix + 'checkbox') + (record.get('checked') ? ' ' + treePrefix + 'checkbox-checked' : ''),
                            record.get('checked') ? 'aria-checked="true"' : ''
                        ));
                        if (record.get('checked')) {
                            metaData.tdCls += (' ' + treePrefix + 'checked');
                        }
                    }
                    if (record.isLast()) {
                        if (record.isExpandable()) {
                            buf.unshift(format(imgText, (elbowPrefix + 'end-plus ' + expanderCls), blank));
                        } else {
                            buf.unshift(format(imgText, (elbowPrefix + 'end'), blank));
                        }
                            
                    } else {
                        if (record.isExpandable()) {
                            buf.unshift(format(imgText, (elbowPrefix + 'plus ' + expanderCls), blank));
                        } else {
                            buf.unshift(format(imgText, (treePrefix + 'elbow'), blank));
                        }
                    }
                } else {
                    if (record.isLast() || record.getDepth() === 0) {
                        buf.unshift(format(imgText, (elbowPrefix + 'empty'), blank));
                    } else if (record.getDepth() !== 0) {
                        buf.unshift(format(imgText, (elbowPrefix + 'line'), blank));
                    }                      
                }
            }
            record = record.parentNode;
        }
        if (href) {
            buf.push('<a href="', href, '" target="', target, '">', formattedValue, '</a>');
        } else {
            buf.push(formattedValue);
        }
        if (cls) {
            metaData.tdCls += ' ' + cls;
        }
        return buf.join('');
    },

    defaultRenderer: function(value) {
        return value;
    }
});


Ext.define('Ext.view.DragZone', {
    extend: 'Ext.dd.DragZone',
    containerScroll: false,

    constructor: function(config) {
        var me = this,
            view,
            ownerCt,
            el;

        Ext.apply(me, config);

        
        
        
        
        
        if (!me.ddGroup) {
            me.ddGroup = 'view-dd-zone-' + me.view.id;
        }

        
        
        
        
        
        
        
        view = me.view;
        ownerCt = view.ownerCt;
        
        
        if (ownerCt) {
            el = ownerCt.getTargetEl().dom;
        } else {
            el = view.el.dom.parentNode;
        }
        me.callParent([el]);

        me.ddel = Ext.get(document.createElement('div'));
        me.ddel.addCls(Ext.baseCSSPrefix + 'grid-dd-wrap');
    },

    init: function(id, sGroup, config) {
        this.initTarget(id, sGroup, config);
        this.view.mon(this.view, {
            itemmousedown: this.onItemMouseDown,
            scope: this
        });
    },

    onValidDrop: function(target, e, id) {
        this.callParent();
        
        target.el.focus();
    },
    
    onItemMouseDown: function(view, record, item, index, e) {
        if (!this.isPreventDrag(e, record, item, index)) {
            
            
            
            this.view.focus();
            this.handleMouseDown(e);

            
            
            if (view.getSelectionModel().selectionMode == 'MULTI' && !e.ctrlKey && view.getSelectionModel().isSelected(record)) {
                return false;
            }
        }
    },

    
    isPreventDrag: function(e) {
        return false;
    },

    getDragData: function(e) {
        var view = this.view,
            item = e.getTarget(view.getItemSelector());

        if (item) {
            return {
                copy: view.copy || (view.allowCopy && e.ctrlKey),
                event: new Ext.EventObjectImpl(e),
                view: view,
                ddel: this.ddel,
                item: item,
                records: view.getSelectionModel().getSelection(),
                fromPosition: Ext.fly(item).getXY()
            };
        }
    },

    onInitDrag: function(x, y) {
        var me = this,
            data = me.dragData,
            view = data.view,
            selectionModel = view.getSelectionModel(),
            record = view.getRecord(data.item),
            e = data.event;

        
        
        if (!selectionModel.isSelected(record)) {
            selectionModel.select(record, true);
        }
        data.records = selectionModel.getSelection();

        me.ddel.update(me.getDragText());
        me.proxy.update(me.ddel.dom);
        me.onStartDrag(x, y);
        return true;
    },

    getDragText: function() {
        var count = this.dragData.records.length;
        return Ext.String.format(this.dragText, count, count == 1 ? '' : 's');
    },

    getRepairXY : function(e, data){
        return data ? data.fromPosition : false;
    }
});

Ext.define('Ext.tree.ViewDragZone', {
    extend: 'Ext.view.DragZone',

    isPreventDrag: function(e, record) {
        return (record.get('allowDrag') === false) || !!e.getTarget(this.view.expanderSelector);
    },
    
    afterRepair: function() {
        var me = this,
            view = me.view,
            selectedRowCls = view.selectedItemCls,
            records = me.dragData.records,
            r,
            rLen    = records.length,
            fly = Ext.fly,
            item;
        
        if (Ext.enableFx && me.repairHighlight) {
            
            for (r = 0; r < rLen; r++) {
                
                
                item = view.getNode(records[r]);

                
                
                fly(item.firstChild).highlight(me.repairHighlightColor, {
                    listeners: {
                        beforeanimate: function() {
                            if (view.isSelected(item)) {
                                fly(item).removeCls(selectedRowCls);
                            }
                        },
                        afteranimate: function() {
                            if (view.isSelected(item)) {
                                fly(item).addCls(selectedRowCls);
                            }
                        }
                    }
                });
            }

        }
        me.dragging = false;
    }
});

Ext.define('Ext.view.DropZone', {
    extend: 'Ext.dd.DropZone',

    indicatorHtml: '<div class="' + Ext.baseCSSPrefix + 'grid-drop-indicator-left"></div><div class="' + Ext.baseCSSPrefix + 'grid-drop-indicator-right"></div>',
    indicatorCls: Ext.baseCSSPrefix + 'grid-drop-indicator',

    constructor: function(config) {
        var me = this;
        Ext.apply(me, config);

        
        
        
        
        
        if (!me.ddGroup) {
            me.ddGroup = 'view-dd-zone-' + me.view.id;
        }

        
        
        
        me.callParent([me.view.el]);
    },



    fireViewEvent: function() {
        var me = this,
            result;

        me.lock();
        result = me.view.fireEvent.apply(me.view, arguments);
        me.unlock();
        return result;
    },

    getTargetFromEvent : function(e) {
        var node = e.getTarget(this.view.getItemSelector()),
            mouseY, nodeList, testNode, i, len, box;



        if (!node) {
            mouseY = e.getPageY();
            for (i = 0, nodeList = this.view.getNodes(), len = nodeList.length; i < len; i++) {
                testNode = nodeList[i];
                box = Ext.fly(testNode).getBox();
                if (mouseY <= box.bottom) {
                    return testNode;
                }
            }
        }
        return node;
    },

    getIndicator: function() {
        var me = this;

        if (!me.indicator) {
            me.indicator = new Ext.Component({
                html: me.indicatorHtml,
                cls: me.indicatorCls,
                ownerCt: me.view,
                floating: true,
                shadow: false
            });
        }
        return me.indicator;
    },

    getPosition: function(e, node) {
        var y      = e.getXY()[1],
            region = Ext.fly(node).getRegion(),
            pos;

        if ((region.bottom - y) >= (region.bottom - region.top) / 2) {
            pos = "before";
        } else {
            pos = "after";
        }
        return pos;
    },

    
    containsRecordAtOffset: function(records, record, offset) {
        if (!record) {
            return false;
        }
        var view = this.view,
            recordIndex = view.indexOf(record),
            nodeBefore = view.getNode(recordIndex + offset),
            recordBefore = nodeBefore ? view.getRecord(nodeBefore) : null;

        return recordBefore && Ext.Array.contains(records, recordBefore);
    },

    positionIndicator: function(node, data, e) {
        var me = this,
            view = me.view,
            pos = me.getPosition(e, node),
            overRecord = view.getRecord(node),
            draggingRecords = data.records,
            indicatorY;

        if (!Ext.Array.contains(draggingRecords, overRecord) && (
            pos == 'before' && !me.containsRecordAtOffset(draggingRecords, overRecord, -1) ||
            pos == 'after' && !me.containsRecordAtOffset(draggingRecords, overRecord, 1)
        )) {
            me.valid = true;

            if (me.overRecord != overRecord || me.currentPosition != pos) {

                indicatorY = Ext.fly(node).getY() - view.el.getY() - 1;
                if (pos == 'after') {
                    indicatorY += Ext.fly(node).getHeight();
                }
                me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, indicatorY);

                
                me.overRecord = overRecord;
                me.currentPosition = pos;
            }
        } else {
            me.invalidateDrop();
        }
    },

    invalidateDrop: function() {
        if (this.valid) {
            this.valid = false;
            this.getIndicator().hide();
        }
    },

    
    onNodeOver: function(node, dragZone, e, data) {
        var me = this;

        if (!Ext.Array.contains(data.records, me.view.getRecord(node))) {
            me.positionIndicator(node, data, e);
        }
        return me.valid ? me.dropAllowed : me.dropNotAllowed;
    },

    
    
    notifyOut: function(node, dragZone, e, data) {
        var me = this;

        me.callParent(arguments);
        delete me.overRecord;
        delete me.currentPosition;
        if (me.indicator) {
            me.indicator.hide();
        }
    },

    
    onContainerOver : function(dd, e, data) {
        var me = this,
            view = me.view,
            count = view.store.getCount();

        
        if (count) {
            me.positionIndicator(view.getNode(count - 1), data, e);
        }

        
        else {
            delete me.overRecord;
            delete me.currentPosition;
            me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, 0);
            me.valid = true;
        }
        return me.dropAllowed;
    },

    onContainerDrop : function(dd, e, data) {
        return this.onNodeDrop(dd, null, e, data);
    },

    onNodeDrop: function(node, dragZone, e, data) {
        var me = this,
            dropHandled = false,
 
            
            
            
            
            
            dropHandlers = {
                wait: false,
                processDrop: function () {
                    me.invalidateDrop();
                    me.handleNodeDrop(data, me.overRecord, me.currentPosition);
                    dropHandled = true;
                    me.fireViewEvent('drop', node, data, me.overRecord, me.currentPosition);
                },
 
                cancelDrop: function() {
                    me.invalidateDrop();
                    dropHandled = true;
                }
            },
            performOperation = false;
 
        if (me.valid) {
            performOperation = me.fireViewEvent('beforedrop', node, data, me.overRecord, me.currentPosition, dropHandlers);
            if (dropHandlers.wait) {
                return;
            }
 
            if (performOperation !== false) {
                
                if (!dropHandled) {
                    dropHandlers.processDrop();
                }
            }
        }
        return performOperation;
    },
    
    destroy: function(){
        Ext.destroy(this.indicator);
        delete this.indicator;
        this.callParent();
    }
});


Ext.define('Ext.grid.ViewDropZone', {
    extend: 'Ext.view.DropZone',

    indicatorHtml: '<div class="' + Ext.baseCSSPrefix + 'grid-drop-indicator-left"></div><div class="' + Ext.baseCSSPrefix + 'grid-drop-indicator-right"></div>',
    indicatorCls: Ext.baseCSSPrefix + 'grid-drop-indicator',

    handleNodeDrop : function(data, record, position) {
        var view = this.view,
            store = view.getStore(),
            index, records, i, len;

        
        if (data.copy) {
            records = data.records;
            data.records = [];
            for (i = 0, len = records.length; i < len; i++) {
                data.records.push(records[i].copy(records[i].getId()));
            }
        } else {
            
            data.view.store.remove(data.records, data.view === view);
        }

        index = store.indexOf(record);

        
        if (position !== 'before') {
            index++;
        }
        store.insert(index, data.records);
        view.getSelectionModel().select(data.records);
    }
});

Ext.define('Ext.tree.ViewDropZone', {
    extend: 'Ext.view.DropZone',

    
    allowParentInserts: false,
 
    
    allowContainerDrops: false,

    
    appendOnly: false,

    
    expandDelay : 500,

    indicatorCls: Ext.baseCSSPrefix + 'tree-ddindicator',

    
    expandNode : function(node) {
        var view = this.view;
        if (!node.isLeaf() && !node.isExpanded()) {
            view.expand(node);
            this.expandProcId = false;
        }
    },

    
    queueExpand : function(node) {
        this.expandProcId = Ext.Function.defer(this.expandNode, this.expandDelay, this, [node]);
    },

    
    cancelExpand : function() {
        if (this.expandProcId) {
            clearTimeout(this.expandProcId);
            this.expandProcId = false;
        }
    },

    getPosition: function(e, node) {
        var view = this.view,
            record = view.getRecord(node),
            y = e.getPageY(),
            noAppend = record.isLeaf(),
            noBelow = false,
            region = Ext.fly(node).getRegion(),
            fragment;

        
        if (record.isRoot()) {
            return 'append';
        }

        
        if (this.appendOnly) {
            return noAppend ? false : 'append';
        }

        if (!this.allowParentInsert) {
            noBelow = record.hasChildNodes() && record.isExpanded();
        }

        fragment = (region.bottom - region.top) / (noAppend ? 2 : 3);
        if (y >= region.top && y < (region.top + fragment)) {
            return 'before';
        }
        else if (!noBelow && (noAppend || (y >= (region.bottom - fragment) && y <= region.bottom))) {
            return 'after';
        }
        else {
            return 'append';
        }
    },

    isValidDropPoint : function(node, position, dragZone, e, data) {
        if (!node || !data.item) {
            return false;
        }

        var view = this.view,
            targetNode = view.getRecord(node),
            draggedRecords = data.records,
            dataLength = draggedRecords.length,
            ln = draggedRecords.length,
            i, record;

        
        if (!(targetNode && position && dataLength)) {
            return false;
        }

        
        for (i = 0; i < ln; i++) {
            record = draggedRecords[i];
            if (record.isNode && record.contains(targetNode)) {
                return false;
            }
        }
        
        
        if (position === 'append' && targetNode.get('allowDrop') === false) {
            return false;
        }
        else if (position != 'append' && targetNode.parentNode.get('allowDrop') === false) {
            return false;
        }

        
        if (Ext.Array.contains(draggedRecords, targetNode)) {
             return false;
        }

        
        
        return true;
    },

    onNodeOver : function(node, dragZone, e, data) {
        var position = this.getPosition(e, node),
            returnCls = this.dropNotAllowed,
            view = this.view,
            targetNode = view.getRecord(node),
            indicator = this.getIndicator(),
            indicatorX = 0,
            indicatorY = 0;

        
        this.cancelExpand();
        if (position == 'append' && !this.expandProcId && !Ext.Array.contains(data.records, targetNode) && !targetNode.isLeaf() && !targetNode.isExpanded()) {
            this.queueExpand(targetNode);
        }
            
            
        if (this.isValidDropPoint(node, position, dragZone, e, data)) {
            this.valid = true;
            this.currentPosition = position;
            this.overRecord = targetNode;

            indicator.setWidth(Ext.fly(node).getWidth());
            indicatorY = Ext.fly(node).getY() - Ext.fly(view.el).getY() - 1;

            
            if (position == 'before') {
                returnCls = targetNode.isFirst() ? Ext.baseCSSPrefix + 'tree-drop-ok-above' : Ext.baseCSSPrefix + 'tree-drop-ok-between';
                indicator.showAt(0, indicatorY);
                dragZone.proxy.show();
            } else if (position == 'after') {
                returnCls = targetNode.isLast() ? Ext.baseCSSPrefix + 'tree-drop-ok-below' : Ext.baseCSSPrefix + 'tree-drop-ok-between';
                indicatorY += Ext.fly(node).getHeight();
                indicator.showAt(0, indicatorY);
                dragZone.proxy.show();
            } else {
                returnCls = Ext.baseCSSPrefix + 'tree-drop-ok-append';
                
                indicator.hide();
            }
        } else {
            this.valid = false;
        }

        this.currentCls = returnCls;
        return returnCls;
    },

    onContainerOver : function(dd, e, data) {
        return e.getTarget('.' + this.indicatorCls) ? this.currentCls : this.dropNotAllowed;
    },
    
    notifyOut: function() {
        this.callParent(arguments);
        this.cancelExpand();
    },

    handleNodeDrop : function(data, targetNode, position) {
        var me = this,
            view = me.view,
            parentNode = targetNode.parentNode,
            store = view.getStore(),
            recordDomNodes = [],
            records, i, len,
            insertionMethod, argList,
            needTargetExpand,
            transferData,
            processDrop;

        
        if (data.copy) {
            records = data.records;
            data.records = [];
            for (i = 0, len = records.length; i < len; i++) {
                data.records.push(Ext.apply({}, records[i].data));
            }
        }

        
        me.cancelExpand();

        
        
        
        
        if (position == 'before') {
            insertionMethod = parentNode.insertBefore;
            argList = [null, targetNode];
            targetNode = parentNode;
        }
        else if (position == 'after') {
            if (targetNode.nextSibling) {
                insertionMethod = parentNode.insertBefore;
                argList = [null, targetNode.nextSibling];
            }
            else {
                insertionMethod = parentNode.appendChild;
                argList = [null];
            }
            targetNode = parentNode;
        }
        else {
            if (!targetNode.isExpanded()) {
                needTargetExpand = true;
            }
            insertionMethod = targetNode.appendChild;
            argList = [null];
        }

        
        transferData = function() {
            var node,
                r, rLen, color, n;
            for (i = 0, len = data.records.length; i < len; i++) {
                argList[0] = data.records[i];
                node = insertionMethod.apply(targetNode, argList);
                
                if (Ext.enableFx && me.dropHighlight) {
                    recordDomNodes.push(view.getNode(node));
                }
            }
            
            
            
            if (Ext.enableFx && me.dropHighlight) {
                
                
                rLen  = recordDomNodes.length;
                color = me.dropHighlightColor;

                for (r = 0; r < rLen; r++) {
                    n = recordDomNodes[r];

                    if (n) {
                        Ext.fly(n.firstChild ? n.firstChild : n).highlight(color);
                    }
                }
            }
        };

        
        if (needTargetExpand) {
            targetNode.expand(false, transferData);
        }
        
        else {
            transferData();
        }
    }
});

Ext.define('Ext.view.TableChunker', {
    singleton: true,
    requires: ['Ext.XTemplate'],
    metaTableTpl: [
        '{%if (this.openTableWrap)out.push(this.openTableWrap())%}',
        '<table class="' + Ext.baseCSSPrefix + 'grid-table ' + Ext.baseCSSPrefix + 'grid-table-resizer" border="0" cellspacing="0" cellpadding="0" {[this.embedFullWidth(values)]}>',
            '<tbody>',
            '<tr class="' + Ext.baseCSSPrefix + 'grid-header-row">',
            '<tpl for="columns">',
                '<th class="' + Ext.baseCSSPrefix + 'grid-col-resizer-{id}" style="width: {width}px; height: 0px;"></th>',
            '</tpl>',
            '</tr>',
            '{[this.openRows()]}',
                '{row}',
                '<tpl for="features">',
                    '{[this.embedFeature(values, parent, xindex, xcount)]}',
                '</tpl>',
            '{[this.closeRows()]}',
            '</tbody>',
        '</table>',
        '{%if (this.closeTableWrap)out.push(this.closeTableWrap())%}'
    ],

    constructor: function() {
        Ext.XTemplate.prototype.recurse = function(values, reference) {
            return this.apply(reference ? values[reference] : values);
        };
    },

    embedFeature: function(values, parent, x, xcount) {
        var tpl = '';
        if (!values.disabled) {
            tpl = values.getFeatureTpl(values, parent, x, xcount);
        }
        return tpl;
    },

    embedFullWidth: function(values) {
        var result = 'style="width:{fullWidth}px;';

        
        
        if (!values.rowCount) {
            result += 'height:1px;';
        }
        return result + '"';
    },

    openRows: function() {
        return '<tpl for="rows">';
    },

    closeRows: function() {
        return '</tpl>';
    },

    metaRowTpl: [
        '<tr class="' + Ext.baseCSSPrefix + 'grid-row {[this.embedRowCls()]}" {[this.embedRowAttr()]}>',
            '<tpl for="columns">',
                '<td class="{cls} ' + Ext.baseCSSPrefix + 'grid-cell ' + Ext.baseCSSPrefix + 'grid-cell-{columnId} {{id}-modified} {{id}-tdCls} {[this.firstOrLastCls(xindex, xcount)]}" {{id}-tdAttr}>',
                    '<div {unselectableAttr} class="' + Ext.baseCSSPrefix + 'grid-cell-inner {unselectableCls}" style="text-align: {align}; {{id}-style};">{{id}}</div>',
                '</td>',
            '</tpl>',
        '</tr>'
    ],

    firstOrLastCls: function(xindex, xcount) {
        if (xindex === 1) {
            return Ext.view.Table.prototype.firstCls;
        } else if (xindex === xcount) {
            return Ext.view.Table.prototype.lastCls;
        }
    },
    
    embedRowCls: function() {
        return '{rowCls}';
    },
    
    embedRowAttr: function() {
        return '{rowAttr}';
    },
    
    openTableWrap: undefined,
    
    closeTableWrap: undefined,

    getTableTpl: function(cfg, textOnly) {
        var tpl,
            tableTplMemberFns = {
                openRows: this.openRows,
                closeRows: this.closeRows,
                embedFeature: this.embedFeature,
                embedFullWidth: this.embedFullWidth,
                openTableWrap: this.openTableWrap,
                closeTableWrap: this.closeTableWrap
            },
            tplMemberFns = {},
            features = cfg.features || [],
            ln = features.length,
            i  = 0,
            memberFns = {
                embedRowCls: this.embedRowCls,
                embedRowAttr: this.embedRowAttr,
                firstOrLastCls: this.firstOrLastCls,
                unselectableAttr: cfg.enableTextSelection ? '' : 'unselectable="on"',
                unselectableCls: cfg.enableTextSelection ? '' : Ext.baseCSSPrefix + 'unselectable'
            },
            
            metaRowTpl = Array.prototype.slice.call(this.metaRowTpl, 0),
            metaTableTpl;
            
        for (; i < ln; i++) {
            if (!features[i].disabled) {
                features[i].mutateMetaRowTpl(metaRowTpl);
                Ext.apply(memberFns, features[i].getMetaRowTplFragments());
                Ext.apply(tplMemberFns, features[i].getFragmentTpl());
                Ext.apply(tableTplMemberFns, features[i].getTableFragments());
            }
        }
        
        metaRowTpl = new Ext.XTemplate(metaRowTpl.join(''), memberFns);
        cfg.row = metaRowTpl.applyTemplate(cfg);
        
        metaTableTpl = new Ext.XTemplate(this.metaTableTpl.join(''), tableTplMemberFns);
        
        tpl = metaTableTpl.applyTemplate(cfg);
        
        
        if (!textOnly) {
            tpl = new Ext.XTemplate(tpl, tplMemberFns);
        }
        return tpl;
        
    }
});


Ext.define('Ext.view.View', {
    extend: 'Ext.view.AbstractView',
    alternateClassName: 'Ext.DataView',
    alias: 'widget.dataview',

    deferHighlight: (Ext.isIE6 || Ext.isIE7) ? 100 : 0,

    inputTagRe: /^textarea$|^input$/i,

    inheritableStatics: {
        EventMap: {
            mousedown: 'MouseDown',
            mouseup: 'MouseUp',
            click: 'Click',
            dblclick: 'DblClick',
            contextmenu: 'ContextMenu',
            mouseover: 'MouseOver',
            mouseout: 'MouseOut',
            mouseenter: 'MouseEnter',
            mouseleave: 'MouseLeave',
            keydown: 'KeyDown',
            focus: 'Focus'
        }
    },

    initComponent: function() {
        var me = this;
        me.callParent();
        if (me.deferHighlight){
            me.setHighlightedItem =
                Ext.Function.createBuffered(me.setHighlightedItem, me.deferHighlight, me);
        }
    },

    addCmpEvents: function() {
        this.addEvents(
            
            'beforeitemmousedown',
            
            'beforeitemmouseup',
            
            'beforeitemmouseenter',
            
            'beforeitemmouseleave',
            
            'beforeitemclick',
            
            'beforeitemdblclick',
            
            'beforeitemcontextmenu',
            
            'beforeitemkeydown',
            
            'itemmousedown',
            
            'itemmouseup',
            
            'itemmouseenter',
            
            'itemmouseleave',
            
            'itemclick',
            
            'itemdblclick',
            
            'itemcontextmenu',
            
            'itemkeydown',
            
            'beforecontainermousedown',
            
            'beforecontainermouseup',
            
            'beforecontainermouseover',
            
            'beforecontainermouseout',
            
            'beforecontainerclick',
            
            'beforecontainerdblclick',
            
            'beforecontainercontextmenu',
            
            'beforecontainerkeydown',
            
            'containermouseup',
            
            'containermouseover',
            
            'containermouseout',
            
            'containerclick',
            
            'containerdblclick',
            
            'containercontextmenu',
            
            'containerkeydown',

            
            'selectionchange',
            
            'beforeselect',
            
            'beforedeselect',
            
            'select',
            
            'deselect',
            
            'focuschange',
            
            
            'highlightitem',
            
            
            'unhighlightitem'
        );
    },

    getFocusEl: function() {
        return this.getTargetEl();
    },

    
    afterRender: function(){
        var me = this;
        me.callParent();
        me.mon(me.getTargetEl(), {
            scope: me,
            
            freezeEvent: true,
            click: me.handleEvent,
            mousedown: me.handleEvent,
            mouseup: me.handleEvent,
            dblclick: me.handleEvent,
            contextmenu: me.handleEvent,
            mouseover: me.handleEvent,
            mouseout: me.handleEvent,
            keydown: me.handleEvent
        });
    },

    handleEvent: function(e) {
        var me = this,
            key = e.type == 'keydown' && e.getKey();

        if (me.processUIEvent(e) !== false) {
            me.processSpecialEvent(e);
        }

        
        
        
        if (key === e.SPACE) {
            if (!me.inputTagRe.test(e.getTarget().tagName)) {
                e.stopEvent();
            }
        }
    },

    
    processItemEvent: Ext.emptyFn,
    processContainerEvent: Ext.emptyFn,
    processSpecialEvent: Ext.emptyFn,

    
    stillOverItem: function (event, overItem) {
        var nowOver;

        
        
        
        
        
        
        if (overItem && typeof(overItem.offsetParent) === "object") {
            
            
            nowOver = (event.type == 'mouseout') ? event.getRelatedTarget() : event.getTarget();
            return Ext.fly(overItem).contains(nowOver);
        }

        return false;
    },

    processUIEvent: function(e) {
        var me = this,
            item = e.getTarget(me.getItemSelector(), me.getTargetEl()),
            map = this.statics().EventMap,
            index, record,
            type = e.type,
            overItem = me.mouseOverItem,
            newType;

        if (!item) {
            if (type == 'mouseover' && me.stillOverItem(e, overItem)) {
                item = overItem;
            }

            
            if (type == 'keydown') {
                record = me.getSelectionModel().getLastSelected();
                if (record) {
                    item = me.getNode(record);
                }
            }
        }

        if (item) {
            index = me.indexOf(item);
            if (!record) {
                record = me.getRecord(item);
            }

            
            
            
            if (!record || me.processItemEvent(record, item, index, e) === false) {
                return false;
            }

            newType = me.isNewItemEvent(item, e);
            if (newType === false) {
                return false;
            }

            if (
                (me['onBeforeItem' + map[newType]](record, item, index, e) === false) ||
                (me.fireEvent('beforeitem' + newType, me, record, item, index, e) === false) ||
                (me['onItem' + map[newType]](record, item, index, e) === false)
            ) {
                return false;
            }

            me.fireEvent('item' + newType, me, record, item, index, e);
        }
        else {
            if (
                (me.processContainerEvent(e) === false) ||
                (me['onBeforeContainer' + map[type]](e) === false) ||
                (me.fireEvent('beforecontainer' + type, me, e) === false) ||
                (me['onContainer' + map[type]](e) === false)
            ) {
                return false;
            }

            me.fireEvent('container' + type, me, e);
        }

        return true;
    },

    isNewItemEvent: function (item, e) {
        var me = this,
            overItem = me.mouseOverItem,
            type = e.type;

        switch (type) {
            case 'mouseover':
                if (item === overItem) {
                    return false;
                }
                me.mouseOverItem = item;
                return 'mouseenter';

            case 'mouseout':
                
                if (me.stillOverItem(e, overItem)) {
                    return false;
                }
                me.mouseOverItem = null;
                return 'mouseleave';
        }
        return type;
    },

    
    onItemMouseEnter: function(record, item, index, e) {
        if (this.trackOver) {
            this.highlightItem(item);
        }
    },

    
    onItemMouseLeave : function(record, item, index, e) {
        if (this.trackOver) {
            this.clearHighlight();
        }
    },

    
    onItemMouseDown: Ext.emptyFn,
    onItemMouseUp: Ext.emptyFn,
    onItemFocus: Ext.emptyFn,
    onItemClick: Ext.emptyFn,
    onItemDblClick: Ext.emptyFn,
    onItemContextMenu: Ext.emptyFn,
    onItemKeyDown: Ext.emptyFn,
    onBeforeItemMouseDown: Ext.emptyFn,
    onBeforeItemMouseUp: Ext.emptyFn,
    onBeforeItemFocus: Ext.emptyFn,
    onBeforeItemMouseEnter: Ext.emptyFn,
    onBeforeItemMouseLeave: Ext.emptyFn,
    onBeforeItemClick: Ext.emptyFn,
    onBeforeItemDblClick: Ext.emptyFn,
    onBeforeItemContextMenu: Ext.emptyFn,
    onBeforeItemKeyDown: Ext.emptyFn,

    
    onContainerMouseDown: Ext.emptyFn,
    onContainerMouseUp: Ext.emptyFn,
    onContainerMouseOver: Ext.emptyFn,
    onContainerMouseOut: Ext.emptyFn,
    onContainerClick: Ext.emptyFn,
    onContainerDblClick: Ext.emptyFn,
    onContainerContextMenu: Ext.emptyFn,
    onContainerKeyDown: Ext.emptyFn,
    onBeforeContainerMouseDown: Ext.emptyFn,
    onBeforeContainerMouseUp: Ext.emptyFn,
    onBeforeContainerMouseOver: Ext.emptyFn,
    onBeforeContainerMouseOut: Ext.emptyFn,
    onBeforeContainerClick: Ext.emptyFn,
    onBeforeContainerDblClick: Ext.emptyFn,
    onBeforeContainerContextMenu: Ext.emptyFn,
    onBeforeContainerKeyDown: Ext.emptyFn,

    
    setHighlightedItem: function(item){
        var me = this,
            highlighted = me.highlightedItem;

        if (highlighted != item){
            if (highlighted) {
                Ext.fly(highlighted).removeCls(me.overItemCls);
                me.fireEvent('unhighlightitem', me, highlighted);
            }

            me.highlightedItem = item;

            if (item) {
                
                Ext.fly(item).addCls(me.overItemCls);
                me.fireEvent('highlightitem', me, item);
            }
        }
    },

    
    highlightItem: function(item) {
        this.setHighlightedItem(item);
    },

    
    clearHighlight: function() {
        this.setHighlightedItem(undefined);
    },
    
    onUpdate: function(store, record){
        var me = this,
            node,
            newNode,
            highlighted;
        
        if (me.viewReady) {
            node = me.getNode(record);
            newNode = me.callParent(arguments);
            highlighted = me.highlightedItem;
            
            if (highlighted && highlighted === node) {
                delete me.highlightedItem;
                if (newNode) {
                    me.highlightItem(newNode);
                }
            }
        }
    },

    refresh: function() {
        this.clearHighlight();
        this.callParent(arguments);
    }
});

Ext.define('Ext.view.BoundList', {
    extend: 'Ext.view.View',
    alias: 'widget.boundlist',
    alternateClassName: 'Ext.BoundList',
    requires: ['Ext.layout.component.BoundList', 'Ext.toolbar.Paging'],

    
    pageSize: 0,
    
    

    

    
    baseCls: Ext.baseCSSPrefix + 'boundlist',
    itemCls: Ext.baseCSSPrefix + 'boundlist-item',
    listItemCls: '',
    shadow: false,
    trackOver: true,
    refreshed: 0,
    
    
    deferInitialRefresh: false,

    componentLayout: 'boundlist',

    childEls: [
        'listEl'
    ],

    renderTpl: [
        '<div id="{id}-listEl" class="{baseCls}-list-ct" style="overflow:auto"></div>',
        '{%',
            'var me=values.$comp, pagingToolbar=me.pagingToolbar;',
            'if (pagingToolbar) {',
                'pagingToolbar.ownerLayout = me.componentLayout;',
                'Ext.DomHelper.generateMarkup(pagingToolbar.getRenderTree(), out);',
            '}',
        '%}',
        {
            disableFormats: true
        }
    ],

    

    initComponent: function() {
        var me = this,
            baseCls = me.baseCls,
            itemCls = me.itemCls;
            
        me.selectedItemCls = baseCls + '-selected';
        me.overItemCls = baseCls + '-item-over';
        me.itemSelector = "." + itemCls;

        if (me.floating) {
            me.addCls(baseCls + '-floating');
        }

        if (!me.tpl) {
            
            
            me.tpl = new Ext.XTemplate(
                '<ul><tpl for=".">',
                    '<li role="option" class="' + itemCls + '">' + me.getInnerTpl(me.displayField) + '</li>',
                '</tpl></ul>'
            );
        } else if (Ext.isString(me.tpl)) {
            me.tpl = new Ext.XTemplate(me.tpl);
        }

        if (me.pageSize) {
            me.pagingToolbar = me.createPagingToolbar();
        }

        me.callParent();
    },

    beforeRender: function() {
        var me = this;

        me.callParent(arguments);

        
        
        if (me.up('menu')) {
            me.addCls(Ext.baseCSSPrefix + 'menu');
        }
    },

    
    getBubbleTarget: function() {
        return this.pickerField;
    },

    getRefItems: function() {
        return this.pagingToolbar ? [ this.pagingToolbar ] : [];
    },

    createPagingToolbar: function() {
        return Ext.widget('pagingtoolbar', {
            id: this.id + '-paging-toolbar',
            pageSize: this.pageSize,
            store: this.store,
            border: false,
            ownerCt: this,
            ownerLayout: this.getComponentLayout()
        });
    },

    
    
    finishRenderChildren: function () {
        var toolbar = this.pagingToolbar;

        this.callParent(arguments);

        if (toolbar) {
            toolbar.finishRender();
        }
    },
    
    refresh: function(){
        var me = this,
            toolbar = me.pagingToolbar;
        
        me.callParent();
        
        
        if (me.rendered && toolbar && toolbar.rendered && !me.preserveScrollOnRefresh) {
            me.el.appendChild(toolbar.el);
        }  
    },

    bindStore : function(store, initial) {
        var toolbar = this.pagingToolbar;
            
        this.callParent(arguments);
        if (toolbar) {
            toolbar.bindStore(this.store, initial);
        }
    },

    getTargetEl: function() {
        return this.listEl || this.el;
    },

    
    getInnerTpl: function(displayField) {
        return '{' + displayField + '}';
    },

    onDestroy: function() {
        Ext.destroyMembers(this, 'pagingToolbar', 'listEl');
        this.callParent();
    }
});


Ext.define('Ext.picker.Time', {
    extend: 'Ext.view.BoundList',
    alias: 'widget.timepicker',
    requires: ['Ext.data.Store', 'Ext.Date'],

    

    

    
    increment: 15,

    
    
    format : "g:i A",
    

    
    displayField: 'disp',

    
    initDate: [2008,0,1],

    componentCls: Ext.baseCSSPrefix + 'timepicker',

    
    loadMask: false,

    initComponent: function() {
        var me = this,
            dateUtil = Ext.Date,
            clearTime = dateUtil.clearTime,
            initDate = me.initDate;

        
        me.absMin = clearTime(new Date(initDate[0], initDate[1], initDate[2]));
        me.absMax = dateUtil.add(clearTime(new Date(initDate[0], initDate[1], initDate[2])), 'mi', (24 * 60) - 1);

        me.store = me.createStore();
        me.updateList();

        me.callParent();
    },

    
    setMinValue: function(value) {
        this.minValue = value;
        this.updateList();
    },

    
    setMaxValue: function(value) {
        this.maxValue = value;
        this.updateList();
    },

    
    normalizeDate: function(date) {
        var initDate = this.initDate;
        date.setFullYear(initDate[0], initDate[1], initDate[2]);
        return date;
    },

    
    updateList: function() {
        var me = this,
            min = me.normalizeDate(me.minValue || me.absMin),
            max = me.normalizeDate(me.maxValue || me.absMax);

        me.store.filterBy(function(record) {
            var date = record.get('date');
            return date >= min && date <= max;
        });
    },

    
    createStore: function() {
        var me = this,
            utilDate = Ext.Date,
            times = [],
            min = me.absMin,
            max = me.absMax;

        while(min <= max){
            times.push({
                disp: utilDate.dateFormat(min, me.format),
                date: min
            });
            min = utilDate.add(min, 'mi', me.increment);
        }

        return new Ext.data.Store({
            fields: ['disp', 'date'],
            data: times
        });
    }

});


Ext.define('Ext.view.BoundListKeyNav', {
    extend: 'Ext.util.KeyNav',
    requires: 'Ext.view.BoundList',

    

    constructor: function(el, config) {
        var me = this;
        me.boundList = config.boundList;
        me.callParent([el, Ext.apply({}, config, me.defaultHandlers)]);
    },

    defaultHandlers: {
        up: function() {
            var me = this,
                boundList = me.boundList,
                allItems = boundList.all,
                oldItem = boundList.highlightedItem,
                oldItemIdx = oldItem ? boundList.indexOf(oldItem) : -1,
                newItemIdx = oldItemIdx > 0 ? oldItemIdx - 1 : allItems.getCount() - 1; 
            me.highlightAt(newItemIdx);
        },

        down: function() {
            var me = this,
                boundList = me.boundList,
                allItems = boundList.all,
                oldItem = boundList.highlightedItem,
                oldItemIdx = oldItem ? boundList.indexOf(oldItem) : -1,
                newItemIdx = oldItemIdx < allItems.getCount() - 1 ? oldItemIdx + 1 : 0; 
            me.highlightAt(newItemIdx);
        },

        pageup: function() {
            
        },

        pagedown: function() {
            
        },

        home: function() {
            this.highlightAt(0);
        },

        end: function() {
            var me = this;
            me.highlightAt(me.boundList.all.getCount() - 1);
        },

        enter: function(e) {
            this.selectHighlighted(e);
        }
    },

    
    highlightAt: function(index) {
        var boundList = this.boundList,
            item = boundList.all.item(index);
        if (item) {
            item = item.dom;
            boundList.highlightItem(item);
            boundList.getTargetEl().scrollChildIntoView(item, false);
        }
    },

    
    selectHighlighted: function(e) {
        var me = this,
            boundList = me.boundList,
            highlighted = boundList.highlightedItem,
            selModel = boundList.getSelectionModel();
        if (highlighted) {
            selModel.selectWithEvent(boundList.getRecord(highlighted), e);
        }
    }

});

Ext.define('Ext.form.field.ComboBox', {
    extend:'Ext.form.field.Picker',
    requires: ['Ext.util.DelayedTask', 'Ext.EventObject', 'Ext.view.BoundList', 'Ext.view.BoundListKeyNav', 'Ext.data.StoreManager', 'Ext.layout.component.field.ComboBox'],
    alternateClassName: 'Ext.form.ComboBox',
    alias: ['widget.combobox', 'widget.combo'],
    mixins: {
        bindable: 'Ext.util.Bindable'    
    },

    componentLayout: 'combobox',

    
    triggerCls: Ext.baseCSSPrefix + 'form-arrow-trigger',
    
    
    hiddenName: '',
    
    

    
    hiddenDataCls: Ext.baseCSSPrefix + 'hide-display ' + Ext.baseCSSPrefix + 'form-data-hidden',

    
    fieldSubTpl: [
        '<div class="{hiddenDataCls}" role="presentation"></div>',
        '<input id="{id}" type="{type}" {inputAttrTpl} class="{fieldCls} {typeCls}" autocomplete="off"',
            '<tpl if="value"> value="{[Ext.util.Format.htmlEncode(values.value)]}"</tpl>',
            '<tpl if="name"> name="{name}"</tpl>',
            '<tpl if="placeholder"> placeholder="{placeholder}"</tpl>',
            '<tpl if="size"> size="{size}"</tpl>',
            '<tpl if="maxLength !== undefined"> maxlength="{maxLength}"</tpl>',
            '<tpl if="readOnly"> readonly="readonly"</tpl>',
            '<tpl if="disabled"> disabled="disabled"</tpl>',
            '<tpl if="tabIdx"> tabIndex="{tabIdx}"</tpl>',
            '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
            '/>',
        {
            compiled: true,
            disableFormats: true
        }
    ],

    getSubTplData: function(){
        var me = this;
        Ext.applyIf(me.subTplData, {
            hiddenDataCls: me.hiddenDataCls
        });
        return me.callParent(arguments);
    },

    afterRender: function(){
        var me = this;
        me.callParent(arguments);
        me.setHiddenValue(me.value);
    },

    

    
    multiSelect: false,

    
    
    delimiter: ', ',
    

    
    displayField: 'text',

    

    
    triggerAction: 'all',

    
    allQuery: '',

    
    queryParam: 'query',

    
    queryMode: 'remote',

    
    queryCaching: true,

    
    pageSize: 0,

    

    

    
    autoSelect: true,

    
    typeAhead: false,

    
    typeAheadDelay: 250,

    
    selectOnTab: true,

    
    forceSelection: false,

    
    growToLongestValue: true,

    

    

    
    defaultListConfig: {
        loadingHeight: 70,
        minWidth: 70,
        maxHeight: 300,
        shadow: 'sides'
    },

    

    

    
    ignoreSelection: 0,

    
    removingRecords: null,

    
    resizeComboToGrow: function () {
        var me = this;
        return me.grow && me.growToLongestValue;
    },

    initComponent: function() {
        var me = this,
            isDefined = Ext.isDefined,
            store = me.store,
            transform = me.transform,
            transformSelect, isLocalMode;

        Ext.applyIf(me.renderSelectors, {
            hiddenDataEl: '.' + me.hiddenDataCls.split(' ').join('.')
        });
        

        this.addEvents(
            
            'beforequery',

            
            'select',

            
            'beforeselect',

            
            'beforedeselect'
        );

        
        if (transform) {
            transformSelect = Ext.getDom(transform);
            if (transformSelect) {
                if (!me.store) {
                    store = Ext.Array.map(Ext.Array.from(transformSelect.options), function(option){
                        return [option.value, option.text];
                    });
                }
                if (!me.name) {
                    me.name = transformSelect.name;
                }
                if (!('value' in me)) {
                    me.value = transformSelect.value;
                }
            }
        }

        me.bindStore(store || 'ext-empty-store', true);
        store = me.store;
        if (store.autoCreated) {
            me.queryMode = 'local';
            me.valueField = me.displayField = 'field1';
            if (!store.expanded) {
                me.displayField = 'field2';
            }
        }


        if (!isDefined(me.valueField)) {
            me.valueField = me.displayField;
        }

        isLocalMode = me.queryMode === 'local';
        if (!isDefined(me.queryDelay)) {
            me.queryDelay = isLocalMode ? 10 : 500;
        }
        if (!isDefined(me.minChars)) {
            me.minChars = isLocalMode ? 0 : 4;
        }

        if (!me.displayTpl) {
            me.displayTpl = new Ext.XTemplate(
                '<tpl for=".">' +
                    '{[typeof values === "string" ? values : values["' + me.displayField + '"]]}' +
                    '<tpl if="xindex < xcount">' + me.delimiter + '</tpl>' +
                '</tpl>'
            );
        } else if (Ext.isString(me.displayTpl)) {
            me.displayTpl = new Ext.XTemplate(me.displayTpl);
        }

        me.callParent();

        me.doQueryTask = new Ext.util.DelayedTask(me.doRawQuery, me);

        
        if (me.store.getCount() > 0) {
            me.setValue(me.value);
        }

        
        if (transformSelect) {
            me.render(transformSelect.parentNode, transformSelect);
            Ext.removeNode(transformSelect);
            delete me.renderTo;
        }
    },

    
    getStore : function(){
        return this.store;
    },

    beforeBlur: function() {
        this.doQueryTask.cancel();
        this.assertValue();
    },

    
    assertValue: function() {
        var me = this,
            value = me.getRawValue(),
            rec;

        if (me.forceSelection) {
            if (me.multiSelect) {
                
                
                if (value !== me.getDisplayValue()) {
                    me.setValue(me.lastSelection);
                }
            } else {
                
                
                rec = me.findRecordByDisplay(value);
                if (rec) {
                    me.select(rec);
                } else {
                    me.setValue(me.lastSelection);
                }
            }
        }
        me.collapse();
    },

    onTypeAhead: function() {
        var me = this,
            displayField = me.displayField,
            record = me.store.findRecord(displayField, me.getRawValue()),
            boundList = me.getPicker(),
            newValue, len, selStart;

        if (record) {
            newValue = record.get(displayField);
            len = newValue.length;
            selStart = me.getRawValue().length;

            boundList.highlightItem(boundList.getNode(record));

            if (selStart !== 0 && selStart !== len) {
                me.setRawValue(newValue);
                me.selectText(selStart, newValue.length);
            }
        }
    },

    
    
    resetToDefault: Ext.emptyFn,
    
    beforeReset: function() {
        this.callParent();
        this.clearFilter();    
    },
    
    onUnbindStore: function(store) {
        var picker = this.picker;
        if (!store && picker) {
            picker.bindStore(null);
        }
        this.clearFilter();
    },
    
    onBindStore: function(store, initial) {
        var picker = this.picker;
        if (!initial) {
            this.resetToDefault();
        }
        if (picker) {
            picker.bindStore(store);
        }
    },
    
    getStoreListeners: function() {
        var me = this;
        
        return {
            beforeload: me.onBeforeLoad,
            clear: me.onClear,
            datachanged: me.onDataChanged,
            load: me.onLoad,
            exception: me.onException,
            remove: me.onRemove
        }; 
    },
    
    onBeforeLoad: function(){
        
        
        
        ++this.ignoreSelection;    
    },
    
    onDataChanged: function() {
        var me = this;

        if (me.resizeComboToGrow()) {
            me.updateLayout();
        }
    },

    onClear: function() {
        var me = this;

        if (me.resizeComboToGrow()) {
            me.removingRecords = true;
            me.onDataChanged();
        }
    },

    onRemove: function() {
        var me = this;

        if (me.resizeComboToGrow()) {
            me.removingRecords = true;
        }
    },

    onException: function(){
        if (this.ignoreSelection > 0) {
            --this.ignoreSelection;
        }
        this.collapse();    
    },

    onLoad: function() {
        var me = this,
            value = me.value;

        if (me.ignoreSelection > 0) {
            --me.ignoreSelection;
        }
        
        if (me.rawQuery) {
            me.rawQuery = false;
            me.syncSelection();
            if (me.picker && !me.picker.getSelectionModel().hasSelection()) {
                me.doAutoSelect();
            }
        }
        
        else {
            
            if (me.value || me.value === 0) {
                me.setValue(me.value);
            } else {
                
                
                if (me.store.getCount()) {
                    me.doAutoSelect();
                } else {
                    
                    me.setValue(me.value);
                }
            }
        }
    },

    
    doRawQuery: function() {
        this.doQuery(this.getRawValue(), false, true);
    },

    
    doQuery: function(queryString, forceAll, rawQuery) {
        queryString = queryString || '';

        
        
        var me = this,
            qe = {
                query: queryString,
                forceAll: forceAll,
                combo: me,
                cancel: false
            },
            store = me.store,
            isLocalMode = me.queryMode === 'local',
            needsRefresh;

        if (me.fireEvent('beforequery', qe) === false || qe.cancel) {
            return false;
        }

        
        queryString = qe.query;
        forceAll = qe.forceAll;

        
        if (forceAll || (queryString.length >= me.minChars)) {
            
            me.expand();

            
            if (!me.queryCaching || me.lastQuery !== queryString) {
                me.lastQuery = queryString;

                if (isLocalMode) {
                    
                    store.suspendEvents();
                    needsRefresh = me.clearFilter();
                    if (queryString || !forceAll) {
                        me.activeFilter = new Ext.util.Filter({
                            root: 'data',
                            property: me.displayField,
                            value: queryString
                        });
                        store.filter(me.activeFilter);
                        needsRefresh = true;
                    } else {
                        delete me.activeFilter;
                    }
                    store.resumeEvents();
                    if (me.rendered && needsRefresh) {
                        me.getPicker().refresh();
                    }
                } else {
                    
                    me.rawQuery = rawQuery;

                    
                    
                    if (me.pageSize) {
                        
                        me.loadPage(1);
                    } else {
                        store.load({
                            params: me.getParams(queryString)
                        });
                    }
                }
            }

            
            if (me.getRawValue() !== me.getDisplayValue()) {
                me.ignoreSelection++;
                me.picker.getSelectionModel().deselectAll();
                me.ignoreSelection--;
            }

            if (isLocalMode) {
                me.doAutoSelect();
            }
            if (me.typeAhead) {
                me.doTypeAhead();
            }
        }
        return true;
    },
    
    
    clearFilter: function() {
        var store = this.store,
            filter = this.activeFilter,
            filters = store.filters,
            remaining;
            
        if (filter) {
            if (filters.getCount() > 1) {
                
                filters.remove(filter);
                remaining = filters.getRange();
            }
            store.clearFilter(true);
            if (remaining) {
                store.filter(remaining);
            }
        }
        return !!filter;
    },

    loadPage: function(pageNum){
        this.store.loadPage(pageNum, {
            params: this.getParams(this.lastQuery)
        });
    },

    onPageChange: function(toolbar, newPage){
        
        this.loadPage(newPage);
        return false;
    },

    
    getParams: function(queryString) {
        var params = {},
            param = this.queryParam;

        if (param) {
            params[param] = queryString;
        }
        return params;
    },

    
    doAutoSelect: function() {
        var me = this,
            picker = me.picker,
            lastSelected, itemNode;
        if (picker && me.autoSelect && me.store.getCount() > 0) {
            
            lastSelected = picker.getSelectionModel().lastSelected;
            itemNode = picker.getNode(lastSelected || 0);
            if (itemNode) {
                picker.highlightItem(itemNode);
                picker.listEl.scrollChildIntoView(itemNode, false);
            }
        }
    },

    doTypeAhead: function() {
        if (!this.typeAheadTask) {
            this.typeAheadTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
        }
        if (this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE) {
            this.typeAheadTask.delay(this.typeAheadDelay);
        }
    },

    onTriggerClick: function() {
        var me = this;
        if (!me.readOnly && !me.disabled) {
            if (me.isExpanded) {
                me.collapse();
            } else {
                me.onFocus({});
                if (me.triggerAction === 'all') {
                    me.doQuery(me.allQuery, true);
                } else {
                    me.doQuery(me.getRawValue(), false, true);
                }
            }
            me.inputEl.focus();
        }
    },


    
    onKeyUp: function(e, t) {
        var me = this,
            key = e.getKey();

        if (!me.readOnly && !me.disabled && me.editable) {
            me.lastKey = key;
            
            

            
            if (!e.isSpecialKey() || key == e.BACKSPACE || key == e.DELETE) {
                me.doQueryTask.delay(me.queryDelay);
            }
        }

        if (me.enableKeyEvents) {
            me.callParent(arguments);
        }
    },

    initEvents: function() {
        var me = this;
        me.callParent();

        
        if (!me.enableKeyEvents) {
            me.mon(me.inputEl, 'keyup', me.onKeyUp, me);
        }
    },

    onDestroy: function() {
        this.bindStore(null);
        this.callParent();
    },

    
    
    onAdded: function() {
        var me = this;
        me.callParent(arguments);
        if (me.picker) {
            me.picker.ownerCt = me.up('[floating]');
            me.picker.registerWithOwnerCt();
        }
    },

    createPicker: function() {
        var me = this,
            picker,
            pickerCfg = Ext.apply({
                xtype: 'boundlist',
                pickerField: me,
                selModel: {
                    mode: me.multiSelect ? 'SIMPLE' : 'SINGLE'
                },
                floating: true,
                hidden: true,
                store: me.store,
                displayField: me.displayField,
                focusOnToFront: false,
                pageSize: me.pageSize,
                tpl: me.tpl
            }, me.listConfig, me.defaultListConfig);

        picker = me.picker = Ext.widget(pickerCfg);
        if (me.pageSize) {
            picker.pagingToolbar.on('beforechange', me.onPageChange, me);
        }

        me.mon(picker, {
            itemclick: me.onItemClick,
            refresh: me.onListRefresh,
            scope: me
        });

        me.mon(picker.getSelectionModel(), {
            beforeselect: me.onBeforeSelect,
            beforedeselect: me.onBeforeDeselect,
            selectionchange: me.onListSelectionChange,
            scope: me
        });

        return picker;
    },

    alignPicker: function(){
        var me = this,
            picker = me.getPicker(),
            heightAbove = me.getPosition()[1] - Ext.getBody().getScroll().top,
            heightBelow = Ext.Element.getViewHeight() - heightAbove - me.getHeight(),
            space = Math.max(heightAbove, heightBelow);

        
        if (picker.height) {
            delete picker.height;
            picker.updateLayout();
        }
        
        if (picker.getHeight() > space - 5) {
            picker.setHeight(space - 5); 
        }
        me.callParent();
    },

    onListRefresh: function() {
        this.alignPicker();
        this.syncSelection();
    },

    onItemClick: function(picker, record){
        
        var me = this,
            selection = me.picker.getSelectionModel().getSelection(),
            valueField = me.valueField;

        if (!me.multiSelect && selection.length) {
            if (record.get(valueField) === selection[0].get(valueField)) {
                
                me.displayTplData = [record.data];
                me.setRawValue(me.getDisplayValue());
                me.collapse();
            }
        }
    },

    onBeforeSelect: function(list, record) {
        return this.fireEvent('beforeselect', this, record, record.index);
    },

    onBeforeDeselect: function(list, record) {
        return this.fireEvent('beforedeselect', this, record, record.index);
    },

    onListSelectionChange: function(list, selectedRecords) {
        var me = this,
            isMulti = me.multiSelect,
            hasRecords = selectedRecords.length > 0;
        
        
        if (!me.ignoreSelection && me.isExpanded) {
            if (!isMulti) {
                Ext.defer(me.collapse, 1, me);
            }
            
            if (isMulti || hasRecords) {
                me.setValue(selectedRecords, false);
            }
            if (hasRecords) {
                me.fireEvent('select', me, selectedRecords);
            }
            me.inputEl.focus();
        }
    },

    
    onExpand: function() {
        var me = this,
            keyNav = me.listKeyNav,
            selectOnTab = me.selectOnTab,
            picker = me.getPicker();

        
        if (keyNav) {
            keyNav.enable();
        } else {
            keyNav = me.listKeyNav = new Ext.view.BoundListKeyNav(this.inputEl, {
                boundList: picker,
                forceKeyDown: true,
                tab: function(e) {
                    if (selectOnTab) {
                        this.selectHighlighted(e);
                        me.triggerBlur();
                    }
                    
                    return true;
                }
            });
        }

        
        if (selectOnTab) {
            me.ignoreMonitorTab = true;
        }

        Ext.defer(keyNav.enable, 1, keyNav); 
        me.inputEl.focus();
    },

    
    onCollapse: function() {
        var me = this,
            keyNav = me.listKeyNav;
        if (keyNav) {
            keyNav.disable();
            me.ignoreMonitorTab = false;
        }
    },

    
    select: function(r) {
        this.setValue(r, true);
    },

    
    findRecord: function(field, value) {
        var ds = this.store,
            idx = ds.findExact(field, value);
        return idx !== -1 ? ds.getAt(idx) : false;
    },

    
    findRecordByValue: function(value) {
        return this.findRecord(this.valueField, value);
    },

    
    findRecordByDisplay: function(value) {
        return this.findRecord(this.displayField, value);
    },

    
    setValue: function(value, doSelect) {
        var me = this,
            valueNotFoundText = me.valueNotFoundText,
            inputEl = me.inputEl,
            i, len, record,
            dataObj,
            matchedRecords = [],
            displayTplData = [],
            processedValue = [];

        if (me.store.loading) {
            
            me.value = value;
            me.setHiddenValue(me.value);
            return me;
        }

        
        value = Ext.Array.from(value);

        
        for (i = 0, len = value.length; i < len; i++) {
            record = value[i];
            if (!record || !record.isModel) {
                record = me.findRecordByValue(record);
            }
            
            if (record) {
                matchedRecords.push(record);
                displayTplData.push(record.data);
                processedValue.push(record.get(me.valueField));
            }
            
            
            else {
                
                
                if (!me.forceSelection) {
                    processedValue.push(value[i]);
                    dataObj = {};
                    dataObj[me.displayField] = value[i];
                    displayTplData.push(dataObj);
                    
                }
                
                else if (Ext.isDefined(valueNotFoundText)) {
                    displayTplData.push(valueNotFoundText);
                }
            }
        }

        
        me.setHiddenValue(processedValue);
        me.value = me.multiSelect ? processedValue : processedValue[0];
        if (!Ext.isDefined(me.value)) {
            me.value = null;
        }
        me.displayTplData = displayTplData; 
        me.lastSelection = me.valueModels = matchedRecords;

        if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
            inputEl.removeCls(me.emptyCls);
        }

        
        me.setRawValue(me.getDisplayValue());
        me.checkChange();

        if (doSelect !== false) {
            me.syncSelection();
        }
        me.applyEmptyText();

        return me;
    },

    
    setHiddenValue: function(values){
        var me = this,
            name = me.hiddenName, 
            i,
            dom, childNodes, input, valueCount, childrenCount;
            
        if (!me.hiddenDataEl || !name) {
            return;
        }
        values = Ext.Array.from(values);
        dom = me.hiddenDataEl.dom;
        childNodes = dom.childNodes;
        input = childNodes[0];
        valueCount = values.length;
        childrenCount = childNodes.length;
        
        if (!input && valueCount > 0) {
            me.hiddenDataEl.update(Ext.DomHelper.markup({
                tag: 'input', 
                type: 'hidden', 
                name: name
            }));
            childrenCount = 1;
            input = dom.firstChild;
        }
        while (childrenCount > valueCount) {
            dom.removeChild(childNodes[0]);
            -- childrenCount;
        }
        while (childrenCount < valueCount) {
            dom.appendChild(input.cloneNode(true));
            ++ childrenCount;
        }
        for (i = 0; i < valueCount; i++) {
            childNodes[i].value = values[i];
        }
    },

    
    getDisplayValue: function() {
        return this.displayTpl.apply(this.displayTplData);
    },

    getValue: function() {
        
        
        
        var me = this,
            picker = me.picker,
            rawValue = me.getRawValue(), 
            value = me.value; 

        if (me.getDisplayValue() !== rawValue) {
            value = rawValue;
            me.value = me.displayTplData = me.valueModels = null;
            if (picker) {
                me.ignoreSelection++;
                picker.getSelectionModel().deselectAll();
                me.ignoreSelection--;
            }
        }

        return value;
    },

    getSubmitValue: function() {
        return this.getValue();
    },

    isEqual: function(v1, v2) {
        var fromArray = Ext.Array.from,
            i, len;

        v1 = fromArray(v1);
        v2 = fromArray(v2);
        len = v1.length;

        if (len !== v2.length) {
            return false;
        }

        for(i = 0; i < len; i++) {
            if (v2[i] !== v1[i]) {
                return false;
            }
        }

        return true;
    },

    
    clearValue: function() {
        this.setValue([]);
    },

    
    syncSelection: function() {
        var me = this,
            picker = me.picker,
            selection, selModel,
            values = me.valueModels || [],
            vLen  = values.length, v, value;

        if (picker) {
            
            selection = [];
            for (v = 0; v < vLen; v++) {
                value = values[v];

                if (value && value.isModel && me.store.indexOf(value) >= 0) {
                    selection.push(value);
                }
            }

            
            me.ignoreSelection++;
            selModel = picker.getSelectionModel();
            selModel.deselectAll();
            if (selection.length) {
                selModel.select(selection);
            }
            me.ignoreSelection--;
        }
    },
    
    onEditorTab: function(e){
        var keyNav = this.listKeyNav;
        
        if (this.selectOnTab && keyNav) {
            keyNav.selectHighlighted(e);
        }
    }
});


Ext.define('Ext.form.field.Time', {
    extend:'Ext.form.field.ComboBox',
    alias: 'widget.timefield',
    requires: ['Ext.form.field.Date', 'Ext.picker.Time', 'Ext.view.BoundListKeyNav', 'Ext.Date'],
    alternateClassName: ['Ext.form.TimeField', 'Ext.form.Time'],

    
    triggerCls: Ext.baseCSSPrefix + 'form-time-trigger',

    

    

    
    
    minText : "The time in this field must be equal to or after {0}",
    

    
    
    maxText : "The time in this field must be equal to or before {0}",
    

    
    
    invalidText : "{0} is not a valid time",
    

    
    
    format : "g:i A",
    

    
    
    

    
    
    altFormats : "g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H|gi a|hi a|giA|hiA|gi A|hi A",
    

    
    increment: 15,

    
    pickerMaxHeight: 300,

    
    selectOnTab: true,
    
    
    snapToIncrement: false,

    
    initDate: '1/1/2008',
    initDateFormat: 'j/n/Y',
    
    ignoreSelection: 0,

    queryMode: 'local',

    displayField: 'disp',

    valueField: 'date',

    initComponent: function() {
        var me = this,
            min = me.minValue,
            max = me.maxValue;
        if (min) {
            me.setMinValue(min);
        }
        if (max) {
            me.setMaxValue(max);
        }
        me.displayTpl = new Ext.XTemplate(
            '<tpl for=".">' +
                '{[typeof values === "string" ? values : this.formatDate(values["' + me.displayField + '"])]}' +
                '<tpl if="xindex < xcount">' + me.delimiter + '</tpl>' +
            '</tpl>', {
            formatDate: Ext.Function.bind(me.formatDate, me)
        });
        this.callParent();
    },

    
    transformOriginalValue: function(value) {
        if (Ext.isString(value)) {
            return this.rawToValue(value);
        }
        return value;
    },

    
    isEqual: function(v1, v2) {
        return Ext.Date.isEqual(v1, v2);
    },

    
    setMinValue: function(value) {
        var me = this,
            picker = me.picker;
        me.setLimit(value, true);
        if (picker) {
            picker.setMinValue(me.minValue);
        }
    },

    
    setMaxValue: function(value) {
        var me = this,
            picker = me.picker;
        me.setLimit(value, false);
        if (picker) {
            picker.setMaxValue(me.maxValue);
        }
    },

    
    setLimit: function(value, isMin) {
        var me = this,
            d, val;
        if (Ext.isString(value)) {
            d = me.parseDate(value);
        }
        else if (Ext.isDate(value)) {
            d = value;
        }
        if (d) {
            val = Ext.Date.clearTime(new Date(me.initDate));
            val.setHours(d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
        }
        
        else {
            val = null;
        }
        me[isMin ? 'minValue' : 'maxValue'] = val;
    },

    rawToValue: function(rawValue) {
        return this.parseDate(rawValue) || rawValue || null;
    },

    valueToRaw: function(value) {
        return this.formatDate(this.parseDate(value));
    },

    
    getErrors: function(value) {
        var me = this,
            format = Ext.String.format,
            errors = me.callParent(arguments),
            minValue = me.minValue,
            maxValue = me.maxValue,
            date;

        value = me.formatDate(value || me.processRawValue(me.getRawValue()));

        if (value === null || value.length < 1) { 
             return errors;
        }

        date = me.parseDate(value);
        if (!date) {
            errors.push(format(me.invalidText, value, Ext.Date.unescapeFormat(me.format)));
            return errors;
        }

        if (minValue && date < minValue) {
            errors.push(format(me.minText, me.formatDate(minValue)));
        }

        if (maxValue && date > maxValue) {
            errors.push(format(me.maxText, me.formatDate(maxValue)));
        }

        return errors;
    },

    formatDate: function() {
        return Ext.form.field.Date.prototype.formatDate.apply(this, arguments);
    },

    
    parseDate: function(value) {
        var me = this,
            val = value,
            altFormats = me.altFormats,
            altFormatsArray = me.altFormatsArray,
            i = 0,
            len;

        if (value && !Ext.isDate(value)) {
            val = me.safeParse(value, me.format);

            if (!val && altFormats) {
                altFormatsArray = altFormatsArray || altFormats.split('|');
                len = altFormatsArray.length;
                for (; i < len && !val; ++i) {
                    val = me.safeParse(value, altFormatsArray[i]);
                }
            }
        }

        
        if (val && me.snapToIncrement) {
            val = new Date(Ext.Number.snap(val.getTime(), me.increment * 60 * 1000));
        }
        return val;
    },

    safeParse: function(value, format){
        var me = this,
            utilDate = Ext.Date,
            parsedDate,
            result = null;

        if (utilDate.formatContainsDateInfo(format)) {
            
            result = utilDate.parse(value, format);
        } else {
            
            parsedDate = utilDate.parse(me.initDate + ' ' + value, me.initDateFormat + ' ' + format);
            if (parsedDate) {
                result = parsedDate;
            }
        }
        return result;
    },

    
    getSubmitValue: function() {
        var me = this,
            format = me.submitFormat || me.format,
            value = me.getValue();

        return value ? Ext.Date.format(value, format) : null;
    },

    
    createPicker: function() {
        var me = this,
            picker;

        me.listConfig = Ext.apply({
            xtype: 'timepicker',
            selModel: {
                mode: 'SINGLE'
            },
            cls: undefined,
            minValue: me.minValue,
            maxValue: me.maxValue,
            increment: me.increment,
            format: me.format,
            maxHeight: me.pickerMaxHeight
        }, me.listConfig);
        picker = me.callParent();
        me.store = picker.store;
        return picker;
    },
    
    onItemClick: function(picker, record){
        
        var me = this,
            selected = picker.getSelectionModel().getSelection();

        if (selected.length > 0) {
            selected = selected[0];
            if (selected && Ext.Date.isEqual(record.get('date'), selected.get('date'))) {
                me.collapse();
            }
        }
    },

    
    onListSelectionChange: function(list, recordArray) {
        var me = this,
            record = recordArray[0],
            val = record ? record.get('date') : null;
            
        if (!me.ignoreSelection) {
            me.skipSync = true;
            me.setValue(val);
            me.skipSync = false;
            me.fireEvent('select', me, val);
            me.picker.clearHighlight();
            me.collapse();
            me.inputEl.focus();
        }
    },
    
    
    syncSelection: function() {
        var me = this,
            picker = me.picker,
            toSelect,
            selModel,
            value,
            data, d, dLen, rec;
            
        if (picker && !me.skipSync) {
            picker.clearHighlight();
            value = me.getValue();
            selModel = picker.getSelectionModel();
            
            me.ignoreSelection++;
            if (value === null) {
                selModel.deselectAll();
            } else if(Ext.isDate(value)) {
                
                data = picker.store.data.items;
                dLen = data.length;

                for (d = 0; d < dLen; d++) {
                    rec = data[d];

                    if (Ext.Date.isEqual(rec.get('date'), value)) {
                       toSelect = rec;
                       break;
                   }
                }

                selModel.select(toSelect);
            }
            me.ignoreSelection--;
        }
    },

    postBlur: function() {
        var me = this;

        me.callParent(arguments);
        me.setRawValue(me.formatDate(me.getValue()));
    },

    setValue: function() {

        
        this.getPicker();

        this.callParent(arguments);
    },

    getValue: function() {
        return this.parseDate(this.callParent(arguments));
    }
});

Ext.define('Ext.view.Table', {
    extend: 'Ext.view.View',
    alias: 'widget.tableview',
    uses: [
        'Ext.view.TableLayout',
        'Ext.view.TableChunker',
        'Ext.util.DelayedTask',
        'Ext.util.MixedCollection'
    ],

    componentLayout: 'tableview',

    baseCls: Ext.baseCSSPrefix + 'grid-view',

    
    itemSelector: 'tr.' + Ext.baseCSSPrefix + 'grid-row',
    
    cellSelector: 'td.' + Ext.baseCSSPrefix + 'grid-cell',

    
    rowSelector: 'tr.' + Ext.baseCSSPrefix + 'grid-row',

    
    firstCls: Ext.baseCSSPrefix + 'grid-cell-first',

    
    lastCls: Ext.baseCSSPrefix + 'grid-cell-last',

    headerRowSelector: 'tr.' + Ext.baseCSSPrefix + 'grid-header-row',

    selectedItemCls: Ext.baseCSSPrefix + 'grid-row-selected',
    selectedCellCls: Ext.baseCSSPrefix + 'grid-cell-selected',
    focusedItemCls: Ext.baseCSSPrefix + 'grid-row-focused',
    overItemCls: Ext.baseCSSPrefix + 'grid-row-over',
    altRowCls:   Ext.baseCSSPrefix + 'grid-row-alt',
    rowClsRe: new RegExp('(?:^|\\s*)' + Ext.baseCSSPrefix + 'grid-row-(first|last|alt)(?:\\s+|$)', 'g'),
    cellRe: new RegExp(Ext.baseCSSPrefix + 'grid-cell-([^\\s]+) ', ''),

    
    trackOver: true,

    
    getRowClass: null,

    
    stripeRows: true,
    
    
    markDirty : true,

    

    
    initialTpl: '<div></div>',

    initComponent: function() {
        var me = this,
            scroll = me.scroll;

        
        me.table = new Ext.dom.Element.Fly();
        me.table.id = me.id + 'gridTable';

        
        
        me.autoScroll = undefined;

        
        if (scroll === true || scroll === 'both') {
            me.autoScroll = true;
        } else if (scroll === 'horizontal') {
            me.overflowX = 'auto';
        } else if (scroll === 'vertical') {
            me.overflowY = 'auto';
        }
        me.selModel.view = me;
        me.headerCt.view = me;
        me.headerCt.markDirty = me.markDirty;

        
        me.initFeatures(me.grid);
        delete me.grid;

        
        me.tpl = me.getTpl('initialTpl');
        me.callParent();
    },
    
    
    moveColumn: function(fromIdx, toIdx, colsToMove) {
        var me = this,
            fragment = (colsToMove > 1) ? document.createDocumentFragment() : undefined,
            destinationCellIdx = toIdx,
            colCount = me.getGridColumns().length,
            lastIdx = colCount - 1,
            doFirstLastClasses = (me.firstCls || me.lastCls) && (toIdx === 0 || toIdx == colCount || fromIdx === 0 || fromIdx == lastIdx),
            i,
            j,
            rows, len, tr, headerRows;

        if (me.rendered) {
            
            
            headerRows = me.el.query(me.headerRowSelector);
            rows = me.el.query(me.rowSelector);

            if (toIdx > fromIdx && fragment) {
                destinationCellIdx -= colsToMove;
            }

            
            for (i = 0, len = headerRows.length; i < len; ++i) {
                tr = headerRows[i];
                if (fragment) {
                    for (j = 0; j < colsToMove; j++) {
                        fragment.appendChild(tr.cells[fromIdx]);
                    }
                    tr.insertBefore(fragment, tr.cells[destinationCellIdx] || null);
                } else {
                    tr.insertBefore(tr.cells[fromIdx], tr.cells[destinationCellIdx] || null);
                }
            }

            for (i = 0, len = rows.length; i < len; i++) {
                tr = rows[i];

                
                if (doFirstLastClasses) {

                    if (fromIdx === 0) {
                        Ext.fly(tr.cells[0]).removeCls(me.firstCls);
                        Ext.fly(tr.cells[1]).addCls(me.firstCls);
                    } else if (fromIdx === lastIdx) {
                        Ext.fly(tr.cells[lastIdx]).removeCls(me.lastCls);
                        Ext.fly(tr.cells[lastIdx - 1]).addCls(me.lastCls);
                    }
                    if (toIdx === 0) {
                        Ext.fly(tr.cells[0]).removeCls(me.firstCls);
                        Ext.fly(tr.cells[fromIdx]).addCls(me.firstCls);
                    } else if (toIdx === colCount) {
                        Ext.fly(tr.cells[lastIdx]).removeCls(me.lastCls);
                        Ext.fly(tr.cells[fromIdx]).addCls(me.lastCls);
                    }
                }

                if (fragment) {
                    for (j = 0; j < colsToMove; j++) {
                        fragment.appendChild(tr.cells[fromIdx]);
                    }
                    tr.insertBefore(fragment, tr.cells[destinationCellIdx] || null);
                } else {
                    tr.insertBefore(tr.cells[fromIdx], tr.cells[destinationCellIdx] || null);
                }
            }
            me.setNewTemplate();
        }
    },

    
    scrollToTop: Ext.emptyFn,

    
    addElListener: function(eventName, fn, scope){
        this.mon(this, eventName, fn, scope, {
            element: 'el'
        });
    },

    
    getGridColumns: function() {
        return this.headerCt.getGridColumns();
    },

    
    getHeaderAtIndex: function(index) {
        return this.headerCt.getHeaderAtIndex(index);
    },

    
    getCell: function(record, column) {
        var row = this.getNode(record);
        return Ext.fly(row).down(column.getCellSelector());
    },

    
    getFeature: function(id) {
        var features = this.featuresMC;
        if (features) {
            return features.get(id);
        }
    },

    
    initFeatures: function(grid) {
        var me = this,
            i,
            features,
            feature,
            len;

        me.featuresMC = new Ext.util.MixedCollection();
        features = me.features = me.constructFeatures();
        len = features ? features.length : 0;
        for (i = 0; i < len; i++) {
            feature = features[i];

            
            feature.view = me;
            feature.grid = grid;
            me.featuresMC.add(feature);
            feature.init();
        }
    },

    
    constructFeatures: function() {
        var me = this,
            features = me.features,
            feature,
            result,
            i = 0, len;
        
        if (features) {
            result = [];
            len = features.length;
            for (; i < len; i++) {
                feature = features[i];
                if (!feature.isFeature) {
                    feature = Ext.create('feature.' + feature.ftype, feature);
                }
                result[i] = feature;
            }
        }
        return result;
    },

    
    attachEventsForFeatures: function() {
        var features = this.features,
            ln       = features.length,
            i        = 0;

        for (; i < ln; i++) {
            if (features[i].isFeature) {
                features[i].attachEvents();
            }
        }
    },

    afterRender: function() {
        var me = this;
        me.callParent();

        if (!me.enableTextSelection) {
            me.el.unselectable();
        }
        me.attachEventsForFeatures();
    },

    
    onViewScroll: function(e, t) {
        this.callParent(arguments);
        this.fireEvent('bodyscroll', e, t);
    },

    
    prepareData: function(data, idx, record) {
        var me       = this,
            result   = me.headerCt.prepareData(data, idx, record, me, me.ownerCt),
            features = me.features,
            ln       = features.length,
            i        = 0,
            feature;

        for (; i < ln; i++) {
            feature = features[i];
            if (feature.isFeature) {
                Ext.apply(result, feature.getAdditionalData(data, idx, record, result, me));
            }
        }

        return result;
    },

    
    collectData: function(records, startIndex) {
        var me = this,
            preppedRecords = me.callParent(arguments),
            headerCt  = me.headerCt,
            fullWidth = headerCt.getFullWidth(),
            features  = me.features,
            ln = features.length,
            o = {
                rows: preppedRecords,
                fullWidth: fullWidth
            },
            i  = 0,
            feature,
            j = 0,
            jln,
            rowParams,
            rec,
            cls;

        jln = preppedRecords.length;
        
        
        if (me.getRowClass) {
            for (; j < jln; j++) {
                rowParams = {};
                rec = preppedRecords[j];
                cls = rec.rowCls || '';
                rec.rowCls = this.getRowClass(records[j], j, rowParams, me.store) + ' ' + cls;
            }
        }
        
        
        for (; i < ln; i++) {
            feature = features[i];
            if (feature.isFeature && feature.collectData && !feature.disabled) {
                o = feature.collectData(records, preppedRecords, startIndex, fullWidth, o);
                break;
            }
        }
        return o;
    },

    
    
    
    
    
    
    refreshSize: function() {
        var me = this,
            cmp;

        
        me.table.attach(me.el.child('table', true));

        if (!me.hasLoadingHeight) {
            cmp = me.up('tablepanel');

            
            
            Ext.suspendLayouts();

            me.callParent();

            
            
            if (cmp && Ext.getScrollbarSize().width && (me.autoScroll || me.overflowY)) {
                cmp.updateLayout();
            }

            Ext.resumeLayouts(true);
        }
    },

    
    setNewTemplate: function() {
        var me = this,
            columns = me.headerCt.getColumnsForTpl(true);

        
        me.tpl = me.getTableChunker().getTableTpl({
            rowCount: me.store.getCount(),
            columns: columns,
            features: me.features,
            enableTextSelection: me.enableTextSelection
        });
    },

    
    getTableChunker: function() {
        return this.chunker || Ext.view.TableChunker;
    },

    
    addRowCls: function(rowInfo, cls) {
        var row = this.getNode(rowInfo);
        if (row) {
            Ext.fly(row).addCls(cls);
        }
    },

    
    removeRowCls: function(rowInfo, cls) {
        var row = this.getNode(rowInfo);
        if (row) {
            Ext.fly(row).removeCls(cls);
        }
    },

    
    onRowSelect : function(rowIdx) {
        this.addRowCls(rowIdx, this.selectedItemCls);
    },

    
    onRowDeselect : function(rowIdx) {
        var me = this;

        me.removeRowCls(rowIdx, me.selectedItemCls);
        me.removeRowCls(rowIdx, me.focusedItemCls);
    },

    onCellSelect: function(position) {
        var cell = this.getCellByPosition(position, true);
        if (cell) {
            Ext.fly(cell).addCls(this.selectedCellCls);
        }
    },

    onCellDeselect: function(position) {
        var cell = this.getCellByPosition(position, true);
        if (cell) {
            Ext.fly(cell).removeCls(this.selectedCellCls);
        }

    },

    onCellFocus: function(position) {
        this.focusCell(position);
    },

    getCellByPosition: function(position, returnDom) {
        if (position) {
            var node   = this.getNode(position.row),
                header = this.headerCt.getHeaderAtIndex(position.column);

            if (header && node) {
                return Ext.fly(node).down(header.getCellSelector(), returnDom);
            }
        }
        return false;
    },

    
    
    onRowFocus: function(rowIdx, highlight, supressFocus) {
        var me = this;

        if (highlight) {
            me.addRowCls(rowIdx, me.focusedItemCls);
            if (!supressFocus) {
                me.focusRow(rowIdx);
            }
            
        } else {
            me.removeRowCls(rowIdx, me.focusedItemCls);
        }
    },

    
    focusRow: function(rowIdx) {
        var me         = this,
            row        = me.getNode(rowIdx),
            el         = me.el,
            adjustment = 0,
            panel      = me.ownerCt,
            rowRegion,
            elTop,
            elBottom,
            record;

        if (row && el) {
            
            
            elTop = el.getY();
            elBottom = elTop + el.dom.clientHeight;
            rowRegion = Ext.fly(row).getRegion();
            
            if (rowRegion.top < elTop) {
                adjustment = rowRegion.top - elTop;
            
            } else if (rowRegion.bottom > elBottom) {
                adjustment = rowRegion.bottom - elBottom;
            }
            record = me.getRecord(row);
            rowIdx = me.store.indexOf(record);

            if (adjustment) {
                panel.scrollByDeltaY(adjustment);
            }
            me.fireEvent('rowfocus', record, row, rowIdx);
        }
    },

    focusCell: function(position) {
        var me          = this,
            cell        = me.getCellByPosition(position),
            el          = me.el,
            adjustmentY = 0,
            adjustmentX = 0,
            elRegion    = el.getRegion(),
            panel       = me.ownerCt,
            cellRegion,
            record;

        
        
        elRegion.bottom = elRegion.top + el.dom.clientHeight;
        elRegion.right = elRegion.left + el.dom.clientWidth;
        if (cell) {
            cellRegion = cell.getRegion();
            
            if (cellRegion.top < elRegion.top) {
                adjustmentY = cellRegion.top - elRegion.top;
            
            } else if (cellRegion.bottom > elRegion.bottom) {
                adjustmentY = cellRegion.bottom - elRegion.bottom;
            }

            
            if (cellRegion.left < elRegion.left) {
                adjustmentX = cellRegion.left - elRegion.left;
            
            } else if (cellRegion.right > elRegion.right) {
                adjustmentX = cellRegion.right - elRegion.right;
            }

            if (adjustmentY) {
                panel.scrollByDeltaY(adjustmentY);
            }
            if (adjustmentX) {
                panel.scrollByDeltaX(adjustmentX);
            }
            el.focus();
            me.fireEvent('cellfocus', record, cell, position);
        }
    },

    
    scrollByDelta: function(delta, dir) {
        dir = dir || 'scrollTop';
        var elDom = this.el.dom;
        elDom[dir] = (elDom[dir] += delta);
    },

    
    onUpdate : function(store, record, operation, changedFieldNames) {
        var me = this,
            index,
            newRow, newAttrs, attLen, i, attName, oldRow, oldRowDom,
            oldCells, newCells, len, i,
            columns, overItemCls,
            isHovered, row,
            
            isEditing = me.editingPlugin && me.editingPlugin.editing;

        if (me.viewReady) {

            index = me.store.indexOf(record);
            columns = me.headerCt.getGridColumns();
            overItemCls = me.overItemCls;

            
            
            if (columns.length && index > -1) {
                newRow = me.bufferRender([record], index)[0];
                oldRow = me.all.item(index);
                if (oldRow) {
                    oldRowDom = oldRow.dom;
                    isHovered = oldRow.hasCls(overItemCls);

                    
                    if (oldRowDom.mergeAttributes) {
                        oldRowDom.mergeAttributes(newRow, true);
                    } else {
                        newAttrs = newRow.attributes;
                        attLen = newAttrs.length;
                        for (i = 0; i < attLen; i++) {
                            attName = newAttrs[i].name;
                            if (attName !== 'id') {
                                oldRowDom.setAttribute(attName, newAttrs[i].value);
                            }
                        }
                    }

                    if (isHovered) {
                        oldRow.addCls(overItemCls);
                    }

                    
                    oldCells = oldRow.query(me.cellSelector);
                    newCells = Ext.fly(newRow).query(me.cellSelector);
                    len = newCells.length;
                    
                    row = oldCells[0].parentNode;
                    for (i = 0; i < len; i++) {
                        
                        
                        if (me.shouldUpdateCell(columns[i], changedFieldNames)) {
                            
                            if (isEditing) {
                                Ext.fly(oldCells[i]).syncContent(newCells[i]);
                            }
                            
                            else {
                                row.insertBefore(newCells[i], oldCells[i]);
                                row.removeChild(oldCells[i]);
                            }
                        }
                    }
                }
                me.fireEvent('itemupdate', record, index, newRow);
            }
        }
    },
    
    shouldUpdateCell: function(column, changedFieldNames){
        
        
        if (column.hasCustomRenderer) {
            return true;
        }
        return !changedFieldNames || Ext.Array.contains(changedFieldNames, column.dataIndex);
    },

    
    refresh: function() {
        var me = this;
        me.setNewTemplate();
        me.callParent(arguments);
        me.doStripeRows(0);
        me.headerCt.setSortState();
    },

    clearViewEl: function() {
        this.callParent();
        delete this.table.dom;
    },

    processItemEvent: function(record, row, rowIndex, e) {
        var me = this,
            cell = e.getTarget(me.cellSelector, row),
            cellIndex = cell ? cell.cellIndex : -1,
            map = me.statics().EventMap,
            selModel = me.getSelectionModel(),
            type = e.type,
            result;

        if (type == 'keydown' && !cell && selModel.getCurrentPosition) {
            
            cell = me.getCellByPosition(selModel.getCurrentPosition());
            if (cell) {
                cell = cell.dom;
                cellIndex = cell.cellIndex;
            }
        }

        result = me.fireEvent('uievent', type, me, cell, rowIndex, cellIndex, e, record, row);

        if (result === false || me.callParent(arguments) === false) {
            return false;
        }

        
        if (type == 'mouseover' || type == 'mouseout') {
            return true;
        }

        if(!cell) {
            
            
            return true;
        }

        return !(
            
            (me['onBeforeCell' + map[type]](cell, cellIndex, record, row, rowIndex, e) === false) ||
            (me.fireEvent('beforecell' + type, me, cell, cellIndex, record, row, rowIndex, e) === false) ||
            (me['onCell' + map[type]](cell, cellIndex, record, row, rowIndex, e) === false) ||
            (me.fireEvent('cell' + type, me, cell, cellIndex, record, row, rowIndex, e) === false)
        );
    },

    processSpecialEvent: function(e) {
        var me = this,
            map = me.statics().EventMap,
            features = me.features,
            ln = features.length,
            type = e.type,
            i, feature, prefix, featureTarget,
            beforeArgs, args,
            panel = me.ownerCt;

        me.callParent(arguments);

        if (type == 'mouseover' || type == 'mouseout') {
            return;
        }

        for (i = 0; i < ln; i++) {
            feature = features[i];
            if (feature.hasFeatureEvent) {
                featureTarget = e.getTarget(feature.eventSelector, me.getTargetEl());
                if (featureTarget) {
                    prefix = feature.eventPrefix;
                    
                    
                    beforeArgs = feature.getFireEventArgs('before' + prefix + type, me, featureTarget, e);
                    args = feature.getFireEventArgs(prefix + type, me, featureTarget, e);

                    if (
                        
                        (me.fireEvent.apply(me, beforeArgs) === false) ||
                        
                        (panel.fireEvent.apply(panel, beforeArgs) === false) ||
                        
                        (me.fireEvent.apply(me, args) === false) ||
                        
                        (panel.fireEvent.apply(panel, args) === false)
                    ) {
                        return false;
                    }
                }
            }
        }
        return true;
    },

    onCellMouseDown: Ext.emptyFn,
    onCellMouseUp: Ext.emptyFn,
    onCellClick: Ext.emptyFn,
    onCellDblClick: Ext.emptyFn,
    onCellContextMenu: Ext.emptyFn,
    onCellKeyDown: Ext.emptyFn,
    onBeforeCellMouseDown: Ext.emptyFn,
    onBeforeCellMouseUp: Ext.emptyFn,
    onBeforeCellClick: Ext.emptyFn,
    onBeforeCellDblClick: Ext.emptyFn,
    onBeforeCellContextMenu: Ext.emptyFn,
    onBeforeCellKeyDown: Ext.emptyFn,

    
    expandToFit: function(header) {
        if (header) {
            var maxWidth = this.getMaxContentWidth(header);
            delete header.flex;
            header.setWidth(maxWidth);
        }
    },

    
    getMaxContentWidth: function(header) {
        var cellSelector = header.getCellInnerSelector(),
            cells        = this.el.query(cellSelector),
            i = 0,
            ln = cells.length,
            maxWidth = header.el.dom.scrollWidth,
            scrollWidth;

        for (; i < ln; i++) {
            scrollWidth = cells[i].scrollWidth;
            if (scrollWidth > maxWidth) {
                maxWidth = scrollWidth;
            }
        }
        return maxWidth;
    },

    getPositionByEvent: function(e) {
        var me       = this,
            cellNode = e.getTarget(me.cellSelector),
            rowNode  = e.getTarget(me.itemSelector),
            record   = me.getRecord(rowNode),
            header   = me.getHeaderByCell(cellNode);

        return me.getPosition(record, header);
    },

    getHeaderByCell: function(cell) {
        if (cell) {
            var m = cell.className.match(this.cellRe);
            if (m && m[1]) {
                return Ext.getCmp(m[1]);
            }
        }
        return false;
    },

    
    walkCells: function(pos, direction, e, preventWrap, verifierFn, scope) {

        
        
        if (!pos) {
            return;
        }

        var me       = this,
            row      = pos.row,
            column   = pos.column,
            rowCount = me.store.getCount(),
            firstCol = me.getFirstVisibleColumnIndex(),
            lastCol  = me.getLastVisibleColumnIndex(),
            newPos   = {row: row, column: column},
            activeHeader = me.headerCt.getHeaderAtIndex(column);

        
        if (!activeHeader || activeHeader.hidden) {
            return false;
        }

        e = e || {};
        direction = direction.toLowerCase();
        switch (direction) {
            case 'right':
                
                if (column === lastCol) {
                    
                    if (preventWrap || row === rowCount - 1) {
                        return false;
                    }
                    if (!e.ctrlKey) {
                        
                        newPos.row = row + 1;
                        newPos.column = firstCol;
                    }
                
                } else {
                    if (!e.ctrlKey) {
                        newPos.column = column + me.getRightGap(activeHeader);
                    } else {
                        newPos.column = lastCol;
                    }
                }
                break;

            case 'left':
                
                if (column === firstCol) {
                    
                    if (preventWrap || row === 0) {
                        return false;
                    }
                    if (!e.ctrlKey) {
                        
                        newPos.row = row - 1;
                        newPos.column = lastCol;
                    }
                
                } else {
                    if (!e.ctrlKey) {
                        newPos.column = column + me.getLeftGap(activeHeader);
                    } else {
                        newPos.column = firstCol;
                    }
                }
                break;

            case 'up':
                
                if (row === 0) {
                    return false;
                
                } else {
                    if (!e.ctrlKey) {
                        newPos.row = row - 1;
                    } else {
                        newPos.row = 0;
                    }
                }
                break;

            case 'down':
                
                if (row === rowCount - 1) {
                    return false;
                
                } else {
                    if (!e.ctrlKey) {
                        newPos.row = row + 1;
                    } else {
                        newPos.row = rowCount - 1;
                    }
                }
                break;
        }

        if (verifierFn && verifierFn.call(scope || window, newPos) !== true) {
            return false;
        } else {
            return newPos;
        }
    },
    getFirstVisibleColumnIndex: function() {
        var firstVisibleHeader = this.getHeaderCt().getVisibleGridColumns()[0];

        return firstVisibleHeader ? firstVisibleHeader.getIndex() : -1;
    },

    getLastVisibleColumnIndex: function() {
        var visHeaders = this.getHeaderCt().getVisibleGridColumns(),
            lastHeader = visHeaders[visHeaders.length - 1];

        return lastHeader.getIndex();
    },

    getHeaderCt: function() {
        return this.headerCt;
    },

    
    getPosition: function(record, header) {
        var me = this,
            store = me.store,
            gridCols = me.headerCt.getGridColumns();

        return {
            row: store.indexOf(record),
            column: Ext.Array.indexOf(gridCols, header)
        };
    },

    
    getRightGap: function(activeHeader) {
        var headerCt        = this.getHeaderCt(),
            headers         = headerCt.getGridColumns(),
            activeHeaderIdx = Ext.Array.indexOf(headers, activeHeader),
            i               = activeHeaderIdx + 1,
            nextIdx;

        for (; i <= headers.length; i++) {
            if (!headers[i].hidden) {
                nextIdx = i;
                break;
            }
        }

        return nextIdx - activeHeaderIdx;
    },

    beforeDestroy: function() {
        if (this.rendered) {
            this.el.removeAllListeners();
        }
        this.callParent(arguments);
    },

    
    getLeftGap: function(activeHeader) {
        var headerCt        = this.getHeaderCt(),
            headers         = headerCt.getGridColumns(),
            activeHeaderIdx = Ext.Array.indexOf(headers, activeHeader),
            i               = activeHeaderIdx - 1,
            prevIdx;

        for (; i >= 0; i--) {
            if (!headers[i].hidden) {
                prevIdx = i;
                break;
            }
        }

        return prevIdx - activeHeaderIdx;
    },

    
    onAdd: function(ds, records, index) {
        this.callParent(arguments);
        this.doStripeRows(index);
    },
    
    
    onRemove: function(ds, records, index) {
        this.callParent(arguments);
        this.doStripeRows(index);
    },
    
    
    doStripeRows: function(startRow, endRow) {
        var me = this,
            rows,
            rowsLn,
            i,
            row;
            
        
        if (me.rendered && me.stripeRows) {
            rows = me.getNodes(startRow, endRow);
                
            for (i = 0, rowsLn = rows.length; i < rowsLn; i++) {
                row = rows[i];
                
                row.className = row.className.replace(me.rowClsRe, ' ');
                startRow++;
                
                if (startRow % 2 === 0) {
                    row.className += (' ' + me.altRowCls);
                }
            }
        }
    }
 
});


Ext.define('Ext.grid.Lockable', {

    requires: [
        'Ext.grid.LockingView',
        'Ext.view.Table'
    ],

    
    syncRowHeight: true,

    

    

    

    headerCounter: 0,

    
    scrollDelta: 40,
    
    
    
    

    
    
    unlockText: 'Unlock',
    
    
    lockText: 'Lock',
    

    determineXTypeToCreate: function() {
        var me = this,
            typeToCreate,
            xtypes, xtypesLn, xtype, superxtype;

        if (me.subGridXType) {
            typeToCreate = me.subGridXType;
        } else {
            xtypes     = this.getXTypes().split('/');
            xtypesLn   = xtypes.length;
            xtype      = xtypes[xtypesLn - 1];
            superxtype = xtypes[xtypesLn - 2];

            if (superxtype !== 'tablepanel') {
                typeToCreate = superxtype;
            } else {
                typeToCreate = xtype;
            }
        }

        return typeToCreate;
    },

    
    
    injectLockable: function() {
        
        this.lockable = true;
        
        
        this.hasView = true;

        var me = this,
            
            scrollLocked = Ext.getScrollbarSize().width === 0,
            store = me.store = Ext.StoreManager.lookup(me.store),
            
            
            
            xtype = me.determineXTypeToCreate(),
            
            selModel = me.getSelectionModel(),
            lockedFeatures,
            normalFeatures,
            lockedPlugins,
            normalPlugins,
            lockedGrid,
            normalGrid,
            i, len,
            columns,
            lockedHeaderCt,
            normalHeaderCt,
            lockedView,
            normalView,
            listeners;

        lockedFeatures = me.constructFeatures();

        
        me.cloneFeatures();
        normalFeatures = me.constructFeatures();

        lockedPlugins = me.constructPlugins();

        
        me.clonePlugins();
        normalPlugins = me.constructPlugins();

        
        delete me.features;
        delete me.plugins;

        
        for (i = 0, len = (lockedFeatures ? lockedFeatures.length : 0); i < len; i++) {
            lockedFeatures[i].lockingPartner = normalFeatures[i];
            normalFeatures[i].lockingPartner = lockedFeatures[i];
        }

        lockedGrid = Ext.apply({
            xtype: xtype,
            store: store,
            scrollerOwner: false,
            
            enableAnimations: false,
            scroll: scrollLocked ? 'vertical' : false,
            selModel: selModel,
            border: false,
            cls: Ext.baseCSSPrefix + 'grid-inner-locked',
            isLayoutRoot: function() {
                return false;
            },
            features: lockedFeatures,
            plugins: lockedPlugins
        }, me.lockedGridConfig);

        normalGrid = Ext.apply({
            xtype: xtype,
            store: store,
            scrollerOwner: false,
            enableAnimations: false,
            selModel: selModel,
            border: false,
            isLayoutRoot: function() {
                return false;
            },
            features: normalFeatures,
            plugins: normalPlugins
        }, me.normalGridConfig);

        me.addCls(Ext.baseCSSPrefix + 'grid-locked');

        
        
        
        Ext.copyTo(normalGrid, me, me.bothCfgCopy);
        Ext.copyTo(lockedGrid, me, me.bothCfgCopy);
        Ext.copyTo(normalGrid, me, me.normalCfgCopy);
        Ext.copyTo(lockedGrid, me, me.lockedCfgCopy);
        for (i = 0; i < me.normalCfgCopy.length; i++) {
            delete me[me.normalCfgCopy[i]];
        }
        for (i = 0; i < me.lockedCfgCopy.length; i++) {
            delete me[me.lockedCfgCopy[i]];
        }

        me.addEvents(
            
            'lockcolumn',

            
            'unlockcolumn'
        );

        me.addStateEvents(['lockcolumn', 'unlockcolumn']);

        me.lockedHeights = [];
        me.normalHeights = [];

        columns = me.processColumns(me.columns);

        lockedGrid.width = columns.lockedWidth + Ext.num(selModel.headerWidth, 0);
        lockedGrid.columns = columns.locked;
        normalGrid.columns = columns.normal;

        
        normalGrid.flex = 1;
        lockedGrid.viewConfig = me.lockedViewConfig || {};
        lockedGrid.viewConfig.loadingUseMsg = false;
        normalGrid.viewConfig = me.normalViewConfig || {};

        Ext.applyIf(lockedGrid.viewConfig, me.viewConfig);
        Ext.applyIf(normalGrid.viewConfig, me.viewConfig);

        me.lockedGrid = Ext.ComponentManager.create(lockedGrid);
        lockedView = me.lockedGrid.getView();
        
        normalGrid.viewConfig.lockingPartner = lockedView;
        me.normalGrid = Ext.ComponentManager.create(normalGrid);
        normalView = me.normalGrid.getView();

        me.view = new Ext.grid.LockingView({
            locked: me.lockedGrid,
            normal: me.normalGrid,
            panel: me
        });

        
        listeners = {
            scroll: {
                fn: me.onLockedViewScroll,
                element: 'el',
                scope: me
            }
        };
        
        if (!scrollLocked) {
            listeners.mousewheel = {
                fn: me.onLockedViewMouseWheel,
                element: 'el',
                scope: me
            };
        }
        if (me.syncRowHeight) {
            listeners.refresh = me.onLockedViewRefresh;
            listeners.itemupdate = me.onLockedViewItemUpdate;
            listeners.scope = me;
        }
        lockedView.on(listeners);

        
        listeners = {
            scroll: {
                fn: me.onNormalViewScroll,
                element: 'el',
                scope: me
            },
            refresh: me.syncRowHeight ? me.onNormalViewRefresh : me.updateSpacer,
            scope: me
        };
        normalView.on(listeners);

        lockedHeaderCt = me.lockedGrid.headerCt;
        normalHeaderCt = me.normalGrid.headerCt;

        lockedHeaderCt.lockedCt = true;
        lockedHeaderCt.lockableInjected = true;
        normalHeaderCt.lockableInjected = true;

        lockedHeaderCt.on({
            columnshow: me.onLockedHeaderShow,
            columnhide: me.onLockedHeaderHide,
            columnmove: me.onLockedHeaderMove,
            sortchange: me.onLockedHeaderSortChange,
            columnresize: me.onLockedHeaderResize,
            scope: me
        });

        normalHeaderCt.on({
            columnmove: me.onNormalHeaderMove,
            sortchange: me.onNormalHeaderSortChange,
            scope: me
        });

        me.modifyHeaderCt();
        me.items = [me.lockedGrid, me.normalGrid];

        me.relayHeaderCtEvents(lockedHeaderCt);
        me.relayHeaderCtEvents(normalHeaderCt);

        me.layout = {
            type: 'hbox',
            align: 'stretch'
        };
    },

    processColumns: function(columns){
        
        var i = 0,
            len = columns.length,
            lockedWidth = 0,
            lockedHeaders = [],
            normalHeaders = [],
            column;

        for (; i < len; ++i) {
            column = columns[i];
            
            
            if (!column.isComponent) {
                column = Ext.apply({}, columns[i]);
            }

            
            
            column.processed = true;
            if (column.locked) {
                if (!column.hidden) {
                    lockedWidth += column.width || Ext.grid.header.Container.prototype.defaultWidth;
                }
                lockedHeaders.push(column);
            } else {
                normalHeaders.push(column);
            }
            if (!column.headerId) {
                column.headerId = (column.initialConfig || column).id || ('L' + (++this.headerCounter));
            }
        }
        return {
            lockedWidth: lockedWidth,
            locked: {
                items: lockedHeaders,
                itemId: 'lockedHeaderCt',
                stretchMaxPartner: '^^>>#normalHeaderCt'
            },
            normal: {
                items: normalHeaders,
                itemId: 'normalHeaderCt',
                stretchMaxPartner: '^^>>#lockedHeaderCt'
            }
        };
    },

    
    onLockedViewMouseWheel: function(e) {
        var me = this,
            scrollDelta = -me.scrollDelta,
            deltaY = scrollDelta * e.getWheelDeltas().y,
            vertScrollerEl = me.lockedGrid.getView().el.dom,
            verticalCanScrollDown, verticalCanScrollUp;

        if (vertScrollerEl) {
            verticalCanScrollDown = vertScrollerEl.scrollTop !== vertScrollerEl.scrollHeight - vertScrollerEl.clientHeight;
            verticalCanScrollUp   = vertScrollerEl.scrollTop !== 0;
        }

        if ((deltaY < 0 && verticalCanScrollUp) || (deltaY > 0 && verticalCanScrollDown)) {
            e.stopEvent();

            
            
            
            me.scrolling = true;
            vertScrollerEl.scrollTop += deltaY;
            me.normalGrid.getView().el.dom.scrollTop = vertScrollerEl.scrollTop;
            me.scrolling = false;

            
            me.onNormalViewScroll();
        }
    },

    onLockedViewScroll: function() {
        var me = this,
            lockedView = me.lockedGrid.getView(),
            normalView = me.normalGrid.getView(),
            normalTable,
            lockedTable;

        
        if (!me.scrolling) {
            me.scrolling = true;
            normalView.el.dom.scrollTop = lockedView.el.dom.scrollTop;
    
            
            if (me.store.buffered) {
                lockedTable = lockedView.el.child('table', true);
                normalTable = normalView.el.child('table', true);
                lockedTable.style.position = 'absolute';
            }
            me.scrolling = false;
        }
    },
    
    onNormalViewScroll: function() {
        var me = this,
            lockedView = me.lockedGrid.getView(),
            normalView = me.normalGrid.getView(),
            normalTable,
            lockedTable;

        
        if (!me.scrolling) {
            me.scrolling = true;
            lockedView.el.dom.scrollTop = normalView.el.dom.scrollTop;
    
            
            if (me.store.buffered) {
                lockedTable = lockedView.el.child('table', true);
                normalTable = normalView.el.child('table', true);
                lockedTable.style.position = 'absolute';
                lockedTable.style.top = normalTable.style.top;
            }
            me.scrolling = false;
        }
    },

    
    onLockedHeaderMove: function() {
        if (this.syncRowHeight) {
            this.onNormalViewRefresh();
        }
    },

    
    onNormalHeaderMove: function() {
        if (this.syncRowHeight) {
            this.onLockedViewRefresh();
        }
    },
    
    
    
    
    
    updateSpacer: function() {
        var me   = this,
            
            
            lockedViewEl   = me.lockedGrid.getView().el,
            normalViewEl = me.normalGrid.getView().el.dom,
            spacerId = lockedViewEl.dom.id + '-spacer',
            spacerHeight = (normalViewEl.offsetHeight - normalViewEl.clientHeight) + 'px';

        me.spacerEl = Ext.getDom(spacerId);
        if (me.spacerEl) {
            me.spacerEl.style.height = spacerHeight;
        } else {
            Ext.core.DomHelper.append(lockedViewEl, {
                id: spacerId,
                style: 'height: ' + spacerHeight
            });
        }
    },

    
    onLockedViewRefresh: function() {

        
        if (this.normalGrid.headerCt.getGridColumns().length) {
            var me     = this,
                view   = me.lockedGrid.getView(),
                el     = view.el,
                rowEls = el.query(view.getItemSelector()),
                ln     = rowEls.length,
                i = 0;
    
            
            me.lockedHeights = [];

            for (; i < ln; i++) {
                me.lockedHeights[i] = rowEls[i].offsetHeight;
            }
            me.syncRowHeights();
            me.updateSpacer();
        }
    },

    
    onNormalViewRefresh: function() {

        
        if (this.lockedGrid.headerCt.getGridColumns().length) {
            var me     = this,
                view   = me.normalGrid.getView(),
                el     = view.el,
                rowEls = el.query(view.getItemSelector()),
                ln     = rowEls.length,
                i = 0;
    
            
            me.normalHeights = [];
    
            for (; i < ln; i++) {
                me.normalHeights[i] = rowEls[i].offsetHeight;
            }
            me.syncRowHeights();
            me.updateSpacer();
        }
    },

    
    onLockedViewItemUpdate: function(record, index, node) {

        
        if (this.normalGrid.headerCt.getGridColumns().length) {
            this.lockedHeights[index] = node.offsetHeight;
            this.syncRowHeights();
        }
    },

    
    onNormalViewItemUpdate: function(record, index, node) {
    
        
        if (this.lockedGrid.headerCt.getGridColumns().length) {
            this.normalHeights[index] = node.offsetHeight;
            this.syncRowHeights();
        }
    },

    
    syncRowHeights: function() {
        var me = this,
            lockedHeights = me.lockedHeights,
            normalHeights = me.normalHeights,
            ln = lockedHeights.length,
            i  = 0,
            lockedView, normalView,
            lockedRowEls, normalRowEls,
            scrollTop;

        
        
        if (lockedHeights.length && normalHeights.length) {
            lockedView = me.lockedGrid.getView();
            normalView = me.normalGrid.getView();
            lockedRowEls = lockedView.el.query(lockedView.getItemSelector());
            normalRowEls = normalView.el.query(normalView.getItemSelector());

            
            for (; i < ln; i++) {
                
                if (!isNaN(lockedHeights[i]) && !isNaN(normalHeights[i])) {
                    if (lockedHeights[i] > normalHeights[i]) {
                        Ext.fly(normalRowEls[i]).setHeight(lockedHeights[i]);
                    } else if (lockedHeights[i] < normalHeights[i]) {
                        Ext.fly(lockedRowEls[i]).setHeight(normalHeights[i]);
                    }
                }
            }

            
            scrollTop = normalView.el.dom.scrollTop;
            normalView.el.dom.scrollTop = scrollTop;
            lockedView.el.dom.scrollTop = scrollTop;
            
            
            me.lockedHeights = [];
            me.normalHeights = [];
        }
    },

    
    modifyHeaderCt: function() {
        var me = this;
        me.lockedGrid.headerCt.getMenuItems = me.getMenuItems(me.lockedGrid.headerCt.getMenuItems, true);
        me.normalGrid.headerCt.getMenuItems = me.getMenuItems(me.normalGrid.headerCt.getMenuItems, false);
    },

    onUnlockMenuClick: function() {
        this.unlock();
    },

    onLockMenuClick: function() {
        this.lock();
    },

    getMenuItems: function(getMenuItems, locked) {
        var me            = this,
            unlockText    = me.unlockText,
            lockText      = me.lockText,
            unlockCls     = Ext.baseCSSPrefix + 'hmenu-unlock',
            lockCls       = Ext.baseCSSPrefix + 'hmenu-lock',
            unlockHandler = Ext.Function.bind(me.onUnlockMenuClick, me),
            lockHandler   = Ext.Function.bind(me.onLockMenuClick, me);

        
        return function() {

            
            
            var o = getMenuItems.call(this);
            o.push('-', {
                cls: unlockCls,
                text: unlockText,
                handler: unlockHandler,
                disabled: !locked
            });
            o.push({
                cls: lockCls,
                text: lockText,
                handler: lockHandler,
                disabled: locked
            });
            return o;
        };
    },

    
    
    lock: function(activeHd, toIdx) {
        var me         = this,
            normalGrid = me.normalGrid,
            lockedGrid = me.lockedGrid,
            normalHCt  = normalGrid.headerCt,
            lockedHCt  = lockedGrid.headerCt;

        activeHd = activeHd || normalHCt.getMenu().activeHeader;

        
        
        if (activeHd.flex) {
            activeHd.width = activeHd.getWidth();
            delete activeHd.flex;
        }

        Ext.suspendLayouts();
        activeHd.ownerCt.remove(activeHd, false);
        activeHd.locked = true;
        if (Ext.isDefined(toIdx)) {
            lockedHCt.insert(toIdx, activeHd);
        } else {
            lockedHCt.add(activeHd);
        }
        me.syncLockedSection();
        Ext.resumeLayouts(true);
        me.updateSpacer();

        me.fireEvent('lockcolumn', me, activeHd);
    },

    syncLockedSection: function() {
        var me = this;
        me.syncLockedWidth();
        me.lockedGrid.getView().refresh();
        me.normalGrid.getView().refresh();
    },

    
    
    syncLockedWidth: function() {
        var me = this,
            locked = me.lockedGrid,
            width = locked.headerCt.getFullWidth(true);
            
        Ext.suspendLayouts();
        if (width > 0) {
            locked.setWidth(width);
            locked.show();
        } else {
            locked.hide();
        }
        Ext.resumeLayouts(true);
        
        return width > 0;
    },

    onLockedHeaderResize: function() {
        this.syncLockedWidth();
    },

    onLockedHeaderHide: function() {
        this.syncLockedWidth();
    },

    onLockedHeaderShow: function() {
        this.syncLockedWidth();
    },

    onLockedHeaderSortChange: function(headerCt, header, sortState) {
        if (sortState) {
            
            
            this.normalGrid.headerCt.clearOtherSortStates(null, true);
        }
    },

    onNormalHeaderSortChange: function(headerCt, header, sortState) {
        if (sortState) {
            
            
            this.lockedGrid.headerCt.clearOtherSortStates(null, true);
        }
    },

    
    
    unlock: function(activeHd, toIdx) {
        var me         = this,
            normalGrid = me.normalGrid,
            lockedGrid = me.lockedGrid,
            normalHCt  = normalGrid.headerCt,
            lockedHCt  = lockedGrid.headerCt,
            refreshLocked = false;

        if (!Ext.isDefined(toIdx)) {
            toIdx = 0;
        }
        activeHd = activeHd || lockedHCt.getMenu().activeHeader;

        Ext.suspendLayouts();
        activeHd.ownerCt.remove(activeHd, false);
        if (me.syncLockedWidth()) {
            refreshLocked = true;
        }
        activeHd.locked = false;

        
        normalHCt.insert(toIdx, activeHd);
        me.normalGrid.getView().refresh();

        if (refreshLocked) {
            me.lockedGrid.getView().refresh();
        }
        Ext.resumeLayouts(true);

        me.fireEvent('unlockcolumn', me, activeHd);
    },

    applyColumnsState: function (columns) {
        var me             = this,
            lockedGrid     = me.lockedGrid,
            lockedHeaderCt = lockedGrid.headerCt,
            normalHeaderCt = me.normalGrid.headerCt,
            lockedCols     = Ext.Array.toMap(lockedHeaderCt.items, 'headerId'),
            normalCols     = Ext.Array.toMap(normalHeaderCt.items, 'headerId'),
            locked         = [],
            normal         = [],
            lockedWidth    = 1,
            length         = columns.length,
            i, existing,
            lockedDefault,
            col;

        for (i = 0; i < length; i++) {
            col = columns[i];

            lockedDefault = lockedCols[col.id];
            existing = lockedDefault || normalCols[col.id];

            if (existing) {
                if (existing.applyColumnState) {
                    existing.applyColumnState(col);
                }
                if (existing.locked === undefined) {
                    existing.locked = !!lockedDefault;
                }
                if (existing.locked) {
                    locked.push(existing);
                    if (!existing.hidden && typeof existing.width == 'number') {
                        lockedWidth += existing.width;
                    }
                } else {
                    normal.push(existing);
                }
            }
        }

        
        if (locked.length + normal.length == lockedHeaderCt.items.getCount() + normalHeaderCt.items.getCount()) {
            lockedHeaderCt.removeAll(false);
            normalHeaderCt.removeAll(false);

            lockedHeaderCt.add(locked);
            normalHeaderCt.add(normal);

            lockedGrid.setWidth(lockedWidth);
        }
    },

    getColumnsState: function () {
        var me = this,
            locked = me.lockedGrid.headerCt.getColumnsState(),
            normal = me.normalGrid.headerCt.getColumnsState();

        return locked.concat(normal);
    },

    
    reconfigureLockable: function(store, columns) {
        var me = this,
            lockedGrid = me.lockedGrid,
            normalGrid = me.normalGrid;

        if (columns) {
            Ext.suspendLayouts();
            lockedGrid.headerCt.removeAll();
            normalGrid.headerCt.removeAll();

            columns = me.processColumns(columns);
            lockedGrid.setWidth(columns.lockedWidth);
            lockedGrid.headerCt.add(columns.locked.items);
            normalGrid.headerCt.add(columns.normal.items);
            Ext.resumeLayouts(true);
        }

        if (store) {
            store = Ext.data.StoreManager.lookup(store);
            me.store = store;
            lockedGrid.bindStore(store);
            normalGrid.bindStore(store);
        } else {
            lockedGrid.getView().refresh();
            normalGrid.getView().refresh();
        }
    },

    
    cloneFeatures: function() {
        var me = this,
            features = me.features,
            feature,
            i = 0, len;
        
        if (features) {
            len = features.length;
            for (; i < len; i++) {
                feature = features[i];
                if (feature.isFeature) {
                    features[i] = feature.clone();
                }
            }
        }
    },

    
    clonePlugins: function() {
        var me = this,
            plugins = me.plugins,
            plugin,
            i = 0, len;
        
        if (plugins) {
            len = plugins.length;
            for (; i < len; i++) {
                plugin = plugins[i];
                if (typeof plugin.init === 'function') {
                    plugins[i] = plugin.clone();
                }
            }
        }
    }
}, function() {
    this.borrow(Ext.view.Table, ['constructFeatures']);
    this.borrow(Ext.AbstractComponent, ['constructPlugins', 'constructPlugin']);
});


Ext.define('Ext.grid.View', {
    extend: 'Ext.view.Table',
    alias: 'widget.gridview',

    
    stripeRows: true,

    autoScroll: true
});


Ext.define('Ext.grid.Panel', {
    extend: 'Ext.panel.Table',
    requires: ['Ext.grid.View'],
    alias: ['widget.gridpanel', 'widget.grid'],
    alternateClassName: ['Ext.list.ListView', 'Ext.ListView', 'Ext.grid.GridPanel'],
    viewType: 'gridview',

    lockable: false,

    
    
    bothCfgCopy: [
        'invalidateScrollerOnRefresh',
        'hideHeaders',
        'enableColumnHide',
        'enableColumnMove',
        'enableColumnResize',
        'sortableColumns'
    ],
    normalCfgCopy: [ 
        'verticalScroller', 
        'verticalScrollDock', 
        'verticalScrollerType', 
        'scroll'
    ],
    lockedCfgCopy: [],

    
    rowLines: true

    
    

    

    
});

Ext.define('Ext.grid.property.Grid', {

    extend: 'Ext.grid.Panel',

    alias: 'widget.propertygrid',

    alternateClassName: 'Ext.grid.PropertyGrid',

    uses: [
       'Ext.grid.plugin.CellEditing',
       'Ext.grid.property.Store',
       'Ext.grid.property.HeaderContainer',
       'Ext.XTemplate',
       'Ext.grid.CellEditor',
       'Ext.form.field.Date',
       'Ext.form.field.Text',
       'Ext.form.field.Number',
       'Ext.form.field.ComboBox'
    ],

   

    

    

    

    
    valueField: 'value',

    
    nameField: 'name',

    

    
    enableColumnMove: false,
    columnLines: true,
    stripeRows: false,
    trackMouseOver: false,
    clicksToEdit: 1,
    enableHdMenu: false,

    
    initComponent : function(){
        var me = this;

        me.addCls(Ext.baseCSSPrefix + 'property-grid');
        me.plugins = me.plugins || [];

        
        me.plugins.push(new Ext.grid.plugin.CellEditing({
            clicksToEdit: me.clicksToEdit,

            
            startEdit: function(record, column) {
                
                return this.self.prototype.startEdit.call(this, record, me.headerCt.child('#' + me.valueField));
            }
        }));

        me.selModel = {
            selType: 'cellmodel',
            onCellSelect: function(position) {
                if (position.column != 1) {
                    position.column = 1;
                }
                return this.self.prototype.onCellSelect.call(this, position);
            }
        };
        me.customRenderers = me.customRenderers || {};
        me.customEditors = me.customEditors || {};

        
        if (!me.store) {
            me.propStore = me.store = new Ext.grid.property.Store(me, me.source);
        }

        if (me.sortableColumns) {
            me.store.sort('name', 'ASC');
        }
        me.columns = new Ext.grid.property.HeaderContainer(me, me.store);

        me.addEvents(
            
            'beforepropertychange',
            
            'propertychange'
        );
        me.callParent();

        
        me.getView().walkCells = this.walkCells;

        
        me.editors = {
            'date'    : new Ext.grid.CellEditor({ field: new Ext.form.field.Date({selectOnFocus: true})}),
            'string'  : new Ext.grid.CellEditor({ field: new Ext.form.field.Text({selectOnFocus: true})}),
            'number'  : new Ext.grid.CellEditor({ field: new Ext.form.field.Number({selectOnFocus: true})}),
            'boolean' : new Ext.grid.CellEditor({ field: new Ext.form.field.ComboBox({
                editable: false,
                store: [[ true, me.headerCt.trueText ], [false, me.headerCt.falseText ]]
            })})
        };

        
        me.store.on('update', me.onUpdate, me);
    },

    
    onUpdate : function(store, record, operation) {
        var me = this,
            v, oldValue;

        if (me.rendered && operation == Ext.data.Model.EDIT) {
            v = record.get(me.valueField);
            oldValue = record.modified.value;
            if (me.fireEvent('beforepropertychange', me.source, record.getId(), v, oldValue) !== false) {
                if (me.source) {
                    me.source[record.getId()] = v;
                }
                record.commit();
                me.fireEvent('propertychange', me.source, record.getId(), v, oldValue);
            } else {
                record.reject();
            }
        }
    },

    
    walkCells: function(pos, direction, e, preventWrap, verifierFn, scope) {
        if (direction == 'left') {
            direction = 'up';
        } else if (direction == 'right') {
            direction = 'down';
        }
        pos = Ext.view.Table.prototype.walkCells.call(this, pos, direction, e, preventWrap, verifierFn, scope);
        if (!pos.column) {
            pos.column = 1;
        }
        return pos;
    },

    
    
    getCellEditor : function(record, column) {
        var me = this,
            propName = record.get(me.nameField),
            val = record.get(me.valueField),
            editor = me.customEditors[propName];

        
        
        if (editor) {
            if (!(editor instanceof Ext.grid.CellEditor)) {
                if (!(editor instanceof Ext.form.field.Base)) {
                    editor = Ext.ComponentManager.create(editor, 'textfield');
                }
                editor = me.customEditors[propName] = new Ext.grid.CellEditor({ field: editor });
            }
        } else if (Ext.isDate(val)) {
            editor = me.editors.date;
        } else if (Ext.isNumber(val)) {
            editor = me.editors.number;
        } else if (Ext.isBoolean(val)) {
            editor = me.editors['boolean'];
        } else {
            editor = me.editors.string;
        }

        
        editor.editorId = propName;
        return editor;
    },

    beforeDestroy: function() {
        var me = this;
        me.callParent();
        me.destroyEditors(me.editors);
        me.destroyEditors(me.customEditors);
        delete me.source;
    },

    destroyEditors: function (editors) {
        for (var ed in editors) {
            if (editors.hasOwnProperty(ed)) {
                Ext.destroy(editors[ed]);
            }
        }
    },

    
    setSource: function(source) {
        this.source = source;
        this.propStore.setSource(source);
    },

    
    getSource: function() {
        return this.propStore.getSource();
    },

    
    setProperty: function(prop, value, create) {
        this.propStore.setValue(prop, value, create);
    },

    
    removeProperty: function(prop) {
        this.propStore.remove(prop);
    }

    
    
});

Ext.define('Ext.tree.View', {
    extend: 'Ext.view.Table',
    alias: 'widget.treeview',

    requires: [
        'Ext.data.NodeStore'
    ],

    loadingCls: Ext.baseCSSPrefix + 'grid-tree-loading',
    expandedCls: Ext.baseCSSPrefix + 'grid-tree-node-expanded',
    leafCls: Ext.baseCSSPrefix + 'grid-tree-node-leaf',

    expanderSelector: '.' + Ext.baseCSSPrefix + 'tree-expander',
    checkboxSelector: '.' + Ext.baseCSSPrefix + 'tree-checkbox',
    expanderIconOverCls: Ext.baseCSSPrefix + 'tree-expander-over',

    
    
    
    nodeAnimWrapCls: Ext.baseCSSPrefix + 'tree-animator-wrap',

    blockRefresh: true,
    
    
    loadMask: false,

    
    rootVisible: true,

    
    deferInitialRefresh: false,

    

    expandDuration: 250,
    collapseDuration: 250,

    toggleOnDblClick: true,

    stripeRows: false,

    
    uiFields: ['expanded', 'loaded', 'checked', 'expandable', 'leaf', 'icon', 'iconCls', 'loading', 'qtip', 'qtitle'],

    initComponent: function() {
        var me = this,
            treeStore = me.panel.getStore();

        if (me.initialConfig.animate === undefined) {
            me.animate = Ext.enableFx;
        }

        me.store = new Ext.data.NodeStore({
            treeStore: treeStore,
            recursive: true,
            rootVisible: me.rootVisible,
            listeners: {
                beforeexpand: me.onBeforeExpand,
                expand: me.onExpand,
                beforecollapse: me.onBeforeCollapse,
                collapse: me.onCollapse,
                write: me.onStoreWrite,
                datachanged: me.onStoreDataChanged,
                scope: me
            }
        });

        if (me.node) {
            me.setRootNode(me.node);
        }
        me.animQueue = {};
        me.animWraps = {};
        me.addEvents(
            
            'afteritemexpand',
            
            'afteritemcollapse'
        );
        me.callParent(arguments);
        me.on({
            element: 'el',
            scope: me,
            delegate: me.expanderSelector,
            mouseover: me.onExpanderMouseOver,
            mouseout: me.onExpanderMouseOut
        });
        me.on({
            element: 'el',
            scope: me,
            delegate: me.checkboxSelector,
            click: me.onCheckboxChange
        });
    },
    
    getMaskStore: function(){
        return this.panel.getStore();    
    },

    afterComponentLayout: function(){
        this.callParent(arguments);
        var stretcher = this.stretcher;
        if (stretcher) {
            stretcher.setWidth((this.getWidth() - Ext.getScrollbarSize().width));
        }
    },

    processUIEvent: function(e) {
        
        
        
        if (e.getTarget('.' + this.nodeAnimWrapCls, this.el)) {
            return false;
        }
        return this.callParent(arguments);
    },

    onClear: function(){
        this.store.removeAll();    
    },

    setRootNode: function(node) {
        var me = this;        
        me.store.setNode(node);
        me.node = node;
    },

    onCheckboxChange: function(e, t) {
        var me = this,
            item = e.getTarget(me.getItemSelector(), me.getTargetEl());

        if (item) {
            me.onCheckChange(me.getRecord(item));
        }
    },

    onCheckChange: function(record){
        var checked = record.get('checked');
        if (Ext.isBoolean(checked)) {
            checked = !checked;
            record.set('checked', checked);
            this.fireEvent('checkchange', record, checked);
        }
    },

    getChecked: function() {
        var checked = [];
        this.node.cascadeBy(function(rec){
            if (rec.get('checked')) {
                checked.push(rec);
            }
        });
        return checked;
    },

    isItemChecked: function(rec){
        return rec.get('checked');
    },

    
    createAnimWrap: function(record, index) {
        var thHtml = '',
            headerCt = this.panel.headerCt,
            headers = headerCt.getGridColumns(),
            i = 0, len = headers.length, item,
            node = this.getNode(record),
            tmpEl, nodeEl;

        for (; i < len; i++) {
            item = headers[i];
            thHtml += '<th style="width: ' + (item.hidden ? 0 : item.getDesiredWidth()) + 'px; height: 0px;"></th>';
        }

        nodeEl = Ext.get(node);        
        tmpEl = nodeEl.insertSibling({
            tag: 'tr',
            html: [
                '<td colspan="' + headerCt.getColumnCount() + '">',
                    '<div class="' + this.nodeAnimWrapCls + '">',
                        '<table class="' + Ext.baseCSSPrefix + 'grid-table" style="width: ' + headerCt.getFullWidth() + 'px;"><tbody>',
                            thHtml,
                        '</tbody></table>',
                    '</div>',
                '</td>'
            ].join('')
        }, 'after');

        return {
            record: record,
            node: node,
            el: tmpEl,
            expanding: false,
            collapsing: false,
            animating: false,
            animateEl: tmpEl.down('div'),
            targetEl: tmpEl.down('tbody')
        };
    },

    
    getAnimWrap: function(parent, bubble) {
        if (!this.animate) {
            return null;
        }

        var wraps = this.animWraps,
            wrap = wraps[parent.internalId];

        if (bubble !== false) {
            while (!wrap && parent) {
                parent = parent.parentNode;
                if (parent) {
                    wrap = wraps[parent.internalId];
                }
            }
        }
        return wrap;
    },

    doAdd: function(nodes, records, index) {
        
        
        var me = this,
            record = records[0],
            parent = record.parentNode,
            a = me.all.elements,
            relativeIndex = 0,
            animWrap = me.getAnimWrap(parent),
            targetEl, children, len;

        if (!animWrap || !animWrap.expanding) {
            return me.callParent(arguments);
        }

        
        parent = animWrap.record;

        
        targetEl = animWrap.targetEl;
        children = targetEl.dom.childNodes;

        
        len = children.length - 1;

        
        relativeIndex = index - me.indexOf(parent) - 1;

        
        
        if (!len || relativeIndex >= len) {
            targetEl.appendChild(nodes);
        }
        
        
        else {
            
            Ext.fly(children[relativeIndex + 1]).insertSibling(nodes, 'before', true);
        }

        
        Ext.Array.insert(a, index, nodes);

        
        
        if (animWrap.isAnimating) {
            me.onExpand(parent);
        }
    },

    beginBulkUpdate: function(){
        this.bulkUpdate = true;  
    },

    endBulkUpdate: function(){
        this.bulkUpdate = false;
    },

    onRemove : function(ds, record, index) {
        var me = this,
            bulk = me.bulkUpdate;
            
        if (me.viewReady) {
            me.doRemove(record, index);
            if (!bulk) {
                me.updateIndexes(index);
            }
            if (me.store.getCount() === 0){
                me.refresh();
            }
            if (!bulk) {
                me.fireEvent('itemremove', record, index);
            }
        }
    },

    doRemove: function(record, index) {
        
        
        var me = this,
            all = me.all,
            animWrap = me.getAnimWrap(record),
            item = all.item(index),
            node = item ? item.dom : null;

        if (!node || !animWrap || !animWrap.collapsing) {
            return me.callParent(arguments);
        }

        animWrap.targetEl.appendChild(node);
        all.removeElement(index);
    },

    onBeforeExpand: function(parent, records, index) {
        var me = this,
            animWrap;

        if (!me.rendered || !me.animate) {
            return;
        }

        if (me.getNode(parent)) {
            animWrap = me.getAnimWrap(parent, false);
            if (!animWrap) {
                animWrap = me.animWraps[parent.internalId] = me.createAnimWrap(parent);
                animWrap.animateEl.setHeight(0);
            }
            else if (animWrap.collapsing) {
                
                
                animWrap.targetEl.select(me.itemSelector).remove();
            } 
            animWrap.expanding = true;
            animWrap.collapsing = false;
        }
    },

    onExpand: function(parent) {
        var me = this,
            queue = me.animQueue,
            id = parent.getId(),
            node = me.getNode(parent),
            index = node ? me.indexOf(node) : -1,
            animWrap,
            animateEl, 
            targetEl;        

        if (me.singleExpand) {
            me.ensureSingleExpand(parent);
        }

        
        if (index === -1) {
            return;
        }

        animWrap = me.getAnimWrap(parent, false);

        if (!animWrap) {
            me.isExpandingOrCollapsing = false;
            me.fireEvent('afteritemexpand', parent, index, node);
            return;
        }

        animateEl = animWrap.animateEl;
        targetEl = animWrap.targetEl;

        animateEl.stopAnimation();
        
        queue[id] = true;
        animateEl.slideIn('t', {
            duration: me.expandDuration,
            listeners: {
                scope: me,
                lastframe: function() {
                    
                    animWrap.el.insertSibling(targetEl.query(me.itemSelector), 'before');
                    animWrap.el.remove();
                    me.refreshSize();
                    delete me.animWraps[animWrap.record.internalId];
                    delete queue[id];
                }
            },
            callback: function() {
                me.isExpandingOrCollapsing = false;
                me.fireEvent('afteritemexpand', parent, index, node);
            }
        });

        animWrap.isAnimating = true;
    },

    onBeforeCollapse: function(parent, records, index) {
        var me = this,
            animWrap;

        if (!me.rendered || !me.animate) {
            return;
        }

        if (me.getNode(parent)) {
            animWrap = me.getAnimWrap(parent);
            if (!animWrap) {
                animWrap = me.animWraps[parent.internalId] = me.createAnimWrap(parent, index);
            }
            else if (animWrap.expanding) {
                
                
                animWrap.targetEl.select(this.itemSelector).remove();
            }
            animWrap.expanding = false;
            animWrap.collapsing = true;
        }
    },

    onCollapse: function(parent) {
        var me = this,
            queue = me.animQueue,
            id = parent.getId(),
            node = me.getNode(parent),
            index = node ? me.indexOf(node) : -1,
            animWrap = me.getAnimWrap(parent),
            animateEl, targetEl;

        
        if (index === -1) {
            return;
        }

        if (!animWrap) {
            me.isExpandingOrCollapsing = false;
            me.fireEvent('afteritemcollapse', parent, index, node);
            return;
        }

        animateEl = animWrap.animateEl;
        targetEl = animWrap.targetEl;

        queue[id] = true;

        
        animateEl.stopAnimation();
        animateEl.slideOut('t', {
            duration: me.collapseDuration,
            listeners: {
                scope: me,
                lastframe: function() {
                    animWrap.el.remove();
                    me.refreshSize();
                    delete me.animWraps[animWrap.record.internalId];
                    delete queue[id];
                }             
            },
            callback: function() {
                me.isExpandingOrCollapsing = false;
                me.fireEvent('afteritemcollapse', parent, index, node);
            }
        });
        animWrap.isAnimating = true;
    },

    
    isAnimating: function(node) {
        return !!this.animQueue[node.getId()];    
    },

    collectData: function(records) {
        var data = this.callParent(arguments),
            rows = data.rows,
            len = rows.length,
            i = 0,
            row, record;

        for (; i < len; i++) {
            row = rows[i];
            record = records[i];
            if (record.get('qtip')) {
                row.rowAttr = 'data-qtip="' + record.get('qtip') + '"';
                if (record.get('qtitle')) {
                    row.rowAttr += ' ' + 'data-qtitle="' + record.get('qtitle') + '"';
                }
            }
            if (record.isExpanded()) {
                row.rowCls = (row.rowCls || '') + ' ' + this.expandedCls;
            }
            if (record.isLeaf()) {
                row.rowCls = (row.rowCls || '') + ' ' + this.leafCls;
            }
            if (record.isLoading()) {
                row.rowCls = (row.rowCls || '') + ' ' + this.loadingCls;
            }
        }

        return data;
    },

    
    expand: function(record, deep, callback, scope) {
        return record.expand(deep, callback, scope);
    },

    
    collapse: function(record, deep, callback, scope) {
        return record.collapse(deep, callback, scope);
    },

    
    toggle: function(record, deep, callback, scope) {
        var me = this,
            doAnimate = !!this.animate;

        
        if (!doAnimate || !this.isExpandingOrCollapsing) {
            if (!record.isLeaf()) {
                this.isExpandingOrCollapsing = doAnimate;
            }
            if (record.isExpanded()) {
                me.collapse(record, deep, callback, scope);
            } else {
                me.expand(record, deep, callback, scope);
            }
        }
    },

    onItemDblClick: function(record, item, index) {
        var me = this,
            editingPlugin = me.editingPlugin;
            
        me.callParent(arguments);
        if (me.toggleOnDblClick && record.isExpandable() && !(editingPlugin && editingPlugin.clicksToEdit === 2)) {
            me.toggle(record);
        }
    },

    onBeforeItemMouseDown: function(record, item, index, e) {
        if (e.getTarget(this.expanderSelector, item)) {
            return false;
        }
        return this.callParent(arguments);
    },

    onItemClick: function(record, item, index, e) {
        if (e.getTarget(this.expanderSelector, item) && record.isExpandable()) {
            this.toggle(record, e.ctrlKey);
            return false;
        }
        return this.callParent(arguments);
    },

    onExpanderMouseOver: function(e, t) {
        e.getTarget(this.cellSelector, 10, true).addCls(this.expanderIconOverCls);
    },

    onExpanderMouseOut: function(e, t) {
        e.getTarget(this.cellSelector, 10, true).removeCls(this.expanderIconOverCls);
    },

    
    getTreeStore: function() {
        return this.panel.store;
    },    

    ensureSingleExpand: function(node) {
        var parent = node.parentNode;
        if (parent) {
            parent.eachChild(function(child) {
                if (child !== node && child.isExpanded()) {
                    child.collapse();
                }
            });
        }
    },

    shouldUpdateCell: function(column, changedFieldNames){
        if (changedFieldNames) {
            var i = 0,
                len = changedFieldNames.length;
                
            for (; i < len; ++i) {
                if (Ext.Array.contains(this.uiFields, changedFieldNames[i])) {
                    return true;
                }
            }
        }
        return this.callParent(arguments);
    },

    
    onStoreWrite: function(store, operation) {
        var treeStore = this.panel.store;
        treeStore.fireEvent('write', treeStore, operation);
    },

    
    onStoreDataChanged: function(store, operation) {
        var treeStore = this.panel.store;
        treeStore.fireEvent('datachanged', treeStore);
    }
});


Ext.define('Ext.tree.Panel', {
    extend: 'Ext.panel.Table',
    alias: 'widget.treepanel',
    alternateClassName: ['Ext.tree.TreePanel', 'Ext.TreePanel'],
    requires: ['Ext.tree.View', 'Ext.selection.TreeModel', 'Ext.tree.Column', 'Ext.data.TreeStore'],
    viewType: 'treeview',
    selType: 'treemodel',

    treeCls: Ext.baseCSSPrefix + 'tree-panel',

    deferRowRender: false,

    
    rowLines: false,

    
    lines: true,

    
    useArrows: false,

    
    singleExpand: false,

    ddConfig: {
        enableDrag: true,
        enableDrop: true
    },

    

    
    rootVisible: true,

    
    displayField: 'text',

    
    root: null,

    
    
    normalCfgCopy: ['displayField', 'root', 'singleExpand', 'useArrows', 'lines', 'rootVisible', 'scroll'],
    lockedCfgCopy: ['displayField', 'root', 'singleExpand', 'useArrows', 'lines', 'rootVisible'],
    
    isTree: true,

    

    
     
    

    constructor: function(config) {
        config = config || {};
        if (config.animate === undefined) {
            config.animate = Ext.isDefined(this.animate) ? this.animate : Ext.enableFx;
        }
        this.enableAnimations = config.animate;
        delete config.animate;

        this.callParent([config]);
    },

    initComponent: function() {
        var me = this,
            cls = [me.treeCls],
            view;

        if (me.useArrows) {
            cls.push(Ext.baseCSSPrefix + 'tree-arrows');
            me.lines = false;
        }

        if (me.lines) {
            cls.push(Ext.baseCSSPrefix + 'tree-lines');
        } else if (!me.useArrows) {
            cls.push(Ext.baseCSSPrefix + 'tree-no-lines');
        }

        if (Ext.isString(me.store)) {
            me.store = Ext.StoreMgr.lookup(me.store);
        } else if (!me.store || Ext.isObject(me.store) && !me.store.isStore) {
            me.store = new Ext.data.TreeStore(Ext.apply({}, me.store || {}, {
                root: me.root,
                fields: me.fields,
                model: me.model,
                folderSort: me.folderSort
            }));
        } else if (me.root) {
            me.store = Ext.data.StoreManager.lookup(me.store);
            me.store.setRootNode(me.root);
            if (me.folderSort !== undefined) {
                me.store.folderSort = me.folderSort;
                me.store.sort();
            }
        }

        
        
        
        

        me.viewConfig = Ext.apply({}, me.viewConfig);
        me.viewConfig = Ext.applyIf(me.viewConfig, {
            rootVisible: me.rootVisible,
            animate: me.enableAnimations,
            singleExpand: me.singleExpand,
            node: me.store.getRootNode(),
            hideHeaders: me.hideHeaders
        });

        me.mon(me.store, {
            scope: me,
            rootchange: me.onRootChange,
            clear: me.onClear
        });

        me.relayEvents(me.store, [
            
            'beforeload',

            
            'load'
        ]);

        me.mon(me.store, {
            
            append: me.createRelayer('itemappend'),

            
            remove: me.createRelayer('itemremove'),

            
            move: me.createRelayer('itemmove', [0, 4]),

            
            insert: me.createRelayer('iteminsert'),

            
            beforeappend: me.createRelayer('beforeitemappend'),

            
            beforeremove: me.createRelayer('beforeitemremove'),

            
            beforemove: me.createRelayer('beforeitemmove'),

            
            beforeinsert: me.createRelayer('beforeiteminsert'),

            
            expand: me.createRelayer('itemexpand', [0, 1]),

            
            collapse: me.createRelayer('itemcollapse', [0, 1]),

            
            beforeexpand: me.createRelayer('beforeitemexpand', [0, 1]),

            
            beforecollapse: me.createRelayer('beforeitemcollapse', [0, 1])
        });

        
        if (!me.columns) {
            if (me.initialConfig.hideHeaders === undefined) {
                me.hideHeaders = true;
            }
            me.addCls(Ext.baseCSSPrefix + 'autowidth-table');
            me.columns = [{
                xtype    : 'treecolumn',
                text     : 'Name',
                width    : Ext.isIE6 ? null : 10000,
                dataIndex: me.displayField         
            }];
        }

        if (me.cls) {
            cls.push(me.cls);
        }
        me.cls = cls.join(' ');
        me.callParent();
        
        view = me.getView();

        me.relayEvents(view, [
            
            'checkchange',
            
            'afteritemexpand',
            
            'afteritemcollapse'
        ]);

        
        if (!view.rootVisible && !me.getRootNode()) {
            me.setRootNode({
                expanded: true
            });
        }
    },
    
    onClear: function(){
        this.view.onClear();
    },

    
    setRootNode: function() {
        return this.store.setRootNode.apply(this.store, arguments);
    },

    
    getRootNode: function() {
        return this.store.getRootNode();
    },

    onRootChange: function(root) {
        this.view.setRootNode(root);
    },

    
    getChecked: function() {
        return this.getView().getChecked();
    },

    isItemChecked: function(rec) {
        return rec.get('checked');
    },
    
    
    expandNode: function(record, deep, callback, scope) {
        return this.getView().expand(record, deep, callback, scope || this);
    },

    
    collapseNode: function(record, deep, callback, scope) {
        return this.getView().collapse(record, deep, callback, scope || this);
    },

    
    expandAll : function(callback, scope) {
        var me = this,
            root = me.getRootNode(),
            animate = me.enableAnimations,
            view = me.getView();
        if (root) {
            if (!animate) {
                view.beginBulkUpdate();
            }
            root.expand(true, callback, scope || me);
            if (!animate) {
                view.endBulkUpdate();
            }
        }
    },

    
    collapseAll : function(callback, scope) {
        var me = this,
            root = me.getRootNode(),
            animate = me.enableAnimations,
            view = me.getView();

        if (root) {
            if (!animate) {
                view.beginBulkUpdate();
            }
            scope = scope || me;
            if (view.rootVisible) {
                root.collapse(true, callback, scope);
            } else {
                root.collapseChildren(true, callback, scope);
            }
            if (!animate) {
                view.endBulkUpdate();
            }
        }
    },

    
    expandPath: function(path, field, separator, callback, scope) {
        var me = this,
            current = me.getRootNode(),
            index = 1,
            view = me.getView(),
            keys,
            expander;

        field = field || me.getRootNode().idProperty;
        separator = separator || '/';

        if (Ext.isEmpty(path)) {
            Ext.callback(callback, scope || me, [false, null]);
            return;
        }

        keys = path.split(separator);
        if (current.get(field) != keys[1]) {
            
            Ext.callback(callback, scope || me, [false, current]);
            return;
        }

        expander = function(){
            if (++index === keys.length) {
                Ext.callback(callback, scope || me, [true, current]);
                return;
            }
            var node = current.findChild(field, keys[index]);
            if (!node) {
                Ext.callback(callback, scope || me, [false, current]);
                return;
            }
            current = node;
            current.expand(false, expander);
        };
        current.expand(false, expander);
    },

    
    selectPath: function(path, field, separator, callback, scope) {
        var me = this,
            root,
            keys,
            last;

        field = field || me.getRootNode().idProperty;
        separator = separator || '/';

        keys = path.split(separator);
        last = keys.pop();
        if (keys.length > 1) {
            me.expandPath(keys.join(separator), field, separator, function(success, node){
                var lastNode = node;
                if (success && node) {
                    node = node.findChild(field, last);
                    if (node) {
                        me.getSelectionModel().select(node);
                        Ext.callback(callback, scope || me, [true, node]);
                        return;
                    }
                }
                Ext.callback(callback, scope || me, [false, lastNode]);
            }, me);
        } else {
            root = me.getRootNode();
            if (root.getId() === last) {
                me.getSelectionModel().select(root);
                Ext.callback(callback, scope || me, [true, root]);
            } else {
                Ext.callback(callback, scope || me, [false, null]);
            }
        }
    }
});


Ext.define('Ext.window.Window', {
    extend: 'Ext.panel.Panel',

    alternateClassName: 'Ext.Window',

    requires: ['Ext.util.ComponentDragger', 'Ext.util.Region', 'Ext.EventManager'],

    alias: 'widget.window',

    

    

    

    

    

    

    

    

    
    baseCls: Ext.baseCSSPrefix + 'window',

    
    resizable: true,

    
    draggable: true,

    
    constrain: false,

    
    constrainHeader: false,

    

    
    plain: false,

    
    minimizable: false,

    
    maximizable: false,

    
    minHeight: 50,

    
    minWidth: 50,

    
    expandOnShow: true,

    
    collapsible: false,

    
    closable: true,

    
    hidden: true,

    
    autoRender: true,

    
    hideMode: 'offsets',

    
    floating: true,

    ariaRole: 'alertdialog',

    itemCls: Ext.baseCSSPrefix + 'window-item',
    
    initialAlphaNum: /^[a-z0-9]/,

    overlapHeader: true,

    ignoreHeaderBorderManagement: true,

    
    alwaysFramed: true,

    
    isWindow: true,

    
    initComponent: function() {
        var me = this;
        
        
        me.frame = false;
        me.callParent();
        me.addEvents(
            

            

            
            'resize',

            
            'maximize',

            
            'minimize',

            
            'restore'
        );

        if (me.plain) {
            me.addClsWithUI('plain');
        }

        if (me.modal) {
            me.ariaRole = 'dialog';
        }

        
        if (me.floating) {
            me.on({
                element: 'el',
                mousedown: me.onMouseDown,
                scope: me
            });
        }

        me.addStateEvents(['maximize', 'restore', 'resize', 'dragend']);
    },

    getElConfig: function () {
        var me = this,
            elConfig;

        elConfig = me.callParent();
        elConfig.tabIndex = -1;
        return elConfig;
    },

    
    

    getState: function() {
        var me = this,
            state = me.callParent() || {},
            maximized = !!me.maximized;

        state.maximized = maximized;
        Ext.apply(state, {
            size: maximized ? me.restoreSize : me.getSize(),
            pos: maximized ? me.restorePos : me.getPosition()
        });
        return state;
    },

    applyState: function(state){
        var me = this;

        if (state) {
            me.maximized = state.maximized;
            if (me.maximized) {
                me.hasSavedRestore = true;
                me.restoreSize = state.size;
                me.restorePos = state.pos;
            } else {
                Ext.apply(me, {
                    width: state.size.width,
                    height: state.size.height,
                    x: state.pos[0],
                    y: state.pos[1]
                });
            }
        }
    },

    
    onMouseDown: function (e) {
        var preventFocus;
            
        if (this.floating) {
            if (Ext.fly(e.getTarget()).focusable()) {
                preventFocus = true;
            }
            this.toFront(preventFocus);
        }
    },

    
    onRender: function(ct, position) {
        var me = this;
        me.callParent(arguments);
        me.focusEl = me.el;

        
        if (me.maximizable) {
            me.header.on({
                scope: me,
                dblclick: me.toggleMaximize
            });
        }
    },

    
    afterRender: function() {
        var me = this,
            keyMap;

        me.callParent();

        
        if (me.maximized) {
            me.maximized = false;
            me.maximize();
        }

        if (me.closable) {
            keyMap = me.getKeyMap();
            keyMap.on(27, me.onEsc, me);
        } else {
            keyMap = me.keyMap;
        }
        if (keyMap && me.hidden) {
            keyMap.disable();
        }
    },

    
    initDraggable: function() {
        var me = this,
            ddConfig;

        if (!me.header) {
            me.updateHeader(true);
        }

        
        if (me.header) {
            ddConfig = Ext.applyIf({
                el: me.el,
                delegate: '#' + Ext.escapeId(me.header.id)
            }, me.draggable);

            
            if (me.constrain || me.constrainHeader) {
                ddConfig.constrain = me.constrain;
                ddConfig.constrainDelegate = me.constrainHeader;
                ddConfig.constrainTo = me.constrainTo || me.container;
            }

            
            me.dd = new Ext.util.ComponentDragger(this, ddConfig);
            me.relayEvents(me.dd, ['dragstart', 'drag', 'dragend']);
        }
    },

    
    onEsc: function(k, e) {
        
        if (!Ext.FocusManager || !Ext.FocusManager.enabled || Ext.FocusManager.focusedCmp === this) {
            e.stopEvent();
            this.close();
        }
    },

    
    beforeDestroy: function() {
        var me = this;
        if (me.rendered) {
            delete this.animateTarget;
            me.hide();
            Ext.destroy(
                me.keyMap
            );
        }
        me.callParent();
    },

    
    addTools: function() {
        var me = this;

        
        me.callParent();

        if (me.minimizable) {
            me.addTool({
                type: 'minimize',
                handler: Ext.Function.bind(me.minimize, me, [])
            });
        }
        if (me.maximizable) {
            me.addTool({
                type: 'maximize',
                handler: Ext.Function.bind(me.maximize, me, [])
            });
            me.addTool({
                type: 'restore',
                handler: Ext.Function.bind(me.restore, me, []),
                hidden: true
            });
        }
    },

    
    getFocusEl: function() {
        return this.getDefaultFocus();
    },

    
    getDefaultFocus: function() {
        var me = this,
            result,
            defaultComp = me.defaultButton || me.defaultFocus,
            selector;

        if (defaultComp !== undefined) {
            
            if (Ext.isNumber(defaultComp)) {
                result = me.query('button')[defaultComp];
            }
            
            else if (Ext.isString(defaultComp)) {
                selector = defaultComp;
                
                
                if (selector.match(me.initialAlphaNum)) {
                    result = me.down('#' + selector);
                }
                
                if (!result) {
                    result = me.down(selector);
                }
            }
            
            else if (defaultComp.focus) {
                result = defaultComp;
            }
        }
        return result || me.el;
    },

    
    onFocus: function() {
        var me = this,
            focusDescendant;

        
        if ((Ext.FocusManager && Ext.FocusManager.enabled) || ((focusDescendant = me.getDefaultFocus()) === me)) {
            me.callParent(arguments);
        } else {
            focusDescendant.focus();
        }
    },

    beforeLayout: function () {
        var shadow = this.el.shadow;

        this.callParent();
        if (shadow) {
            shadow.hide();
        }
    },

    onShow: function() {
        var me = this;

        me.callParent(arguments);
        if (me.expandOnShow) {
            me.expand(false);
        }
        me.syncMonitorWindowResize();

        if (me.keyMap) {
            me.keyMap.enable();
        }
   },

    
    doClose: function() {
        var me = this;

        
        if (me.hidden) {
            me.fireEvent('close', me);
            if (me.closeAction == 'destroy') {
                this.destroy();
            }
        } else {
            
            me.hide(me.animateTarget, me.doClose, me);
        }
    },

    
    afterHide: function() {
        var me = this;

        
        me.syncMonitorWindowResize();

        
        if (me.keyMap) {
            me.keyMap.disable();
        }

        
        me.callParent(arguments);
    },

    
    onWindowResize: function() {
        var me = this,
            sizeModel;

        if (me.maximized) {
            me.fitContainer();
        } else {
            sizeModel = me.getSizeModel();
            if (sizeModel.width.natural || sizeModel.height.natural) {
                me.updateLayout();
            }
        }

        me.doConstrain();
    },

    
    minimize: function() {
        this.fireEvent('minimize', this);
        return this;
    },

    afterCollapse: function() {
        var me = this;

        if (me.maximizable) {
            me.tools.maximize.hide();
            me.tools.restore.hide();
        }
        if (me.resizer) {
            me.resizer.disable();
        }
        me.callParent(arguments);
    },

    afterExpand: function() {
        var me = this;

        if (me.maximized) {
            me.tools.restore.show();
        } else if (me.maximizable) {
            me.tools.maximize.show();
        }
        if (me.resizer) {
            me.resizer.enable();
        }
        me.callParent(arguments);
    },

    
    maximize: function() {
        var me = this;

        if (!me.maximized) {
            me.expand(false);
            if (!me.hasSavedRestore) {
                me.restoreSize = me.getSize();
                me.restorePos = me.getPosition(true);
            }
            if (me.maximizable) {
                me.tools.maximize.hide();
                me.tools.restore.show();
            }
            me.maximized = true;
            me.el.disableShadow();

            if (me.dd) {
                me.dd.disable();
            }
            if (me.resizer) {
                me.resizer.disable();
            }
            if (me.collapseTool) {
                me.collapseTool.hide();
            }
            me.el.addCls(Ext.baseCSSPrefix + 'window-maximized');
            me.container.addCls(Ext.baseCSSPrefix + 'window-maximized-ct');

            me.syncMonitorWindowResize();
            me.fitContainer();
            me.fireEvent('maximize', me);
        }
        return me;
    },

    
    restore: function() {
        var me = this,
            tools = me.tools;

        if (me.maximized) {
            delete me.hasSavedRestore;
            me.removeCls(Ext.baseCSSPrefix + 'window-maximized');

            
            if (tools.restore) {
                tools.restore.hide();
            }
            if (tools.maximize) {
                tools.maximize.show();
            }
            if (me.collapseTool) {
                me.collapseTool.show();
            }

            me.maximized = false;

            
            me.setPosition(me.restorePos);
            me.setSize(me.restoreSize);

            
            delete me.restorePos;
            delete me.restoreSize;

            me.el.enableShadow(true);

            
            if (me.dd) {
                me.dd.enable();
            }
            
            if (me.resizer) {
                me.resizer.enable();
            }

            me.container.removeCls(Ext.baseCSSPrefix + 'window-maximized-ct');

            me.syncMonitorWindowResize();
            me.doConstrain();
            me.fireEvent('restore', me);
        }
        return me;
    },

    
    syncMonitorWindowResize: function () {
        var me = this,
            currentlyMonitoring = me._monitoringResize,
            
            yes = me.monitorResize || me.constrain || me.constrainHeader || me.maximized,
            
            veto = me.hidden || me.destroying || me.isDestroyed;

        if (yes && !veto) {
            
            if (!currentlyMonitoring) {
                
                Ext.EventManager.onWindowResize(me.onWindowResize, me);
                me._monitoringResize = true;
            }
        } else if (currentlyMonitoring) {
            
            Ext.EventManager.removeResizeListener(me.onWindowResize, me);
            me._monitoringResize = false;
        }
    },

    
    toggleMaximize: function() {
        return this[this.maximized ? 'restore': 'maximize']();
    }

});


Ext.define('Ext.window.MessageBox', {
    extend: 'Ext.window.Window',

    requires: [
        'Ext.toolbar.Toolbar',
        'Ext.form.field.Text',
        'Ext.form.field.TextArea',
        'Ext.form.field.Display',
        'Ext.button.Button',
        'Ext.layout.container.Anchor',
        'Ext.layout.container.HBox',
        'Ext.ProgressBar'
    ],

    alias: 'widget.messagebox',

    
    OK : 1,
    
    YES : 2,
    
    NO : 4,
    
    CANCEL : 8,
    
    OKCANCEL : 9,
    
    YESNO : 6,
    
    YESNOCANCEL : 14,
    
    INFO : Ext.baseCSSPrefix + 'message-box-info',
    
    WARNING : Ext.baseCSSPrefix + 'message-box-warning',
    
    QUESTION : Ext.baseCSSPrefix + 'message-box-question',
    
    ERROR : Ext.baseCSSPrefix + 'message-box-error',

    
    hideMode: 'offsets',
    closeAction: 'hide',
    resizable: false,
    title: '&#160;',

    width: 600,
    height: 500,
    minWidth: 250,
    maxWidth: 600,
    minHeight: 110,
    maxHeight: 500,
    constrain: true,

    cls: Ext.baseCSSPrefix + 'message-box',

    layout: {
        type: 'vbox',
        align: 'stretch'
    },

    
    defaultTextHeight : 75,
    
    minProgressWidth : 250,
    
    minPromptWidth: 250,
    
    
    buttonText: {
        ok: 'OK',
        yes: 'Yes',
        no: 'No',
        cancel: 'Cancel'
    },
    

    buttonIds: [
        'ok', 'yes', 'no', 'cancel'
    ],

    
    titleText: {
        confirm: 'Confirm',
        prompt: 'Prompt',
        wait: 'Loading...',
        alert: 'Attention'
    },
    

    iconHeight: 35,

    makeButton: function(btnIdx) {
        var btnId = this.buttonIds[btnIdx];
        return new Ext.button.Button({
            handler: this.btnCallback,
            itemId: btnId,
            scope: this,
            text: this.buttonText[btnId],
            minWidth: 75
        });
    },

    btnCallback: function(btn) {
        var me = this,
            value,
            field;

        if (me.cfg.prompt || me.cfg.multiline) {
            if (me.cfg.multiline) {
                field = me.textArea;
            } else {
                field = me.textField;
            }
            value = field.getValue();
            field.reset();
        }

        
        btn.blur();
        me.hide();
        me.userCallback(btn.itemId, value, me.cfg);
    },

    hide: function() {
        var me = this;
        me.dd.endDrag();
        me.progressBar.reset();
        me.removeCls(me.cfg.cls);
        me.callParent(arguments);
    },

    initComponent: function() {
        var me = this,
            baseId = me.id,
            i, button,
            tbLayout;

        me.title = '&#160;';

        me.topContainer = new Ext.container.Container({
            layout: 'hbox',
            style: {
                padding: '10px',
                overflow: 'hidden'
            },
            items: [
                me.iconComponent = new Ext.Component({
                    cls: me.baseCls + '-icon',
                    width: 50,
                    height: me.iconHeight
                }),
                me.promptContainer = new Ext.container.Container({
                    flex: 1,
                    layout: {
                        type: 'anchor'
                    },
                    items: [
                        me.msg = new Ext.form.field.Display({
                            id: baseId + '-displayfield',
                            cls: me.baseCls + '-text'
                        }),
                        me.textField = new Ext.form.field.Text({
                            id: baseId + '-testfield',
                            anchor: '100%',
                            enableKeyEvents: true,
                            listeners: {
                                keydown: me.onPromptKey,
                                scope: me
                            }
                        }),
                        me.textArea = new Ext.form.field.TextArea({
                            id: baseId + '-textarea',
                            anchor: '100%',
                            height: 75
                        })
                    ]
                })
            ]
        });
        me.progressBar = new Ext.ProgressBar({
            id: baseId + '-progressbar',
            margins: '0 10 0 10'
        });

        me.items = [me.topContainer, me.progressBar];

        
        me.msgButtons = [];
        for (i = 0; i < 4; i++) {
            button = me.makeButton(i);
            me.msgButtons[button.itemId] = button;
            me.msgButtons.push(button);
        }
        me.bottomTb = new Ext.toolbar.Toolbar({
            id: baseId + '-toolbar',
            ui: 'footer',
            dock: 'bottom',
            layout: {
                pack: 'center'
            },
            items: [
                me.msgButtons[0],
                me.msgButtons[1],
                me.msgButtons[2],
                me.msgButtons[3]
            ]
        });
        me.dockedItems = [me.bottomTb];

        
        tbLayout = me.bottomTb.getLayout();
        tbLayout.finishedLayout = Ext.Function.createInterceptor(tbLayout.finishedLayout, function(ownerContext) {
            me.tbWidth = ownerContext.getProp('contentWidth');
        });
        me.on('close', me.onClose, me);

        me.callParent();
    },
    
    onClose: function(){
        var btn = this.header.child('[type=close]');
        
        btn.itemId = 'cancel';
        this.btnCallback(btn);
        delete btn.itemId;
    },

    onPromptKey: function(textField, e) {
        var me = this,
            blur;

        if (e.keyCode === Ext.EventObject.RETURN || e.keyCode === 10) {
            if (me.msgButtons.ok.isVisible()) {
                blur = true;
                me.msgButtons.ok.handler.call(me, me.msgButtons.ok);
            } else if (me.msgButtons.yes.isVisible()) {
                me.msgButtons.yes.handler.call(me, me.msgButtons.yes);
                blur = true;
            }

            if (blur) {
                me.textField.blur();
            }
        }
    },

    reconfigure: function(cfg) {
        var me = this,
            buttons = 0,
            hideToolbar = true,
            initialWidth = me.maxWidth,
            oldButtonText = me.buttonText,
            i;

        
        me.updateButtonText();

        cfg = cfg || {};
        me.cfg = cfg;
        if (cfg.width) {
            initialWidth = cfg.width;
        }

        
        delete me.defaultFocus;

        
        me.animateTarget = cfg.animateTarget || undefined;

        
        me.modal = cfg.modal !== false;

        
        if (cfg.title) {
            me.setTitle(cfg.title||'&#160;');
        }

        
        if (Ext.isObject(cfg.buttons)) {
            me.buttonText = cfg.buttons;
            buttons = 0;
        } else {
            me.buttonText = cfg.buttonText || me.buttonText;
            buttons = Ext.isNumber(cfg.buttons) ? cfg.buttons : 0;
        }

        
        
        buttons = buttons | me.updateButtonText();

        
        me.buttonText = oldButtonText;

        
        
        Ext.suspendLayouts();
        me.hidden = false;
        if (!me.rendered) {
            me.width = initialWidth;
            me.render(Ext.getBody());
        } else {
            me.setSize(initialWidth, me.maxHeight);
        }

        
        me.closable = cfg.closable && !cfg.wait;
        me.header.child('[type=close]').setVisible(cfg.closable !== false);

        
        if (!cfg.title && !me.closable) {
            me.header.hide();
        } else {
            me.header.show();
        }

        
        me.liveDrag = !cfg.proxyDrag;

        
        me.userCallback = Ext.Function.bind(cfg.callback ||cfg.fn || Ext.emptyFn, cfg.scope || Ext.global);

        
        me.setIcon(cfg.icon);

        
        if (cfg.msg) {
            me.msg.setValue(cfg.msg);
            me.msg.show();
        } else {
            me.msg.hide();
        }

        
        
        Ext.resumeLayouts(true);
        Ext.suspendLayouts();

        
        if (cfg.prompt || cfg.multiline) {
            me.multiline = cfg.multiline;
            if (cfg.multiline) {
                me.textArea.setValue(cfg.value);
                me.textArea.setHeight(cfg.defaultTextHeight || me.defaultTextHeight);
                me.textArea.show();
                me.textField.hide();
                me.defaultFocus = me.textArea;
            } else {
                me.textField.setValue(cfg.value);
                me.textArea.hide();
                me.textField.show();
                me.defaultFocus = me.textField;
            }
        } else {
            me.textArea.hide();
            me.textField.hide();
        }

        
        if (cfg.progress || cfg.wait) {
            me.progressBar.show();
            me.updateProgress(0, cfg.progressText);
            if(cfg.wait === true){
                me.progressBar.wait(cfg.waitConfig);
            }
        } else {
            me.progressBar.hide();
        }

        
        for (i = 0; i < 4; i++) {
            if (buttons & Math.pow(2, i)) {

                
                if (!me.defaultFocus) {
                    me.defaultFocus = me.msgButtons[i];
                }
                me.msgButtons[i].show();
                hideToolbar = false;
            } else {
                me.msgButtons[i].hide();
            }
        }

        
        if (hideToolbar) {
            me.bottomTb.hide();
        } else {
            me.bottomTb.show();
        }
        Ext.resumeLayouts(true);
    },

    
    updateButtonText: function() {
        var me = this,
            buttonText = me.buttonText,
            buttons = 0,
            btnId,
            btn;

        for (btnId in buttonText) {
            if (buttonText.hasOwnProperty(btnId)) {
                btn = me.msgButtons[btnId];
                if (btn) {
                    if (me.cfg && me.cfg.buttonText) {
                        buttons = buttons | Math.pow(2, Ext.Array.indexOf(me.buttonIds, btnId));
                    }
                    if (btn.text != buttonText[btnId]) {
                        btn.setText(buttonText[btnId]);
                    }
                }
            }
        }
        return buttons;
    },

    
    show: function(cfg) {
        var me = this;

        me.reconfigure(cfg);
        me.addCls(cfg.cls);
        me.doAutoSize();

        
        
        me.hidden = true;
        me.callParent();
        return me;
    },

    onShow: function() {
        this.callParent(arguments);
        this.center();
    },

    doAutoSize: function() {
        var me = this,
            headerVisible = me.header.rendered && me.header.isVisible(),
            footerVisible = me.bottomTb.rendered && me.bottomTb.isVisible(),
            width,
            height;

        if (!Ext.isDefined(me.frameWidth)) {
            me.frameWidth = me.el.getWidth() - me.body.getWidth();
        }

        
        me.minWidth = me.cfg.minWidth || Ext.getClass(this).prototype.minWidth;

        
        width = Math.max(
            headerVisible ? me.header.getMinWidth() : 0,                            
            me.cfg.width || me.msg.getWidth() + me.iconComponent.getWidth() + 25,   
            (footerVisible ? me.tbWidth : 0)
        );

        height = (headerVisible ? me.header.getHeight() : 0) +
            me.topContainer.getHeight() +
            me.progressBar.getHeight() +
            (footerVisible ? me.bottomTb.getHeight() + me.bottomTb.el.getMargin('tb') : 0);

        me.setSize(width + me.frameWidth, height + me.frameWidth);
        return me;
    },

    updateText: function(text) {
        this.msg.setValue(text);
        return this.doAutoSize(true);
    },

    
    setIcon : function(icon) {
        var me = this;
        me.iconComponent.removeCls(me.messageIconCls);
        if (icon) {
            me.iconComponent.show();
            me.iconComponent.addCls(Ext.baseCSSPrefix + 'dlg-icon');
            me.iconComponent.addCls(me.messageIconCls = icon);
        } else {
            me.iconComponent.removeCls(Ext.baseCSSPrefix + 'dlg-icon');
            me.iconComponent.hide();
        }
        return me;
    },

    
    updateProgress : function(value, progressText, msg){
        this.progressBar.updateProgress(value, progressText);
        if (msg){
            this.updateText(msg);
        }
        return this;
    },

    onEsc: function() {
        if (this.closable !== false) {
            this.callParent(arguments);
        }
    },

    
    confirm: function(cfg, msg, fn, scope) {
        if (Ext.isString(cfg)) {
            cfg = {
                title: cfg,
                icon: this.QUESTION,
                msg: msg,
                buttons: this.YESNO,
                callback: fn,
                scope: scope
            };
        }
        return this.show(cfg);
    },

    
    prompt : function(cfg, msg, fn, scope, multiline, value){
        if (Ext.isString(cfg)) {
            cfg = {
                prompt: true,
                title: cfg,
                minWidth: this.minPromptWidth,
                msg: msg,
                buttons: this.OKCANCEL,
                callback: fn,
                scope: scope,
                multiline: multiline,
                value: value
            };
        }
        return this.show(cfg);
    },

    
    wait : function(cfg, title, config){
        if (Ext.isString(cfg)) {
            cfg = {
                title : title,
                msg : cfg,
                closable: false,
                wait: true,
                modal: true,
                minWidth: this.minProgressWidth,
                waitConfig: config
            };
        }
        return this.show(cfg);
    },

    
    alert: function(cfg, msg, fn, scope) {
        if (Ext.isString(cfg)) {
            cfg = {
                title : cfg,
                msg : msg,
                buttons: this.OK,
                fn: fn,
                scope : scope,
                minWidth: this.minWidth
            };
        }
        return this.show(cfg);
    },

    
    progress : function(cfg, msg, progressText){
        if (Ext.isString(cfg)) {
            cfg = {
                title: cfg,
                msg: msg,
                progress: true,
                progressText: progressText
            };
        }
        return this.show(cfg);
    }
}, function() {
    
    Ext.MessageBox = Ext.Msg = new this();
});

Ext.define('Ext.form.Basic', {
    extend: 'Ext.util.Observable',
    alternateClassName: 'Ext.form.BasicForm',
    requires: ['Ext.util.MixedCollection', 'Ext.form.action.Load', 'Ext.form.action.Submit',
               'Ext.window.MessageBox', 'Ext.data.Errors', 'Ext.util.DelayedTask'],

    
    constructor: function(owner, config) {
        var me = this,
            onItemAddOrRemove = me.onItemAddOrRemove,
            api,
            fn;

        
        me.owner = owner;

        
        me.mon(owner, {
            add: onItemAddOrRemove,
            remove: onItemAddOrRemove,
            scope: me
        });

        Ext.apply(me, config);

        
        if (Ext.isString(me.paramOrder)) {
            me.paramOrder = me.paramOrder.split(/[\s,|]/);
        }
        
        if (me.api) {
            api = me.api = Ext.apply({}, me.api);
            for (fn in api) {
                if (api.hasOwnProperty(fn)) {
                    api[fn] = Ext.direct.Manager.parseMethod(api[fn]);
                }
            }
        }

        me.checkValidityTask = new Ext.util.DelayedTask(me.checkValidity, me);

        me.addEvents(
            
            'beforeaction',
            
            'actionfailed',
            
            'actioncomplete',
            
            'validitychange',
            
            'dirtychange'
        );
        me.callParent();
    },

    
    initialize : function() {
        var me = this;
        me.initialized = true;
        me.onValidityChange(!me.hasInvalidField());
    },


    

    

    

    

    

    
    timeout: 30,

    

    

    
    paramsAsHash: false,

    
    
    waitTitle: 'Please Wait...',
    

    
    trackResetOnLoad: false,

    

    


    
    wasDirty: false,


    
    destroy: function() {
        this.clearListeners();
        this.checkValidityTask.cancel();
    },

    
    onItemAddOrRemove: function(parent, child) {
        var me = this,
            isAdding = !!child.ownerCt,
            isContainer = child.isContainer;

        function handleField(field) {
            
            me[isAdding ? 'mon' : 'mun'](field, {
                validitychange: me.checkValidity,
                dirtychange: me.checkDirty,
                scope: me,
                buffer: 100 
            });
            
            delete me._fields;
        }

        if (child.isFormField) {
            handleField(child);
        } else if (isContainer) {
            
            if (child.isDestroyed || child.destroying) {
                
                
                delete me._fields;
            } else {
                Ext.Array.forEach(child.query('[isFormField]'), handleField);
            }
        }

        
        delete this._boundItems;

        
        
        if (me.initialized) {
            me.checkValidityTask.delay(10);
        }
    },

    
    getFields: function() {
        var fields = this._fields;
        if (!fields) {
            fields = this._fields = new Ext.util.MixedCollection();
            fields.addAll(this.owner.query('[isFormField]'));
        }
        return fields;
    },

    
    getBoundItems: function() {
        var boundItems = this._boundItems;
        
        if (!boundItems || boundItems.getCount() === 0) {
            boundItems = this._boundItems = new Ext.util.MixedCollection();
            boundItems.addAll(this.owner.query('[formBind]'));
        }
        
        return boundItems;
    },

    
    hasInvalidField: function() {
        return !!this.getFields().findBy(function(field) {
            var preventMark = field.preventMark,
                isValid;
            field.preventMark = true;
            isValid = field.isValid();
            field.preventMark = preventMark;
            return !isValid;
        });
    },

    
    isValid: function() {
        var me = this,
            invalid;
        Ext.suspendLayouts();
        invalid = me.getFields().filterBy(function(field) {
            return !field.validate();
        });
        Ext.resumeLayouts(true);
        return invalid.length < 1;
    },

    
    checkValidity: function() {
        var me = this,
            valid = !me.hasInvalidField();
        if (valid !== me.wasValid) {
            me.onValidityChange(valid);
            me.fireEvent('validitychange', me, valid);
            me.wasValid = valid;
        }
    },

    
    onValidityChange: function(valid) {
        var boundItems = this.getBoundItems(),
            items, i, iLen, cmp;

        if (boundItems) {
            items = boundItems.items;
            iLen  = items.length;

            for (i = 0; i < iLen; i++) {
                cmp = items[i];

                if (cmp.disabled === valid) {
                    cmp.setDisabled(!valid);
                }
            }
        }
    },

    
    isDirty: function() {
        return !!this.getFields().findBy(function(f) {
            return f.isDirty();
        });
    },

    
    checkDirty: function() {
        var dirty = this.isDirty();
        if (dirty !== this.wasDirty) {
            this.fireEvent('dirtychange', this, dirty);
            this.wasDirty = dirty;
        }
    },

    
    hasUpload: function() {
        return !!this.getFields().findBy(function(f) {
            return f.isFileUpload();
        });
    },

    
    doAction: function(action, options) {
        if (Ext.isString(action)) {
            action = Ext.ClassManager.instantiateByAlias('formaction.' + action, Ext.apply({}, options, {form: this}));
        }
        if (this.fireEvent('beforeaction', this, action) !== false) {
            this.beforeAction(action);
            Ext.defer(action.run, 100, action);
        }
        return this;
    },

    
    submit: function(options) {
        options = options || {};
        var me = this,
            action;
            
        if (options.standardSubmit || me.standardSubmit) {
            action = 'standardsubmit';
        } else {
            action = me.api ? 'directsubmit' : 'submit';
        }
            
        return me.doAction(action, options);
    },

    
    load: function(options) {
        return this.doAction(this.api ? 'directload' : 'load', options);
    },

    
    updateRecord: function(record) {
        record = record || this._record;
        var fields = record.fields.items,
            values = this.getFieldValues(),
            obj = {},
            i = 0,
            len = fields.length,
            name;

        for (; i < len; ++i) {
            name  = fields[i].name;

            if (values.hasOwnProperty(name)) {
                obj[name] = values[name];
            }
        }

        record.beginEdit();
        record.set(obj);
        record.endEdit();

        return this;
    },

    
    loadRecord: function(record) {
        this._record = record;
        return this.setValues(record.data);
    },

    
    getRecord: function() {
        return this._record;
    },

    
    beforeAction: function(action) {
        var waitMsg = action.waitMsg,
            maskCls = Ext.baseCSSPrefix + 'mask-loading',
            fields  = this.getFields().items,
            f,
            fLen    = fields.length,
            field, waitMsgTarget;

        
        for (f = 0; f < fLen; f++) {
            field = fields[f];

            if (field.isFormField && field.syncValue) {
                field.syncValue();
            }
        }

        if (waitMsg) {
            waitMsgTarget = this.waitMsgTarget;
            if (waitMsgTarget === true) {
                this.owner.el.mask(waitMsg, maskCls);
            } else if (waitMsgTarget) {
                waitMsgTarget = this.waitMsgTarget = Ext.get(waitMsgTarget);
                waitMsgTarget.mask(waitMsg, maskCls);
            } else {
                Ext.MessageBox.wait(waitMsg, action.waitTitle || this.waitTitle);
            }
        }
    },

    
    afterAction: function(action, success) {
        if (action.waitMsg) {
            var messageBox = Ext.MessageBox,
                waitMsgTarget = this.waitMsgTarget;
            if (waitMsgTarget === true) {
                this.owner.el.unmask();
            } else if (waitMsgTarget) {
                waitMsgTarget.unmask();
            } else {
                
                
                messageBox.suspendEvents();
                messageBox.hide();
                messageBox.resumeEvents();
            }
        }
        if (success) {
            if (action.reset) {
                this.reset();
            }
            Ext.callback(action.success, action.scope || action, [this, action]);
            this.fireEvent('actioncomplete', this, action);
        } else {
            Ext.callback(action.failure, action.scope || action, [this, action]);
            this.fireEvent('actionfailed', this, action);
        }
    },


    
    findField: function(id) {
        return this.getFields().findBy(function(f) {
            return f.id === id || f.getName() === id;
        });
    },


    
    markInvalid: function(errors) {
        var me = this,
            e, eLen, error, value,
            key;

        function mark(fieldId, msg) {
            var field = me.findField(fieldId);
            if (field) {
                field.markInvalid(msg);
            }
        }

        if (Ext.isArray(errors)) {
            eLen = errors.length;

            for (e = 0; e < eLen; e++) {
                error = errors[e];
                mark(error.id, error.msg);
            }
        } else if (errors instanceof Ext.data.Errors) {
            eLen  = errors.items.length;
            for (e = 0; e < eLen; e++) {
                error = errors.items[e];

                mark(error.field, error.message);
            }
        } else {
            for (key in errors) {
                if (errors.hasOwnProperty(key)) {
                    value = errors[key];
                    mark(key, value, errors);
                }
            }
        }
        return this;
    },

    
    setValues: function(values) {
        var me = this,
            v, vLen, val, field;

        function setVal(fieldId, val) {
            var field = me.findField(fieldId);
            if (field) {
                field.setValue(val);
                if (me.trackResetOnLoad) {
                    field.resetOriginalValue();
                }
            }
        }

        if (Ext.isArray(values)) {
            
            vLen = values.length;

            for (v = 0; v < vLen; v++) {
                val = values[v];

                setVal(val.id, val.value);
            }
        } else {
            
            Ext.iterate(values, setVal);
        }
        return this;
    },

    
    getValues: function(asString, dirtyOnly, includeEmptyText, useDataValues) {
        var values  = {},
            fields  = this.getFields().items,
            f,
            fLen    = fields.length,
            isArray = Ext.isArray,
            field, data, val, bucket, name;

        for (f = 0; f < fLen; f++) {
            field = fields[f];

            if (!dirtyOnly || field.isDirty()) {
                data = field[useDataValues ? 'getModelData' : 'getSubmitData'](includeEmptyText);

                if (Ext.isObject(data)) {
                    for (name in data) {
                        if (data.hasOwnProperty(name)) {
                            val = data[name];

                            if (includeEmptyText && val === '') {
                                val = field.emptyText || '';
                            }

                            if (values.hasOwnProperty(name)) {
                                bucket = values[name];

                                if (!isArray(bucket)) {
                                    bucket = values[name] = [bucket];
                                }

                                if (isArray(val)) {
                                    values[name] = values[name] = bucket.concat(val);
                                } else {
                                    bucket.push(val);
                                }
                            } else {
                                values[name] = val;
                            }
                        }
                    }
                }
            }
        }

        if (asString) {
            values = Ext.Object.toQueryString(values);
        }
        return values;
    },

    
    getFieldValues: function(dirtyOnly) {
        return this.getValues(false, dirtyOnly, false, true);
    },

    
    clearInvalid: function() {
        Ext.suspendLayouts();

        var me     = this,
            fields = me.getFields().items,
            f,
            fLen   = fields.length;

        for (f = 0; f < fLen; f++) {
            fields[f].clearInvalid();
        }

        Ext.resumeLayouts(true);
        return me;
    },

    
    reset: function() {
        Ext.suspendLayouts();

        var me     = this,
            fields = me.getFields().items,
            f,
            fLen   = fields.length;

        for (f = 0; f < fLen; f++) {
            fields[f].reset();
        }

        Ext.resumeLayouts(true);
        return me;
    },

    
    applyToFields: function(obj) {
        var fields = this.getFields().items,
            f,
            fLen   = fields.length;

        for (f = 0; f < fLen; f++) {
            Ext.apply(fields[f], obj);
        }

        return this;
    },

    
    applyIfToFields: function(obj) {
        var fields = this.getFields().items,
            f,
            fLen   = fields.length;

        for (f = 0; f < fLen; f++) {
            Ext.applyIf(fields[f], obj);
        }

        return this;
    }
});


Ext.define('Ext.form.Panel', {
    extend:'Ext.panel.Panel',
    mixins: {
        fieldAncestor: 'Ext.form.FieldAncestor'
    },
    alias: 'widget.form',
    alternateClassName: ['Ext.FormPanel', 'Ext.form.FormPanel'],
    requires: ['Ext.form.Basic', 'Ext.util.TaskRunner'],

    

    

    
    layout: 'anchor',

    ariaRole: 'form',
    
    basicFormConfigs: [
        'api', 
        'baseParams', 
        'errorReader', 
        'method', 
        'paramOrder',
        'paramsAsHash',
        'reader',
        'standardSubmit',
        'timeout',
        'trackResetOnLoad',
        'url',
        'waitMsgTarget',
        'waitTitle'
    ],

    initComponent: function() {
        var me = this;

        if (me.frame) {
            me.border = false;
        }

        me.initFieldAncestor();
        me.callParent();

        me.relayEvents(me.form, [
            
            'beforeaction',
            
            'actionfailed',
            
            'actioncomplete',
            
            'validitychange',
            
            'dirtychange'
        ]);

        
        if (me.pollForChanges) {
            me.startPolling(me.pollInterval || 500);
        }
    },

    initItems: function() {
        
        var me = this;

        me.form = me.createForm();
        me.callParent();
    },

    
    afterFirstLayout: function() {
        this.callParent();
        this.form.initialize();
    },

    
    createForm: function() {
        var cfg = {},
            props = this.basicFormConfigs,
            len = props.length,
            i = 0,
            prop;
            
        for (; i < len; ++i) {
            prop = props[i];
            cfg[prop] = this[prop];
        }
        return new Ext.form.Basic(this, cfg);
    },

    
    getForm: function() {
        return this.form;
    },

    
    loadRecord: function(record) {
        return this.getForm().loadRecord(record);
    },

    
    getRecord: function() {
        return this.getForm().getRecord();
    },

    
    getValues: function(asString, dirtyOnly, includeEmptyText, useDataValues) {
        return this.getForm().getValues(asString, dirtyOnly, includeEmptyText, useDataValues);
    },

    beforeDestroy: function() {
        this.stopPolling();
        this.form.destroy();
        this.callParent();
    },

    
    load: function(options) {
        this.form.load(options);
    },

    
    submit: function(options) {
        this.form.submit(options);
    },

    
    startPolling: function(interval) {
        this.stopPolling();
        var task = new Ext.util.TaskRunner(interval);
        task.start({
            interval: 0,
            run: this.checkChange,
            scope: this
        });
        this.pollTask = task;
    },

    
    stopPolling: function() {
        var task = this.pollTask;
        if (task) {
            task.stopAll();
            delete this.pollTask;
        }
    },

    
    checkChange: function() {
        var fields = this.form.getFields().items,
            f,
            fLen   = fields.length,
            field;

        for (f = 0; f < fLen; f++) {
            fields[f].checkChange();
        }
    }
});










Ext.define('Ext.grid.RowEditor', {
    extend: 'Ext.form.Panel',
    requires: [
        'Ext.tip.ToolTip',
        'Ext.util.HashMap',
        'Ext.util.KeyNav'
    ],

    
    saveBtnText  : 'Update',
    
    
    cancelBtnText: 'Cancel',
    
    
    errorsText: 'Errors',
    
    
    dirtyText: 'You need to commit or cancel your changes',
    

    lastScrollLeft: 0,
    lastScrollTop: 0,

    border: false,
    
    
    
    hideMode: 'offsets',

    initComponent: function() {
        var me = this,
            form;

        me.cls = Ext.baseCSSPrefix + 'grid-row-editor';

        me.layout = {
            type: 'hbox',
            align: 'middle'
        };

        
        
        me.columns = new Ext.util.HashMap();
        me.columns.getKey = function(columnHeader) {
            var f;
            if (columnHeader.getEditor) {
                f = columnHeader.getEditor();
                if (f) {
                    return f.id;
                }
            }
            return columnHeader.id;
        };
        me.mon(me.columns, {
            add: me.onFieldAdd,
            remove: me.onFieldRemove,
            replace: me.onFieldReplace,
            scope: me
        });

        me.callParent(arguments);

        if (me.fields) {
            me.setField(me.fields);
            delete me.fields;
        }
        
        me.mon(Ext.container.Container.hierarchyEventSource, {
            scope: me,
            show: me.repositionIfVisible
        });

        form = me.getForm();
        form.trackResetOnLoad = true;
    },

    onFieldChange: function() {
        var me = this,
            form = me.getForm(),
            valid = form.isValid();
        if (me.errorSummary && me.isVisible()) {
            me[valid ? 'hideToolTip' : 'showToolTip']();
        }
        me.updateButton(valid);
        me.isValid = valid;
    },
    
    updateButton: function(valid){
        var buttons = this.floatingButtons; 
        if (buttons) {
            buttons.child('#update').setDisabled(!valid);
        }    
    },

    afterRender: function() {
        var me = this,
            plugin = me.editingPlugin;

        me.callParent(arguments);
        me.mon(me.renderTo, 'scroll', me.onCtScroll, me, { buffer: 100 });

        
        me.mon(me.el, {
            click: Ext.emptyFn,
            stopPropagation: true
        });

        me.el.swallowEvent([
            'keypress',
            'keydown'
        ]);

        me.keyNav = new Ext.util.KeyNav(me.el, {
            enter: plugin.completeEdit,
            esc: plugin.onEscKey,
            scope: plugin
        });

        me.mon(plugin.view, {
            beforerefresh: me.onBeforeViewRefresh,
            refresh: me.onViewRefresh,
            itemremove: me.onViewItemRemove,
            scope: me
        });
    },

    onBeforeViewRefresh: function(view) {
        var me = this,
            viewDom = view.el.dom;

        if (me.el.dom.parentNode === viewDom) {
            viewDom.removeChild(me.el.dom);
        }
    },

    onViewRefresh: function(view) {
        var me = this,
            viewDom = view.el.dom,
            context = me.context,
            idx;

        viewDom.appendChild(me.el.dom);

        
        if (context && (idx = context.store.indexOf(context.record)) >= 0) {
            context.row = view.getNode(idx);
            me.reposition();
            if (me.tooltip && me.tooltip.isVisible()) {
                me.tooltip.setTarget(context.row);
            }
        } else {
            me.editingPlugin.cancelEdit();
        }
    },

    onViewItemRemove: function(record, index) {
        var context = this.context;
        if (context && record === context.record) {
            
            this.editingPlugin.cancelEdit();
        }
    },

    onCtScroll: function(e, target) {
        var me = this,
            scrollTop  = target.scrollTop,
            scrollLeft = target.scrollLeft;

        if (scrollTop !== me.lastScrollTop) {
            me.lastScrollTop = scrollTop;
            if ((me.tooltip && me.tooltip.isVisible()) || me.hiddenTip) {
                me.repositionTip();
            }
        }
        if (scrollLeft !== me.lastScrollLeft) {
            me.lastScrollLeft = scrollLeft;
            me.reposition();
        }
    },

    onColumnAdd: function(column) {
        if (!column.isGroupHeader) {
            this.setField(column);
        }
    },

    onColumnRemove: function(column) {
        this.columns.remove(column);
    },

    onColumnResize: function(column, width) {
        if (!column.isGroupHeader) {
            column.getEditor().setWidth(width - 2);
            this.repositionIfVisible();
        }
    },

    onColumnHide: function(column) {
        if (!column.isGroupHeader) {
            column.getEditor().hide();
            this.repositionIfVisible();
        }
    },

    onColumnShow: function(column) {
        var field = column.getEditor();
        field.setWidth(column.getWidth() - 2).show();
        this.repositionIfVisible();
    },

    onColumnMove: function(column, fromIdx, toIdx) {
        if (!column.isGroupHeader) {
            var field = column.getEditor();
            if (this.items.indexOf(field) != toIdx) {
                this.move(fromIdx, toIdx);
            }
        }
    },

    onFieldAdd: function(map, fieldId, column) {
        var me = this,
            colIdx,
            field;

        if (!column.isGroupHeader) {
            colIdx = me.editingPlugin.grid.headerCt.getHeaderIndex(column);
            field = column.getEditor({ xtype: 'displayfield' });
            me.insert(colIdx, field);
        }
    },

    onFieldRemove: function(map, fieldId, column) {
        var me = this,
            field,
            fieldEl;

        if (!column.isGroupHeader) {
            field = column.getEditor();
            fieldEl = field.el;
            me.remove(field, false);
            if (fieldEl) {
                fieldEl.remove();
            }
        }
    },

    onFieldReplace: function(map, fieldId, column, oldColumn) {
        this.onFieldRemove(map, fieldId, oldColumn);
    },

    clearFields: function() {
        var map = this.columns,
            key;

        for (key in map) {
            if (map.hasOwnProperty(key)) {
                map.removeAtKey(key);
            }
        }
    },

    getFloatingButtons: function() {
        var me = this,
            cssPrefix = Ext.baseCSSPrefix,
            btnsCss = cssPrefix + 'grid-row-editor-buttons',
            plugin = me.editingPlugin,
            minWidth = Ext.panel.Panel.prototype.minButtonWidth,
            btns;

        if (!me.floatingButtons) {
            btns = me.floatingButtons = new Ext.Container({
                renderTpl: [
                    '<div class="{baseCls}-ml"></div>',
                    '<div class="{baseCls}-mr"></div>',
                    '<div class="{baseCls}-bl"></div>',
                    '<div class="{baseCls}-br"></div>',
                    '<div class="{baseCls}-bc"></div>',
                    '{%this.renderContainer(out,values)%}'
                ],
                width: 200,
                renderTo: me.el,
                baseCls: btnsCss,
                layout: {
                    type: 'hbox',
                    align: 'middle'
                },
                defaults: {
                    flex: 1,
                    margins: '0 1 0 1'
                },
                items: [{
                    itemId: 'update',
                    xtype: 'button',
                    handler: plugin.completeEdit,
                    scope: plugin,
                    text: me.saveBtnText,
                    minWidth: minWidth
                }, {
                    xtype: 'button',
                    handler: plugin.cancelEdit,
                    scope: plugin,
                    text: me.cancelBtnText,
                    minWidth: minWidth
                }]
            });

            
            me.mon(btns.el, {
                
                
                mousedown: Ext.emptyFn,
                click: Ext.emptyFn,
                stopEvent: true
            });
        }
        return me.floatingButtons;
    },
    
    repositionIfVisible: function(c){
        var me = this,
            view = me.view;
        
        
        
        if (c && (c == me || !view.isDescendantOf(c))) {
            return;
        }
        
        if (me.isVisible() && view.isVisible(true)) {
            me.reposition();    
        }
    },

    reposition: function(animateConfig) {
        var me = this,
            context = me.context,
            row = context && Ext.get(context.row),
            btns = me.getFloatingButtons(),
            btnEl = btns.el,
            grid = me.editingPlugin.grid,
            viewEl = grid.view.el,

            
            
            mainBodyWidth = grid.headerCt.getFullWidth(),
            scrollerWidth = grid.getWidth(),

            
            
            width = Math.min(mainBodyWidth, scrollerWidth),
            scrollLeft = grid.view.el.dom.scrollLeft,
            btnWidth = btns.getWidth(),
            left = (width - btnWidth) / 2 + scrollLeft,
            y, rowH, newHeight,

            invalidateScroller = function() {
                btnEl.scrollIntoView(viewEl, false);
                if (animateConfig && animateConfig.callback) {
                    animateConfig.callback.call(animateConfig.scope || me);
                }
            },
            
            animObj;

        
        if (row && Ext.isElement(row.dom)) {
            
            
            row.scrollIntoView(viewEl, false);

            
            
            
            y = row.getXY()[1] - 5;
            rowH = row.getHeight();
            newHeight = rowH + (me.editingPlugin.grid.rowLines ? 9 : 10);

            
            if (me.getHeight() != newHeight) {
                me.setHeight(newHeight);
                me.el.setLeft(0);
            }

            if (animateConfig) {
                animObj = {
                    to: {
                        y: y
                    },
                    duration: animateConfig.duration || 125,
                    listeners: {
                        afteranimate: function() {
                            invalidateScroller();
                            y = row.getXY()[1] - 5;
                        }
                    }
                };
                me.el.animate(animObj);
            } else {
                me.el.setY(y);
                invalidateScroller();
            }
        }
        if (me.getWidth() != mainBodyWidth) {
            me.setWidth(mainBodyWidth);
        }
        btnEl.setLeft(left);
    },

    getEditor: function(fieldInfo) {
        var me = this;

        if (Ext.isNumber(fieldInfo)) {
            
            
            
            return me.query('>[isFormField]')[fieldInfo];
        } else if (fieldInfo.isHeader && !fieldInfo.isGroupHeader) {
            return fieldInfo.getEditor();
        }
    },

    removeField: function(field) {
        var me = this;

        
        field = me.getEditor(field);
        me.mun(field, 'validitychange', me.onValidityChange, me);

        
        
        me.columns.removeAtKey(field.id);
        Ext.destroy(field);
    },

    setField: function(column) {
        var me = this,
            i,
            length, field;

        if (Ext.isArray(column)) {
            length = column.length;

            for (i = 0; i < length; i++) {
                me.setField(column[i]);
            }

            return;
        }

        
        field = column.getEditor(null, {
            xtype: 'displayfield',
            
            
            getModelData: function() {
                return null;
            }
        });
        field.margins = '0 0 0 2';
        me.mon(field, 'change', me.onFieldChange, me);
        
        if (me.isVisible() && me.context) {
            if (field.is('displayfield')) {
                me.renderColumnData(field, me.context.record, column);
            } else {
                field.suspendEvents();
                field.setValue(me.context.record.get(column.dataIndex));
                field.resumeEvents();
            }
        }

        
        
        
        me.columns.add(field.id, column);
        if (column.hidden) {
            me.onColumnHide(column);
        } else if (column.rendered) {
            
            me.onColumnShow(column);
        }
    },

    loadRecord: function(record) {
        var me     = this,
            form   = me.getForm(),
            fields = form.getFields(),
            items  = fields.items,
            length = items.length,
            i, displayFields,
            isValid;
            
        
        for (i = 0; i < length; i++) {
            items[i].suspendEvents();
        }

        form.loadRecord(record);

        for (i = 0; i < length; i++) {
            items[i].resumeEvents();
        }

        isValid = form.isValid();
        if (me.errorSummary) {
            if (isValid) {
                me.hideToolTip();
            } else {
                me.showToolTip();
            }
        }
        
        me.updateButton(isValid);

        
        displayFields = me.query('>displayfield');
        length = displayFields.length;

        for (i = 0; i < length; i++) {
            me.renderColumnData(displayFields[i], record);
        }
    },

    renderColumnData: function(field, record, activeColumn) {
        var me = this,
            grid = me.editingPlugin.grid,
            headerCt = grid.headerCt,
            view = grid.view,
            store = view.store,
            column = activeColumn || me.columns.get(field.id),
            value = record.get(column.dataIndex),
            renderer = column.editRenderer || column.renderer,
            metaData,
            rowIdx,
            colIdx;

        
        if (renderer) {
            metaData = { tdCls: '', style: '' };
            rowIdx = store.indexOf(record);
            colIdx = headerCt.getHeaderIndex(column);

            value = renderer.call(
                column.scope || headerCt.ownerCt,
                value,
                metaData,
                record,
                rowIdx,
                colIdx,
                store,
                view
            );
        }

        field.setRawValue(value);
        field.resetOriginalValue();
    },

    beforeEdit: function() {
        var me = this;

        if (me.isVisible() && me.errorSummary && !me.autoCancel && me.isDirty()) {
            me.showToolTip();
            return false;
        }
    },

    
    startEdit: function(record, columnHeader) {
        var me = this,
            grid = me.editingPlugin.grid,
            store = grid.store,
            context = me.context = Ext.apply(me.editingPlugin.context, {
                view: grid.getView(),
                store: store
            });

        
        context.grid.getSelectionModel().select(record);

        
        me.loadRecord(record);

        if (!me.isVisible()) {
            me.show();
            me.focusContextCell();
        } else {
            me.reposition({
                callback: this.focusContextCell
            });
        }
    },

    
    focusContextCell: function() {
        var field = this.getEditor(this.context.colIdx);
        if (field && field.focus) {
            field.focus();
        }
    },

    cancelEdit: function() {
        var me     = this,
            form   = me.getForm(),
            fields = form.getFields(),
            items  = fields.items,
            length = items.length,
            i;

        me.hide();
        form.clearInvalid();

        
        for (i = 0; i < length; i++) {
            items[i].suspendEvents();
        }

        form.reset();

        for (i = 0; i < length; i++) {
            items[i].resumeEvents();
        }
    },

    completeEdit: function() {
        var me = this,
            form = me.getForm();

        if (!form.isValid()) {
            return;
        }

        form.updateRecord(me.context.record);
        me.hide();
        return true;
    },

    onShow: function() {
        this.callParent(arguments);
        this.reposition();
    },

    onHide: function() {
        var me = this;
        me.callParent(arguments);
        if (me.tooltip) {
            me.hideToolTip();
        }
        if (me.context) {
            me.context.view.focus();
            me.context = null;
        }
    },

    isDirty: function() {
        var me = this,
            form = me.getForm();
        return form.isDirty();
    },

    getToolTip: function() {
        return this.tooltip || (this.tooltip = new Ext.tip.ToolTip({
            cls: Ext.baseCSSPrefix + 'grid-row-editor-errors',
            title: this.errorsText,
            autoHide: false,
            closable: true,
            closeAction: 'disable',
            anchor: 'left'
        }));
    },

    hideToolTip: function() {
        var me = this,
            tip = me.getToolTip();
        if (tip.rendered) {
            tip.disable();
        }
        me.hiddenTip = false;
    },

    showToolTip: function() {
        var me = this,
            tip = me.getToolTip(),
            context = me.context,
            row = Ext.get(context.row),
            viewEl = context.grid.view.el;

        tip.setTarget(row);
        tip.showAt([-10000, -10000]);
        tip.update(me.getErrors());
        tip.mouseOffset = [viewEl.getWidth() - row.getWidth() + me.lastScrollLeft + 15, 0];
        me.repositionTip();
        tip.doLayout();
        tip.enable();
    },

    repositionTip: function() {
        var me = this,
            tip = me.getToolTip(),
            context = me.context,
            row = Ext.get(context.row),
            viewEl = context.grid.view.el,
            viewHeight = viewEl.getHeight(),
            viewTop = me.lastScrollTop,
            viewBottom = viewTop + viewHeight,
            rowHeight = row.getHeight(),
            rowTop = row.dom.offsetTop,
            rowBottom = rowTop + rowHeight;

        if (rowBottom > viewTop && rowTop < viewBottom) {
            tip.show();
            me.hiddenTip = false;
        } else {
            tip.hide();
            me.hiddenTip = true;
        }
    },

    getErrors: function() {
        var me        = this,
            dirtyText = !me.autoCancel && me.isDirty() ? me.dirtyText + '<br />' : '',
            errors    = [],
            fields    = me.query('>[isFormField]'),
            length    = fields.length,
            i;

        function createListItem(e) {
            return '<li>' + e + '</li>';
        }

        for (i = 0; i < length; i++) {
            errors = errors.concat(
                Ext.Array.map(fields[i].getErrors(), createListItem)
            );
        }

        return dirtyText + '<ul>' + errors.join('') + '</ul>';
    },
    
    beforeDestroy: function(){
        Ext.destroy(this.floatingButtons, this.tooltip);
        this.callParent();    
    }
});

Ext.define('Ext.grid.plugin.RowEditing', {
    extend: 'Ext.grid.plugin.Editing',
    alias: 'plugin.rowediting',

    requires: [
        'Ext.grid.RowEditor'
    ],

    editStyle: 'row',

    
    autoCancel: true,

    

    
    errorSummary: true,

    constructor: function() {
        var me = this;

        me.callParent(arguments);

        if (!me.clicksToMoveEditor) {
            me.clicksToMoveEditor = me.clicksToEdit;
        }

        me.autoCancel = !!me.autoCancel;
    },

    init: function(grid) {
        this.callParent([grid]);
    },

    
    destroy: function() {
        var me = this;
        Ext.destroy(me.editor);
        me.callParent(arguments);
    },

    
    startEdit: function(record, columnHeader) {
        var me = this,
            editor = me.getEditor();

        if ((editor.beforeEdit() !== false) && (me.callParent(arguments) !== false)) {
            editor.startEdit(me.context.record, me.context.column);
            return true;
        }
        return false;
    },

    
    cancelEdit: function() {
        var me = this;

        if (me.editing) {
            me.getEditor().cancelEdit();
            me.callParent(arguments);
        }
    },

    
    completeEdit: function() {
        var me = this;

        if (me.editing && me.validateEdit()) {
            me.editing = false;
            me.fireEvent('edit', me, me.context);
        }
    },

    
    validateEdit: function() {
        var me             = this,
            editor         = me.editor,
            context        = me.context,
            record         = context.record,
            newValues      = {},
            originalValues = {},
            editors        = editor.items.items,
            e,
            eLen           = editors.length,
            name, item;

        for (e = 0; e < eLen; e++) {
            item = editors[e];
            name = item.name;

            newValues[name]      = item.getValue();
            originalValues[name] = record.get(name);
        }

        Ext.apply(context, {
            newValues      : newValues,
            originalValues : originalValues
        });

        return me.callParent(arguments) && me.getEditor().completeEdit();
    },

    
    getEditor: function() {
        var me = this;

        if (!me.editor) {
            me.editor = me.initEditor();
        }
        return me.editor;
    },

    
    initEditor: function() {
        var me       = this,
            grid     = me.grid,
            view     = me.view,
            headerCt = grid.headerCt,
            btns     = ['saveBtnText', 'cancelBtnText', 'errorsText', 'dirtyText'],
            b,
            bLen     = btns.length,
            cfg      = {
                autoCancel: me.autoCancel,
                errorSummary: me.errorSummary,
                fields: headerCt.getGridColumns(),
                hidden: true,
                view: view,
                
                editingPlugin: me,
                renderTo: view.el
            },
            item;

        for (b = 0; b < bLen; b++) {
            item = btns[b];

            if (Ext.isDefined(me[item])) {
                cfg[item] = me[item];
            }
        }

        return Ext.create('Ext.grid.RowEditor', cfg);
    },

    
    initEditTriggers: function() {
        var me = this,
            view = me.view,
            moveEditorEvent = me.clicksToMoveEditor === 1 ? 'click' : 'dblclick';

        me.callParent(arguments);

        if (me.clicksToMoveEditor !== me.clicksToEdit) {
            me.mon(view, 'cell' + moveEditorEvent, me.moveEditorByClick, me);
        }

        view.on({
            render: function() {
                me.mon(me.grid.headerCt, {
                    scope: me,
                    columnresize: me.onColumnResize,
                    columnhide: me.onColumnHide,
                    columnshow: me.onColumnShow,
                    columnmove: me.onColumnMove
                });
            },
            single: true
        });
    },

    startEditByClick: function() {
        var me = this;
        if (!me.editing || me.clicksToMoveEditor === me.clicksToEdit) {
            me.callParent(arguments);
        }
    },

    moveEditorByClick: function() {
        var me = this;
        if (me.editing) {
            me.superclass.onCellClick.apply(me, arguments);
        }
    },
    
    
    onColumnAdd: function(ct, column) {
        if (column.isHeader) {
            var me = this,
                editor;

            me.initFieldAccessors(column);

            
            
            editor = me.editor;
            if (editor && editor.onColumnAdd) {
                editor.onColumnAdd(column);
            }
        }
    },

    
    onColumnRemove: function(ct, column) {
        if (column.isHeader) {
            var me = this,
                editor = me.getEditor();

            if (editor && editor.onColumnRemove) {
                editor.onColumnRemove(column);
            }
            me.removeFieldAccessors(column);
        }
    },

    
    onColumnResize: function(ct, column, width) {
        if (column.isHeader) {
            var me = this,
                editor = me.getEditor();

            if (editor && editor.onColumnResize) {
                editor.onColumnResize(column, width);
            }
        }
    },

    
    onColumnHide: function(ct, column) {
        
        var me = this,
            editor = me.getEditor();

        if (editor && editor.onColumnHide) {
            editor.onColumnHide(column);
        }
    },

    
    onColumnShow: function(ct, column) {
        
        var me = this,
            editor = me.getEditor();

        if (editor && editor.onColumnShow) {
            editor.onColumnShow(column);
        }
    },

    
    onColumnMove: function(ct, column, fromIdx, toIdx) {
        
        var me = this,
            editor = me.getEditor();

        if (editor && editor.onColumnMove) {
            
            
            editor.onColumnMove(column, fromIdx, toIdx - (toIdx > fromIdx ? 1 : 0));
        }
    },

    
    setColumnField: function(column, field) {
        var me = this,
            editor = me.getEditor();
            
        editor.removeField(column);
        me.callParent(arguments);
        me.getEditor().setField(column);
    }
});


Ext.define('Ext.view.TableLayout', {
    extend: 'Ext.layout.component.Auto',

    alias: ['layout.tableview'],
    type: 'tableview',

    beginLayout: function(ownerContext) {
        var me = this;

        me.callParent(arguments);

        
        if (me.owner.table.dom) {
            ownerContext.tableContext = ownerContext.getEl(me.owner.table);

            
            ownerContext.headerContext = ownerContext.context.getCmp(me.headerCt);
        }
    },

    calculate: function(ownerContext) {
        var me = this;

        me.callParent(arguments);

        if (ownerContext.tableContext) {
            if (ownerContext.state.columnWidthsSynced) {
                if (ownerContext.hasProp('columnWidthsFlushed')) {
                    ownerContext.tableContext.setHeight(ownerContext.tableContext.el.dom.offsetHeight, false);
                } else {
                    me.done = false;
                }
            } else {
                if (ownerContext.headerContext.hasProp('columnWidthsDone')) {
                    ownerContext.context.queueFlush(me);
                    ownerContext.state.columnWidthsSynced = true;
                }

                
                
                
                me.done = false;
            }
        }
    },

    measureContentHeight: function(ownerContext) {
        
        if (!ownerContext.headerContext || ownerContext.hasProp('columnWidthsFlushed')) {
            return this.callParent(arguments);
        }
    },

    flush: function() {
        var me = this,
            context = me.ownerContext.context,
            columns = me.headerCt.getGridColumns(),
            i = 0, len = columns.length,
            el = me.owner.el,
            tableWidth = 0,
            colWidth;

        
        context.currentLayout = me;

        
        for (i = 0; i < len; i++) {
            colWidth = columns[i].hidden ? 0 : context.getCmp(columns[i]).props.width;
            tableWidth += colWidth;

            
            
            
            el.select(me.getColumnSelector(columns[i])).setWidth(colWidth);
        }
        el.select('table.' + Ext.baseCSSPrefix + 'grid-table-resizer').setWidth(tableWidth);

        
        me.ownerContext.setProp('columnWidthsFlushed', true);
    },
    
    finishedLayout: function(){
        var me = this,
            first;
            
        me.callParent(arguments);   
        
        
        
        if (Ext.isGecko) {
            first = me.headerCt.getGridColumns()[0];
            if (first) {
                first = me.owner.el.down(me.getColumnSelector(first));
                if (first) {
                    first.setStyle('display', 'none');
                    first.dom.scrollWidth;
                    first.setStyle('display', '');
                }
            }
        } 
    },

    getColumnSelector: function(column) {
        return 'th.' + Ext.baseCSSPrefix + 'grid-col-resizer-' + column.id;
    }
});



Ext._endTime = new Date().getTime();
if (Ext._beforereadyhandler){
    Ext._beforereadyhandler();
}

})(this.Ext4 || (this.Ext4 = {}));
