    /**
     * @class Ext.Element
     */
    Ext.Element.addMethods(function(){
    	// local style camelizing for speed
    	var propCache = {},
    		camelRe = /(-[a-z])/gi,
    		classReCache = {},
    		view = document.defaultView,
    		EL = Ext.Element,
    		PADDING = "padding",
    		MARGIN = "margin",
    		BORDER = "border",
    		LEFT = "-left",
    		RIGHT = "-right",
    		TOP = "-top",
    		BOTTOM = "-bottom",
    		WIDTH = "-width",
    		// special markup used throughout Ext when box wrapping elements
    		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};

    	// private
    	function camelFn(m, a) {
    		return a.charAt(1).toUpperCase();
    	}

    	// private (needs to be called => addStyles.call(this, sides, styles))
    	function addStyles(sides, styles){
    	    var val = 0;

    	    Ext.each(sides.match(/\w/g), function(s) {
    			if (s = parseInt(this.getStyle(styles[s]), 10)) {
    				val += Math.abs(s);
    			}
    	    },
    	    this);
    	    return val;
    	}

    	function chkCache(prop) {
    		return propCache[prop] || (propCache[prop] = prop.replace(camelRe, camelFn))
        }

    	return {
    		// private  ==> used by Fx
    		adjustWidth : function(width) {
    			var me = this;
    	        if(typeof width == "number" && me.autoBoxAdjust && !me.isBorderBox()){
    	           width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
    	           width = width < 0 ? 0 : width;
    	        }
    		    return width;
    		},

    		// private   ==> used by Fx
    		adjustHeight : function(height) {
    			var me = this;
    			if(typeof height == "number" && me.autoBoxAdjust && !me.isBorderBox()){
    	           height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
    	           height = height < 0 ? 0 : height;
    	        }
    		    return height;
    		},

    		/**
    	     * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
    	     * @param {String/Array} className The CSS class to add, or an array of classes
    	     * @return {Ext.Element} this
    	     */
    	    addClass : function(className){
    		    var me = this;
    		    Ext.each(className, function(v) {
    				me.dom.className += (!me.hasClass(v) && v ? " " + v : "");
    		    });
    	        return me;
    	    },

    	    /**
    	     * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
    	     * @param {String/Array} className The CSS class to add, or an array of classes
    	     * @return {Ext.Element} this
    	     */
    	    radioClass : function(className){
    		    Ext.each(this.dom.parentNode.childNodes, function(v) {
    				if(v.nodeType == 1) {
    					Ext.get(v).removeClass(className);
    				}
    		    });
    		    return this.addClass(className);
    	    },

    	    /**
    	     * Removes one or more CSS classes from the element.
    	     * @param {String/Array} className The CSS class to remove, or an array of classes
    	     * @return {Ext.Element} this
    	     */
    	    removeClass : function(className){
    		    var me = this;
    		    if (me.dom.className) {
    				Ext.each(className, function(v) {
    					me.dom.className = me.dom.className.replace(
    						classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"),
    						" ");
    				});
    		    }
    		    return me;
    	    },

    	    /**
    	     * 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.Element} this
    	     */
    	    toggleClass : function(className){
    		    return this.hasClass(className) ? this.removeClass(className) : this.addClass(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
    	     */
    	    hasClass : function(className){
    	        return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
    	    },

    	    /**
    	     * 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.Element} this
    	     */
    	    replaceClass : function(oldClassName, newClassName){
    	        return this.removeClass(oldClassName).addClass(newClassName);
    	    },

    	    isStyle : function(style, val) {
    // 		    var ret = false;
    // 		    style = this.getStyle(style);
    // 		    Ext.each(Ext.toArray(arguments,1),function(s){
    // 			    if(style == s) return false; // stop iterating.
    // 		    });
    // 		    return ret;
    			return this.getStyle(style) == val;
    	    },

    	    /**
    	     * Normalizes currentStyle and computedStyle.
    	     * @param {String} property The style property whose value is returned.
    	     * @return {String} The current value of the style property for this element.
    	     */
    	    getStyle : function(){
    	        return view && view.getComputedStyle ?
    	            function(prop){
    	                var el = this.dom,
    	                	v,
    	                	cs;
    	                if(el == document) return null;
    	                prop = prop == 'float' ? 'cssFloat' : prop;
    					return (v = el.style[prop]) ? v :
    						   (cs = view.getComputedStyle(el, "")) ? cs[chkCache(prop)] : null;
    	            } :
    	            function(prop){
    		            var el = this.dom,
    			        	m,
    			        	cs;

    			        if(el == document) return null;
    	                if (prop == 'opacity') {
    	                    if (el.style.filter.match) {
    	                        if(m = el.style.filter.match(/alpha\(opacity=(.*)\)/i)){
    	                            var fv = parseFloat(m[1]);
    	                            if(!isNaN(fv)){
    	                                return fv ? fv / 100 : 0;
    	                            }
    	                        }
    	                    }
    	                    return 1;
    	                }
    	                prop = prop == 'float' ? 'styleFloat' : prop;
    	                return el.style[prop] || ((cs = el.currentStyle) ? cs[chkCache(prop)] : null);
    	            };
    	    }(),

    	    /**
    	     * 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 (optional) defaults to #. Use an empty string when working with
    	     * color anims.
    	     */
    	    getColor : function(attr, defaultValue, prefix){
    	        var v = this.getStyle(attr),
    	        	color = prefix || "#";

         	    if(!v || v == "transparent" || v == "inherit") {
    	            return defaultValue;
    	        }
    	        if (/^r/.test(v)) {
    		        Ext.each(v.slice(4, v.length -1).split(","), function(s) {
    			        h = (s * 1).toString(16);
    			   		color += h < 16 ? "0" + h : h;
    		        });
    			} else {
    				color += v.replace("#","").replace(/^(\w)(\w)(\w)$/, "$1$1$2$2$3$3");
    			}
    	        return color.length > 5 ? color.toLowerCase() : defaultValue;
    	    },

    	    /**
    	     * 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 (optional) The value to apply to the given property, or null if an object was passed.
    	     * @return {Ext.Element} this
    	     */
    	    setStyle : function(prop, value){
    		    var tmp,
    		    	style,
                    camel;
    		    if (!Ext.isObject(prop)) {
    			  	tmp = {};
    			  	tmp[prop] = value;
    			  	prop = tmp;
    		    }
    		    for (style in prop) {
    			    value = prop[style];
    			    camel = chkCache(style);
                    camel == 'opacity' ?
                        this.setOpacity(value) :
                        this.dom.style[camel] = value;
    		    }
    		    return this;
    	    },

    	    /**
    	     * Set the opacity of the element
    	     * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
    	     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
    	     * @return {Ext.Element} this
    	     */
    	     setOpacity : function(opacity, animate){
    		    var me = this,
    		    	s = me.dom.style;
    	        if(!animate || !me.anim){
    	            if (Ext.isIE) {
    	                s.zoom = 1;
    	                s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
    	                           (opacity == 1 ? "" : " alpha(opacity=" + opacity * 100 + ")");
    	            } else {
    	                s.opacity = opacity;
    	            }
    	        }else{
    	            me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');
    	        }
    	        return me;
    	    },

    	    /**
    	     * Clears any opacity settings from this element. Required in some cases for IE.
    	     * @return {Ext.Element} this
    	     */
    	    clearOpacity : function(){
    		    var style = this.dom.style;
    	        if (window.ActiveXObject) {
    	            if(typeof style.filter == 'string' && (/alpha/i).test(style.filter)){
    	                style.filter = "";
    	            }
    	        } else {
    	            style.opacity = "";
    	            style["-moz-opacity"] = "";
    	            style["-khtml-opacity"] = "";
    	        }
    	        return this;
    	    },

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

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

    	    /**
    	     * Set the width of this Element.
    	     * @param {Mixed} 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 (optional) true for the default animation or a standard Element animation config object
    	     * @return {Ext.Element} this
    	     */
    	    setWidth : function(width, animate){
    		    var me = this;
    	        width = me.adjustWidth(width);
    	        !animate || !me.anim ?
    	        	me.dom.style.width = me.addUnits(width) :
    	        	me.anim({width : {to : width}}, me.preanim(arguments, 1));
    	        return me;
    	    },

    	    /**
    	     * Set the height of this Element.
    	     * @param {Mixed} 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 (optional) true for the default animation or a standard Element animation config object
    	     * @return {Ext.Element} this
    	     */
    	     setHeight : function(height, animate){
    		    var me = this;
    	        height = me.adjustHeight(height);
    	        !animate || !me.anim ?
    	        	me.dom.style.height = me.addUnits(height) :
    	        	me.anim({height : {to : height}}, me.preanim(arguments, 1));
    	        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 addStyles.call(this, 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 addStyles.call(this, side, paddings);
    	    },

    	    /**
    	     *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
    	     * @return {Ext.Element} this
    	     */
    	    clip : function(){
    		    var me = this;
    	        if(!me.isClipped){
    	           me.isClipped = true;
    	           me.originalClip = {
    	               o: me.getStyle("overflow"),
    	               x: me.getStyle("overflow-x"),
    	               y: me.getStyle("overflow-y")
    	           };
    	           me.setStyle("overflow", "hidden");
    	           me.setStyle("overflow-x", "hidden");
    	           me.setStyle("overflow-y", "hidden");
    	        }
    	        return me;
    	    },

    	    /**
    	     *  Return clipping (overflow) to original clipping before clip() was called
    	     * @return {Ext.Element} this
    	     */
    	    unclip : function(){
    		    var me = this;
    	        if(me.isClipped){
    	            me.isClipped = false;
    	            var o = me.originalClip;
    	            if(o.o){me.setStyle("overflow", o.o);}
    	            if(o.x){me.setStyle("overflow-x", o.x);}
    	            if(o.y){me.setStyle("overflow-y", o.y);}
    	        }
    	        return me;
    	    },

    	    addStyles : addStyles,
    	    margins : margins
    	}
    }()
    );