    // @tag dom,core
    /**
     */
    Ext.define('Ext.dom.Element_style', {
        override: 'Ext.dom.Element'
    },
    function() {

    var Element = this,
        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,
        // This reduces the lookup of 'me.styleHooks' by one hop in the prototype chain. It is
        // the same object.
        styleHooks, verticalStyleHooks90, verticalStyleHooks270,
        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;

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

                    // In some cases, IE6 will throw Invalid Argument exceptions for properties
                    // like fontSize (/examples/tabs/tabs.html in 4.0 used to exhibit this but
                    // no longer does due to font style changes). There is a real cost to a try
                    // block, so we avoid it where possible...
                    if (hook.canThrow) {
                        try {
                            out = style[camel];
                        } catch (e) {
                            out = '';
                        }
                    } else {
                        // EXTJSIV-5657 - In IE9 quirks mode there is a chance that VML root element
                        // has neither `currentStyle` nor `style`. Return '' this case.
                        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,
                hidden = me.isStyle('display', 'none'),
                height,
                floating;

            if (hidden) {
                return 0;
            }

            height = me.dom.offsetHeight;

            // IE9/10 Direct2D dimension rounding bug
            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;
            }

            // Gecko will in some cases report an offsetWidth that is actually less than the width of the
            // text contents, because it measures fonts with sub-pixel precision but rounds the calculated
            // value down. Using getBoundingClientRect instead of offsetWidth allows us to get the precise
            // subpixel measurements so we can force them to always be rounded up. See
            // https://bugzilla.mozilla.org/show_bug.cgi?id=458617
            // Rounding up ensures that the width includes the full width of the text contents.
            if (preciseWidth && Ext.supports.BoundingClientRect) {
                rect = dom.getBoundingClientRect();
                // IE9 is the only browser that supports getBoundingClientRect() and
                // uses a filter to rotate the element vertically.  When a filter
                // is used to rotate the element, the getHeight/getWidth functions
                // are not inverted (see setVertical).
                width = (me.vertical && !Ext.isIE9 && !Ext.supports.RotatedBoundingClientRect) ?
                        (rect.bottom - rect.top) : (rect.right - rect.left);
            } else {
                width = dom.offsetWidth;
            }

            // IE9/10 Direct2D dimension rounding bug: https://sencha.jira.com/browse/EXTJSIV-603
            // there is no need make adjustments for this bug when the element is vertically
            // rotated because the width of a vertical element is its rotated height
            if (Ext.supports.Direct2DBug && !me.vertical) {
                // get the fractional portion of the sub-pixel precision width of the element's text contents
                floating = me.adjustDirect2DDimension(WIDTH);
                if (preciseWidth) {
                    width += floating;
                }
                // IE9 also measures fonts with sub-pixel precision, but unlike Gecko, instead of rounding the offsetWidth down,
                // it rounds to the nearest integer. This means that in order to ensure that the width includes the full
                // width of the text contents we need to increment the width by 1 only if the fractional portion is less than 0.5
                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)) { // in case of object from getSize()
                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 the body, use static methods
            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)};
        },

        // TODO: Look at this

        // private  ==> used by Fx
        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;
        },

        // private   ==> used by Fx
        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;
        },

        /**
         * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like `#fff`) and valid values
         * are convert to standard 6 digit hex color.
         * @param {String} attr The css attribute
         * @param {String} defaultValue The default value to use when a valid color isn't found
         * @param {String} [prefix] defaults to #. Use an empty string when working with
         * color anims.
         */
        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);
        },

        /**
         * Set the opacity of the element
         * @param {Number} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
         * @param {Boolean/Object} [animate] a standard Element animation config object or `true` for
         * the default animation (`{duration: 350, easing: 'easeIn'}`)
         * @return {Ext.dom.Element} this
         */
        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;
        },

        /**
         * Clears any opacity settings from this element. Required in some cases for IE.
         * @return {Ext.dom.Element} this
         */
        clearOpacity : function() {
            return this.setOpacity('');
        },

        /**
         * @private
         * Returns 1 if the browser returns the subpixel dimension rounded to the lowest pixel.
         * @return {Number} 0 or 1
         */
        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 will contain digits that appears after the decimal point
            // if height or width are set to auto we fallback to msTransformOrigin calculation

            // Use currentStyle here instead of getStyle. In some difficult to reproduce
            // instances it resets the scrollWidth of the element
            floating = (parseFloat(currentStyle[dimension]) || parseFloat(currentStyle.msTransformOrigin.split(' ')[originIndex]) * 2) % 1;

            dom.style.position = inlinePosition;

            if (display === 'inline') {
                dom.style.display = inlineDisplay;
            }

            return floating;
        },

        /**
         * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
         * @return {Ext.dom.Element} this
         */
        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;
        },

        /**
         * Return clipping (overflow) to original clipping before {@link #clip} was called
         * @return {Ext.dom.Element} this
         */
        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;
        },

        /**
         * Wraps the specified element with a special 9 element markup/CSS block that renders by default as
         * a gray container with a gradient background, rounded corners and a 4-way shadow.
         *
         * This special markup is used throughout Ext when box wrapping elements ({@link Ext.button.Button},
         * {@link Ext.panel.Panel} when {@link Ext.panel.Panel#frame frame=true}, {@link Ext.window.Window}).
         * The markup is of this form:
         *
         *     Ext.dom.Element.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>';
         *
         * Example usage:
         *
         *     // Basic box wrap
         *     Ext.get("foo").boxWrap();
         *
         *     // You can also add a custom class and use CSS inheritance rules to customize the box look.
         *     // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
         *     // for how to create a custom box wrap style.
         *     Ext.get("foo").boxWrap().addCls("x-box-blue");
         *
         * @param {String} [class='x-box'] A base CSS class to apply to the containing wrapper element.
         * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
         * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
         * @return {Ext.dom.Element} The outermost wrapping element of the created box structure.
         */
        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;
        },

        /**
         * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
         * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
         * if a height has not been set using CSS.
         * @return {Number}
         */
        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;
        },

        /**
         * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
         * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
         * if a width has not been set using CSS.
         * @return {Number}
         */
        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;
        },

        /**
         * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
         * for more information about the sides.
         * @param {String} sides
         * @return {Number}
         */
        getFrameWidth : function(sides, onlyContentBox) {
            return (onlyContentBox && this.isBorderBox()) ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
        },

        /**
         * Sets up event handlers to add and remove a css class when the mouse is over this element
         * @param {String} className The class to add
         * @param {Function} [testFn] A test function to execute before adding the class. The passed parameter
         * will be the Element instance. If this functions returns false, the class will not be added.
         * @param {Object} [scope] The scope to execute the testFn in.
         * @return {Ext.dom.Element} this
         */
        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;
        },

        /**
         * Sets up event handlers to add and remove a css class when this element has the focus
         * @param {String} className The class to add
         * @param {Function} [testFn] A test function to execute before adding the class. The passed parameter
         * will be the Element instance. If this functions returns false, the class will not be added.
         * @param {Object} [scope] The scope to execute the testFn in.
         * @return {Ext.dom.Element} this
         */
        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;
        },

        /**
         * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
         * @param {String} className The class to add
         * @param {Function} [testFn] A test function to execute before adding the class. The passed parameter
         * will be the Element instance. If this functions returns false, the class will not be added.
         * @param {Object} [scope] The scope to execute the testFn in.
         * @return {Ext.dom.Element} this
         */
        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;
        },

        /**
         * Returns the dimensions of the element available to lay content out in.
         *
         * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and
         * offsetWidth/clientWidth. To obtain the size excluding scrollbars, use getViewSize.
         *
         * 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
         */
        getStyleSize : function() {
            var me = this,
                d = this.dom,
                isDoc = DOCORBODYRE.test(d.nodeName),
                s ,
                w, h;

            // If the body, use static methods
            if (isDoc) {
                return {
                    width : Element.getViewWidth(),
                    height : Element.getViewHeight()
                };
            }

            s = me.getStyle([HEIGHT, WIDTH], true);  //seek inline
            // Use Styles if they are set
            if (s.width && s.width != 'auto') {
                w = parseFloat(s.width);
                if (me.isBorderBox()) {
                    w -= me.getFrameWidth('lr');
                }
            }
            // Use Styles if they are set
            if (s.height && s.height != 'auto') {
                h = parseFloat(s.height);
                if (me.isBorderBox()) {
                    h -= me.getFrameWidth('tb');
                }
            }
            // Use getWidth/getHeight if style not set.
            return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
        },

        statics: {
            selectableCls: Ext.baseCSSPrefix + 'selectable',
            unselectableCls: Ext.baseCSSPrefix + 'unselectable'
        },

        /**
         * Enable text selection for this element (normalized across browsers)
         * @return {Ext.Element} this
         */
        selectable : function() {
            var me = this;

            // We clear this property for all browsers, not just Opera. This is so that rendering templates don't need to
            // condition on Opera when making elements unselectable.
            me.dom.unselectable = '';

            me.removeCls(Element.unselectableCls);
            me.addCls(Element.selectableCls);

            return me;
        },

        /**
         * Disables text selection for this element (normalized across browsers)
         * @return {Ext.dom.Element} this
         */
        unselectable : function() {
            // The approach used to disable text selection combines CSS, HTML attributes and DOM events. Importantly the
            // strategy is designed to be expressible in markup, so that elements can be rendered unselectable without
            // needing modifications post-render. e.g.:
            //
            // <div class="x-unselectable" unselectable="on"></div>
            //
            // Changes to this method may need to be reflected elsewhere, e.g. ProtoElement.
            var me = this;

            // The unselectable property (or similar) is supported by various browsers but Opera is the only browser that
            // doesn't support any of the other techniques. The problem with it is that it isn't inherited by child
            // elements. Theoretically we could add it to all children but the performance would be terrible. In certain
            // key locations (e.g. panel headers) we add unselectable="on" to extra elements during rendering just for
            // Opera's benefit.
            if (Ext.isOpera) {
                me.dom.unselectable = 'on';
            }

            // In Mozilla and WebKit the CSS properties -moz-user-select and -webkit-user-select prevent a selection
            // originating in an element. These are inherited, which is what we want.
            //
            // In IE we rely on a listener for the selectstart event instead. We don't need to register a listener on the
            // individual element, instead we use a single listener and rely on event propagation to listen for the event at
            // the document level. That listener will walk up the DOM looking for nodes that have either of the classes
            // x-selectable or x-unselectable. This simulates the CSS inheritance approach.
            //
            // IE 10 is expected to support -ms-user-select so the listener may not be required.
            me.removeCls(Element.selectableCls);
            me.addCls(Element.unselectableCls);

            return me;
        },

        /**
         * Changes this Element's state to "vertical" (rotated 90 or 270 degrees).
         * This involves inverting the getters and setters for height and width,
         * and applying hooks for rotating getters and setters for border/margin/padding.
         * (getWidth becomes getHeight and vice versa), setStyle and getStyle will
         * also return the inverse when height or width are being operated on.
         *
         * @param {Number} angle the angle of rotation - either 90 or 270
         * @param {String} cls an optional css class that contains the required
         * styles for switching the element to vertical orientation. Omit this if
         * the element already contains vertical styling.  If cls is provided,
         * it will be removed from the element when {@link #setHorizontal} is called.
         * @private
         */
        setVertical: function(angle, cls) {
            var me = this,
                proto = Element.prototype,
                hooks;

            me.vertical = true;
            if (cls) {
                me.addCls(me.verticalCls = cls);
            }

            me.setWidth = proto.setHeight;
            me.setHeight = proto.setWidth;
            if (!Ext.isIE9m) {
                // In browsers that use CSS3 transforms we must invert getHeight and
                // get Width. In IE9 and below no adjustment is needed because we use
                // a BasicImage filter to rotate the element and the element's
                // offsetWidth and offsetHeight are automatically inverted.
                me.getWidth = proto.getHeight;
                me.getHeight = proto.getWidth;
            }

            // Switch to using the appropriate vertical style hooks
            me.styleHooks = (angle === 270) ?
                Element.prototype.verticalStyleHooks270 : Element.prototype.verticalStyleHooks90;
        },

        /**
         * Removes "vertical" state from this element (reverses everything done
         * by {@link #setVertical}).
         * @private
         */
        setHorizontal: function() {
            var me = this,
                cls = me.verticalCls;

            delete me.vertical;
            if (cls) {
                delete me.verticalCls;
                me.removeCls(cls);
            }

            // delete the inverted methods and revert to inheriting from the prototype
            delete me.setWidth;
            delete me.setHeight;
            if (!Ext.isIE9m) {
                delete me.getWidth;
                delete me.getHeight;
            }

            // revert to inheriting styleHooks from the prototype
            delete me.styleHooks;
        }
    });

    Element.prototype.styleHooks = styleHooks = Ext.dom.AbstractElement.prototype.styleHooks;

    // When elements are rotated 80 or 270 degrees, their border, margin and padding hooks
    // need to be rotated as well.
    Element.prototype.verticalStyleHooks90 = verticalStyleHooks90 = Ext.Object.chain(Element.prototype.styleHooks);
    Element.prototype.verticalStyleHooks270 = verticalStyleHooks270 = Ext.Object.chain(Element.prototype.styleHooks);

    verticalStyleHooks90.width = { name: 'height' };
    verticalStyleHooks90.height = { name: 'width' };
    verticalStyleHooks90['margin-top'] = { name: 'marginLeft' };
    verticalStyleHooks90['margin-right'] = { name: 'marginTop' };
    verticalStyleHooks90['margin-bottom'] = { name: 'marginRight' };
    verticalStyleHooks90['margin-left'] = { name: 'marginBottom' };
    verticalStyleHooks90['padding-top'] = { name: 'paddingLeft' };
    verticalStyleHooks90['padding-right'] = { name: 'paddingTop' };
    verticalStyleHooks90['padding-bottom'] = { name: 'paddingRight' };
    verticalStyleHooks90['padding-left'] = { name: 'paddingBottom' };
    verticalStyleHooks90['border-top'] = { name: 'borderLeft' };
    verticalStyleHooks90['border-right'] = { name: 'borderTop' };
    verticalStyleHooks90['border-bottom'] = { name: 'borderRight' };
    verticalStyleHooks90['border-left'] = { name: 'borderBottom' };

    verticalStyleHooks270.width = { name: 'height' };
    verticalStyleHooks270.height = { name: 'width' };
    verticalStyleHooks270['margin-top'] = { name: 'marginRight' };
    verticalStyleHooks270['margin-right'] = { name: 'marginBottom' };
    verticalStyleHooks270['margin-bottom'] = { name: 'marginLeft' };
    verticalStyleHooks270['margin-left'] = { name: 'marginTop' };
    verticalStyleHooks270['padding-top'] = { name: 'paddingRight' };
    verticalStyleHooks270['padding-right'] = { name: 'paddingBottom' };
    verticalStyleHooks270['padding-bottom'] = { name: 'paddingLeft' };
    verticalStyleHooks270['padding-left'] = { name: 'paddingTop' };
    verticalStyleHooks270['border-top'] = { name: 'borderRight' };
    verticalStyleHooks270['border-right'] = { name: 'borderBottom' };
    verticalStyleHooks270['border-bottom'] = { name: 'borderLeft' };
    verticalStyleHooks270['border-left'] = { name: 'borderTop' };

    if (Ext.isIE7m) {
        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
        };
    }

    // override getStyle for border-*-width
    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
            };
        }
    }

    // The following hack is needed to support padding on dom elements with display:table.
    // It was added because at one point auto layout's "outerCt" element had padding applied
    // to it. The padding is now appplied to the innerCt which is display:table-cell, so this
    // hack is not currently needed.
    //if (Ext.isIE9 && Ext.isStrict) {
    //    // In IE9, getComputedStyle always returns 0px for padding if the element has
    //    // "display:table", so we use currentStyle instead.
    //    var names = {
    //            padding: 'padding',
    //            paddingTop: 'padding-top',
    //            paddingRight: 'padding-right',
    //            paddingBottom: 'padding-bottom',
    //            paddingLeft: 'padding-left'
    //        },
    //        createHook = function(name, camelCaseName) {
    //            styleHooks[name] = styleHooks[camelCaseName] = {
    //                name: name,
    //                get: function(dom) {
    //                    return dom.currentStyle[name];
    //                }
    //            }
    //        },
    //        camelCaseName;
    //
    //    for (camelCaseName in names) {
    //        createHook(names[camelCaseName], camelCaseName);
    //    }
    //}

    // Element.unselectable relies on this listener to prevent selection in IE. Some other browsers support the event too
    // but it is only strictly required for IE. In WebKit this listener causes subtle differences to how the browser handles
    // the non-selection, e.g. whether or not the mouse cursor changes when attempting to select text.
    Ext.getDoc().on('selectstart', function(ev, dom) {
        var doc = document.documentElement,
            selectableCls = Element.selectableCls,
            unselectableCls = Element.unselectableCls,
            tagName = dom && dom.tagName;

        tagName = tagName && tagName.toLowerCase();

        // Element.unselectable is not really intended to handle selection within text fields and it is important that
        // fields inside menus or panel headers don't inherit the unselectability. In most browsers this is automatic but in
        // IE 9 the selectstart event can bubble up from text fields so we have to explicitly handle that case.
        if (tagName === 'input' || tagName === 'textarea') {
            return;
        }

        // Walk up the DOM checking the nodes. This may be 'slow' but selectstart events don't fire very often
        while (dom && dom.nodeType === 1 && dom !== doc) {
            var el = Ext.fly(dom);

            // If the node has the class x-selectable then stop looking, the text selection is allowed
            if (el.hasCls(selectableCls)) {
                return;
            }

            // If the node has class x-unselectable then the text selection needs to be stopped
            if (el.hasCls(unselectableCls)) {
                ev.stopEvent();
                return;
            }

            dom = dom.parentNode;
        }
    });

    });

    Ext.onReady(function () {
        var opacityRe = /alpha\(opacity=(.*)\)/i,
            trimRe = /^\s+|\s+$/g,
            hooks = Ext.dom.Element.prototype.styleHooks;

        // Ext.supports flags are not populated until onReady...
        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; // ensure dom.hasLayout

                    // value can be a number or '' or null... so treat falsey as no opacity
                    if (typeof(value) == 'number' && value >= 0 && value < 1) {
                        value *= 100;
                        style.filter = val + (val.length ? ' ' : '') + 'alpha(opacity='+value+')';
                    } else {
                        style.filter = val;
                    }
                }
            });
        }
        // else there is no work around for the lack of opacity support. Should not be a
        // problem given that this has been supported for a long time now...
    });