    /**
     * @class Ext.dom.AbstractElement
     */
    (function(){
        // local style camelizing for speed
        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',
            // special markup used throughout Ext when box wrapping elements
            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({

            /**
             * This shared object is keyed by style name (e.g., 'margin-left' or 'marginLeft'). The
             * values are objects with the following properties:
             *
             *  * `name` (String) : The actual name to be presented to the DOM. This is typically the value
             *      returned by {@link #normalize}.
             *  * `get` (Function) : A hook function that will perform the get on this style. These
             *      functions receive "(dom, el)" arguments. The `dom` parameter is the DOM Element
             *      from which to get ths tyle. The `el` argument (may be null) is the Ext.Element.
             *  * `set` (Function) : A hook function that will perform the set on this style. These
             *      functions receive "(dom, value, el)" arguments. The `dom` parameter is the DOM Element
             *      from which to get ths tyle. The `value` parameter is the new value for the style. The
             *      `el` argument (may be null) is the Ext.Element.
             *
             * The `this` pointer is the object that contains `get` or `set`, which means that
             * `this.name` can be accessed if needed. The hook functions are both optional.
             * @private
             */
            styleHooks: {},

            // private
            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]);
                    }
                    //Gather all at once, returning a hash
                    styleSides = this.getStyle(styleSides);

                    for (i=0; i < len; i++) {
                        side = sidesArr[i];
                        totalSize += Math.abs(parseFloat(styleSides[styles[side]]) || 0);
                    }
                }

                return totalSize;
            },

            /**
             * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
             * @param {String/String[]} className The CSS classes to add separated by space, or an array of classes
             * @return {Ext.dom.Element} this
             * @method
             */
            addCls: hasClassList ?
                function (className) {
                    //<debug warn>
                    if (String(className).indexOf('undefined') > -1) {
                        Ext.Logger.warn("called with an undefined className: " + className);
                    }
                    //</debug>
                    var me = this,
                        dom = me.dom,
                        classList,
                        newCls,
                        i,
                        len,
                        cls;

                    if (typeof(className) == 'string') {
                        // split string on spaces to make an array of className
                        className = className.replace(trimRe, '').split(spacesRe);
                    }

                    // the gain we have here is that we can skip parsing className and use the
                    // classList.contains method, so now O(M) not O(M+N)
                    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(' '); // write to DOM once
                            }
                        }
                    }
                    return me;
                } :
                function(className) {
                    //<debug warn>
                    if (String(className).indexOf('undefined') > -1) {
                        Ext.Logger.warn("called with an undefined className: '" + className + "'");
                    }
                    //</debug>
                    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(' '); // write to DOM once
                        }
                    }
                    return me;
                },

            /**
             * Removes one or more CSS classes from the element.
             * @param {String/String[]} className The CSS classes to remove separated by space, or an array of classes
             * @return {Ext.dom.Element} this
             */
            removeCls: function(className) {
                var me = this,
                    dom = me.dom,
                    len,
                    elClasses;

                if (typeof(className) == 'string') {
                    // split string on spaces to make an array of className
                    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]); // one DOM write
                        }
                    } else {
                        elClasses = Ext.Element.removeCls(dom.className, className);
                        if (elClasses.changed) {
                            dom.className = elClasses.join(' ');
                        }
                    }
                }
                return me;
            },

            /**
             * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
             * @param {String/String[]} className The CSS class to add, or an array of classes
             * @return {Ext.dom.Element} this
             */
            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);
            },

            /**
             * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
             * @param {String} className The CSS class to toggle
             * @return {Ext.dom.Element} this
             * @method
             */
            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);
                },

            /**
             * Checks if the specified CSS class exists on this element's DOM node.
             * @param {String} className The CSS class to check for
             * @return {Boolean} True if the class exists, else false
             * @method
             */
            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;
                },

            /**
             * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
             * @param {String} oldClassName The CSS class to replace
             * @param {String} newClassName The replacement CSS class
             * @return {Ext.dom.Element} this
             */
            replaceCls: function(oldClassName, newClassName){
                return this.removeCls(oldClassName).addCls(newClassName);
            },

            /**
             * Checks if the current value of a style is equal to a given value.
             * @param {String} style property whose value is returned.
             * @param {String} value to check against.
             * @return {Boolean} true for when the current value equals the given value.
             */
            isStyle: function(style, val) {
                return this.getStyle(style) == val;
            },

            /**
             * Returns a named style property based on computed/currentStyle (primary) and
             * inline-style if primary is not available.
             *
             * @param {String/String[]} property The style property (or multiple property names
             * in an array) whose value is returned.
             * @param {Boolean} [inline=false] if `true` only inline styles will be returned.
             * @return {String/Object} The current value of the style property for this element
             * (or a hash of named style values if multiple property arguments are requested).
             * @method
             */
            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 {
                    // Caution: Firefox will not render "presentation" (ie. computed styles) in
                    // iframes that are display:none or those inheriting display:none. Similar
                    // issues with legacy Safari.
                    //
                    style = dom.ownerDocument.defaultView.getComputedStyle(dom, null);

                    // fallback to inline style if rendering context not available
                    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);
            },

            /**
             * Returns true if the value of the given property is visually transparent. This
             * may be due to a 'transparent' style value or an rgba value with 0 in the alpha
             * component.
             * @param {String} prop The style property whose value is to be tested.
             * @return {Boolean} True if the style property is visually transparent.
             */
            isTransparent: function (prop) {
                var value = this.getStyle(prop);
                return value ? transparentRe.test(value) : false;
            },

            /**
             * Wrapper for setting style properties, also takes single object parameter of multiple styles.
             * @param {String/Object} property The style property to be set, or an object of multiple styles.
             * @param {String} [value] The value to apply to the given property, or null if an object was passed.
             * @return {Ext.dom.Element} this
             */
            setStyle: function(prop, value) {
                var me = this,
                    dom = me.dom,
                    hooks = me.styleHooks,
                    style = dom.style,
                    name = prop,
                    hook;

                // we don't promote the 2-arg form to object-form to avoid the overhead...
                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;
            },

            /**
             * Returns the offset height of the element
             * @param {Boolean} [contentHeight] true to get the height minus borders and padding
             * @return {Number} The element's height
             */
            getHeight: function(contentHeight) {
                var dom = this.dom,
                    height = contentHeight ? (dom.clientHeight - this.getPadding("tb")) : dom.offsetHeight;
                return height > 0 ? height: 0;
            },

            /**
             * Returns the offset width of the element
             * @param {Boolean} [contentWidth] true to get the width minus borders and padding
             * @return {Number} The element's width
             */
            getWidth: function(contentWidth) {
                var dom = this.dom,
                    width = contentWidth ? (dom.clientWidth - this.getPadding("lr")) : dom.offsetWidth;
                return width > 0 ? width: 0;
            },

            /**
             * Set the width of this Element.
             * @param {Number/String} width The new width. This may be one of:
             *
             * - A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).
             * - A String used to set the CSS width style. Animation may **not** be used.
             *
             * @param {Boolean/Object} [animate] true for the default animation or a standard Element animation config object
             * @return {Ext.dom.Element} this
             */
            setWidth: function(width) {
                var me = this;
                    me.dom.style.width = Element.addUnits(width);
                return me;
            },

            /**
             * Set the height of this Element.
             *
             *     // change the height to 200px and animate with default configuration
             *     Ext.fly('elementId').setHeight(200, true);
             *
             *     // change the height to 150px and animate with a custom configuration
             *     Ext.fly('elId').setHeight(150, {
             *         duration : 500, // animation will have a duration of .5 seconds
             *         // will change the content to "finished"
             *         callback: function(){ this.{@link #update}("finished"); }
             *     });
             *
             * @param {Number/String} height The new height. This may be one of:
             *
             * - A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)
             * - A String used to set the CSS height style. Animation may **not** be used.
             *
             * @param {Boolean/Object} [animate] true for the default animation or a standard Element animation config object
             * @return {Ext.dom.Element} this
             */
            setHeight: function(height) {
                var me = this;
                    me.dom.style.height = Element.addUnits(height);
                return me;
            },

            /**
             * Gets the width of the border(s) for the specified side(s)
             * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
             * passing `'lr'` would get the border **l**eft width + the border **r**ight width.
             * @return {Number} The width of the sides passed added together
             */
            getBorderWidth: function(side){
                return this.addStyles(side, borders);
            },

            /**
             * Gets the width of the padding(s) for the specified side(s)
             * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
             * passing `'lr'` would get the padding **l**eft + the padding **r**ight.
             * @return {Number} The padding of the sides passed added together
             */
            getPadding: function(side){
                return this.addStyles(side, paddings);
            },

            margins : margins,

            /**
             * More flexible version of {@link #setStyle} for setting style properties.
             * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
             * a function which returns such a specification.
             * @return {Ext.dom.Element} this
             */
            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);
                    }
                }
            },

            /**
             * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
             * @param {Number/String} width The new width. This may be one of:
             *
             * - A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).
             * - A String used to set the CSS width style. Animation may **not** be used.
             * - A size object in the format `{width: widthValue, height: heightValue}`.
             *
             * @param {Number/String} height The new height. This may be one of:
             *
             * - A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).
             * - A String used to set the CSS height style. Animation may **not** be used.
             *
             * @param {Boolean/Object} [animate] true for the default animation or a standard Element animation config object
             * @return {Ext.dom.Element} this
             */
            setSize: function(width, height) {
                var me = this,
                    style = me.dom.style;

                if (Ext.isObject(width)) {
                    // in case of object from getSize()
                    height = width.height;
                    width = width.width;
                }

                style.width = Element.addUnits(width);
                style.height = Element.addUnits(height);
                return me;
            },

            /**
             * Returns the dimensions of the element available to lay content out in.
             *
             * If the element (or any ancestor element) has CSS style `display: none`, the dimensions will be zero.
             *
             * Example:
             *
             *     var vpSize = Ext.getBody().getViewSize();
             *
             *     // all Windows created afterwards will have a default value of 90% height and 95% width
             *     Ext.Window.override({
             *         width: vpSize.width * 0.9,
             *         height: vpSize.height * 0.95
             *     });
             *     // To handle window resizing you would have to hook onto onWindowResize.
             *
             * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
             * To obtain the size including scrollbars, use getStyleSize
             *
             * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
             *
             * @return {Object} Object describing width and height.
             * @return {Number} return.width
             * @return {Number} return.height
             */
            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
                    };
                }
            },

            /**
             * Returns the size of the element.
             * @param {Boolean} [contentSize] true to get the width/size minus borders and padding
             * @return {Object} An object containing the element's size:
             * @return {Number} return.width
             * @return {Number} return.height
             */
            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)
                };
            },

            /**
             * Forces the browser to repaint this element
             * @return {Ext.dom.Element} this
             */
            repaint: function(){
                var dom = this.dom;
                this.addCls(Ext.baseCSSPrefix + 'repaint');
                setTimeout(function(){
                    Ext.fly(dom).removeCls(Ext.baseCSSPrefix + 'repaint');
                }, 1);
                return this;
            },

            /**
             * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
             * then it returns the calculated width of the sides (see getPadding)
             * @param {String} [sides] Any combination of l, r, t, b to get the sum of those sides
             * @return {Object/Number}
             */
            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') {
                        //now mixin nomalized values (from hash table)
                        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);
                }
            },

            /**
             * Puts a mask over this element to disable user interaction. Requires core.css.
             * This method can only be applied to elements which accept child nodes.
             * @param {String} [msg] A message to display in the mask
             * @param {String} [msgCls] A css class to apply to the msg element
             */
            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();
                }
            },

            /**
             * Removes a previously applied mask.
             */
            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;
                }
            }
        });

        /**
         * Creates mappings for 'margin-before' to 'marginLeft' (etc.) given the output
         * map and an ordering pair (e.g., ['left', 'right']). The ordering pair is in
         * before/after order.
         */
        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]; // margin-before
                    // ex: maps margin-before and marginBefore to marginLeft
                    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;

                // Ignore cases when the margin is correctly reported as 0, the bug only shows
                // numbers larger.
                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;

            // Populate the LTR flavors of margin-before et.al. (see Ext.rtl.AbstractElement):
            Element.populateStyleMap(styleHooks, ['left', 'right']);

            // Ext.supports needs to be initialized (we run very early in the onready sequence),
            // but it is OK to call Ext.supports.init() more times than necessary...
            if (supports.init) {
                supports.init();
            }

            // Fix bug caused by this: https://bugs.webkit.org/show_bug.cgi?id=13343
            if (!supports.RightMargin) {
                styleHooks.marginRight = styleHooks['margin-right'] = {
                    name: 'marginRight',
                    // TODO - Touch should use conditional compilation here or ensure that the
                    //      underlying Ext.supports flags are set correctly...
                    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
                    };
                }
            }
        });
    }());