Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / pkgs / classes.js
index 36e5f3c..d53261d 100644 (file)
@@ -32,7 +32,7 @@ If you are unsure which license is appropriate for your use, please contact the
  *             this.listeners = config.listeners;
  *
  *             // Call our superclass constructor to complete construction process.
- *             Employee.superclass.constructor.call(this, config)
+ *             this.callParent(arguments)
  *         }
  *     });
  *
@@ -58,7 +58,7 @@ Ext.define('Ext.util.Observable', {
         /**
          * Removes **all** added captures from the Observable.
          *
-         * @param {Observable} o The Observable to release
+         * @param {Ext.util.Observable} o The Observable to release
          * @static
          */
         releaseCapture: function(o) {
@@ -70,7 +70,7 @@ Ext.define('Ext.util.Observable', {
          * name + standard signature of the event **before** the event is fired. If the supplied function returns false,
          * the event will not fire.
          *
-         * @param {Observable} o The Observable to capture events from.
+         * @param {Ext.util.Observable} o The Observable to capture events from.
          * @param {Function} fn The function to call when an event is fired.
          * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed. Defaults to
          * the Observable firing the event.
@@ -120,9 +120,9 @@ Ext.define('Ext.util.Observable', {
      * should be a valid listeners config object as specified in the {@link #addListener} example for attaching multiple
      * handlers at once.
      *
-     * **DOM events from ExtJS {@link Ext.Component Components}**
+     * **DOM events from Ext JS {@link Ext.Component Components}**
      *
-     * While _some_ ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this is usually
+     * While _some_ Ext JS Component classes export selected DOM events (e.g. "click", "mouseover" etc), this is usually
      * only done when extra value can be added. For example the {@link Ext.view.View DataView}'s **`{@link
      * Ext.view.View#itemclick itemclick}`** event passing the node clicked on. To access DOM events directly from a
      * child element of a Component, we need to specify the `element` option to identify the Component property to add a
@@ -165,13 +165,13 @@ Ext.define('Ext.util.Observable', {
     },
 
     // @private
-    eventOptionsRe : /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|element|vertical|horizontal)$/,
+    eventOptionsRe : /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|element|vertical|horizontal|freezeEvent)$/,
 
     /**
-     * Adds listeners to any Observable object (or Element) which are automatically removed when this Component is
+     * Adds listeners to any Observable object (or Ext.Element) which are automatically removed when this Component is
      * destroyed.
      *
-     * @param {Observable/Element} item The item to which to add a listener/listeners.
+     * @param {Ext.util.Observable/Ext.Element} item The item to which to add a listener/listeners.
      * @param {Object/String} ename The event name, or an object containing event name properties.
      * @param {Function} fn (optional) If the `ename` parameter was an event name, this is the handler function.
      * @param {Object} scope (optional) If the `ename` parameter was an event name, this is the scope (`this` reference)
@@ -211,10 +211,10 @@ Ext.define('Ext.util.Observable', {
     /**
      * Removes listeners that were added by the {@link #mon} method.
      *
-     * @param {Observable|Element} item The item from which to remove a listener/listeners.
-     * @param {Object|String} ename The event name, or an object containing event name properties.
-     * @param {Function} fn Optional. If the `ename` parameter was an event name, this is the handler function.
-     * @param {Object} scope Optional. If the `ename` parameter was an event name, this is the scope (`this` reference)
+     * @param {Ext.util.Observable/Ext.Element} item The item from which to remove a listener/listeners.
+     * @param {Object/String} ename The event name, or an object containing event name properties.
+     * @param {Function} fn (optional) If the `ename` parameter was an event name, this is the handler function.
+     * @param {Object} scope (optional) If the `ename` parameter was an event name, this is the scope (`this` reference)
      * in which the handler function is executed.
      */
     removeManagedListener : function(item, ename, fn, scope) {
@@ -255,51 +255,72 @@ Ext.define('Ext.util.Observable', {
      * @param {Object...} args Variable number of parameters are passed to handlers.
      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
      */
-    fireEvent: function() {
-        var me = this,
-            args = Ext.Array.toArray(arguments),
-            ename = args[0].toLowerCase(),
-            ret = true,
-            event = me.events[ename],
-            queue = me.eventQueue,
-            parent;
+    fireEvent: function(eventName) {
+        var name = eventName.toLowerCase(),
+            events = this.events,
+            event = events && events[name],
+            bubbles = event && event.bubble;
 
-        if (me.eventsSuspended === true) {
-            if (queue) {
-                queue.push(args);
-            }
-        } else if (event && event !== true) {
-            if (event.bubble) {
-                if (event.fire.apply(event, args.slice(1)) === false) {
-                    return false;
+        return this.continueFireEvent(name, Ext.Array.slice(arguments, 1), bubbles);
+    },
+
+    /**
+     * Continue to fire event.
+     * @private
+     *
+     * @param {String} eventName
+     * @param {Array} args
+     * @param {Boolean} bubbles
+     */
+    continueFireEvent: function(eventName, args, bubbles) {
+        var target = this,
+            queue, event,
+            ret = true;
+
+        do {
+            if (target.eventsSuspended === true) {
+                if ((queue = target.eventQueue)) {
+                    queue.push([eventName, args, bubbles]);
                 }
-                parent = me.getBubbleTarget && me.getBubbleTarget();
-                if (parent && parent.isObservable) {
-                    if (!parent.events[ename] || parent.events[ename] === true || !parent.events[ename].bubble) {
-                        parent.enableBubble(ename);
+                return ret;
+            } else {
+                event = target.events[eventName];
+                // Continue bubbling if event exists and it is `true` or the handler didn't returns false and it
+                // configure to bubble.
+                if (event && event != true) {
+                    if ((ret = event.fire.apply(event, args)) === false) {
+                        break;
                     }
-                    return parent.fireEvent.apply(parent, args);
-                }                
-            }
-            else {
-                args.shift();
-                ret = event.fire.apply(event, args);
+                }
             }
-        }
+        } while (bubbles && (target = target.getBubbleParent()));
         return ret;
     },
 
+    /**
+     * Gets the bubbling parent for an Observable
+     * @private
+     * @return {Ext.util.Observable} The bubble parent. null is returned if no bubble target exists
+     */
+    getBubbleParent: function(){
+        var me = this, parent = me.getBubbleTarget && me.getBubbleTarget();
+        if (parent && parent.isObservable) {
+            return parent;
+        }
+        return null;
+    },
+
     /**
      * Appends an event handler to this object.
      *
      * @param {String} eventName The name of the event to listen for. May also be an object who's property names are
      * event names.
-     * @param {Function} handler The method the event invokes.  Will be called with arguments given to
+     * @param {Function} fn The method the event invokes.  Will be called with arguments given to
      * {@link #fireEvent} plus the `options` parameter described below.
-     * @param {Object} scope (optional) The scope (`this` reference) in which the handler function is executed. **If
+     * @param {Object} [scope] The scope (`this` reference) in which the handler function is executed. **If
      * omitted, defaults to the object which fired the event.**
-     * @param {Object} options (optional) An object containing handler configuration.
-     * 
+     * @param {Object} [options] An object containing handler configuration.
+     *
      * **Note:** Unlike in ExtJS 3.x, the options object will also be passed as the last argument to every event handler.
      *
      * This object may contain any of the following properties:
@@ -407,9 +428,10 @@ Ext.define('Ext.util.Observable', {
      * Removes an event handler.
      *
      * @param {String} eventName The type of event the handler was associated with.
-     * @param {Function} handler The handler to remove. **This must be a reference to the function passed into the
+     * @param {Function} fn The handler to remove. **This must be a reference to the function passed into the
      * {@link #addListener} call.**
-     * @param {Object} scope (optional) The scope originally specified for the handler.
+     * @param {Object} scope (optional) The scope originally specified for the handler. It must be the same as the
+     * scope argument specified in the original call to {@link #addListener} or the listener will not be removed.
      */
     removeListener: function(ename, fn, scope) {
         var me = this,
@@ -479,7 +501,7 @@ Ext.define('Ext.util.Observable', {
 
         this.managedListeners = [];
     },
-    
+
     /**
      * Remove a single managed listener item
      * @private
@@ -492,7 +514,7 @@ Ext.define('Ext.util.Observable', {
             managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
             if (!isClear) {
                 Ext.Array.remove(this.managedListeners, managedListener);
-            }    
+            }
         }
     },
 
@@ -516,7 +538,7 @@ Ext.define('Ext.util.Observable', {
      *         storecleared: true
      *     });
      *
-     * @param {String...} more Optional additional event names if multiple event names are being passed as separate
+     * @param {String...} more (optional) Additional event names if multiple event names are being passed as separate
      * parameters. Usage:
      *
      *     this.addEvents('storeloaded', 'storecleared');
@@ -527,12 +549,12 @@ Ext.define('Ext.util.Observable', {
             args,
             len,
             i;
-            
+
             me.events = me.events || {};
         if (Ext.isString(o)) {
             args = arguments;
             i = args.length;
-            
+
             while (i--) {
                 me.events[args[i]] = me.events[args[i]] || true;
             }
@@ -567,29 +589,30 @@ Ext.define('Ext.util.Observable', {
 
     /**
      * Resumes firing events (see {@link #suspendEvents}).
-     * 
-     * If events were suspended using the `**queueSuspended**` parameter, then all events fired
+     *
+     * If events were suspended using the `queueSuspended` parameter, then all events fired
      * during event suspension will be sent to any listeners now.
      */
     resumeEvents: function() {
         var me = this,
-            queued = me.eventQueue || [];
+            queued = me.eventQueue;
 
         me.eventsSuspended = false;
         delete me.eventQueue;
 
-        Ext.each(queued,
-        function(e) {
-            me.fireEvent.apply(me, e);
-        });
+        if (queued) {
+            Ext.each(queued, function(e) {
+                me.continueFireEvent.apply(me, e);
+            });
+        }
     },
 
     /**
      * Relays selected events from the specified Observable as if the events were fired by `this`.
      *
      * @param {Object} origin The Observable whose events this object is to relay.
-     * @param {[String]} events Array of event names to relay.
-     * @param {Object} prefix
+     * @param {String[]} events Array of event names to relay.
+     * @param {String} prefix
      */
     relayEvents : function(origin, events, prefix) {
         prefix = prefix || '';
@@ -659,7 +682,7 @@ Ext.define('Ext.util.Observable', {
      *         }
      *     });
      *
-     * @param {String/[String]} events The event name to bubble, or an Array of event names.
+     * @param {String/String[]} events The event name to bubble, or an Array of event names.
      */
     enableBubble: function(events) {
         var me = this;
@@ -830,7 +853,7 @@ Ext.define('Ext.util.Observable', {
  * This animation class is a mixin.
  * 
  * Ext.util.Animate provides an API for the creation of animated transitions of properties and styles.  
- * This class is used as a mixin and currently applied to {@link Ext.core.Element}, {@link Ext.CompositeElement}, 
+ * This class is used as a mixin and currently applied to {@link Ext.Element}, {@link Ext.CompositeElement}, 
  * {@link Ext.draw.Sprite}, {@link Ext.draw.CompositeSprite}, and {@link Ext.Component}.  Note that Components 
  * have a limited subset of what attributes can be animated such as top, left, x, y, height, width, and 
  * opacity (color, paddings, and margins can not be animated).
@@ -948,7 +971,7 @@ Ext.define('Ext.util.Observable', {
  * 
  * ## Animation Keyframes
  *
- * You can also set up complex animations with {@link Ext.fx.Anim#keyframe keyframe} which follows the 
+ * You can also set up complex animations with {@link Ext.fx.Anim#keyframes keyframes} which follow the 
  * CSS3 Animation configuration pattern. Note rotation, translation, and scaling can only be done for sprites. 
  * The previous example can be written with the following syntax:
  * 
@@ -972,7 +995,7 @@ Ext.define('Ext.util.Observable', {
  * 
  * ## Animation Events
  * 
- * Each animation you create has events for {@link Ext.fx.Anim#beforeanimation beforeanimation}, 
+ * Each animation you create has events for {@link Ext.fx.Anim#beforeanimate beforeanimate}, 
  * {@link Ext.fx.Anim#afteranimate afteranimate}, and {@link Ext.fx.Anim#lastframe lastframe}.  
  * Keyframed animations adds an additional {@link Ext.fx.Animator#keyframe keyframe} event which 
  * fires for each keyframe in your animation.
@@ -1033,7 +1056,7 @@ Ext.define('Ext.util.Animate', {
 
     /**
      * <p>Perform custom animation on this object.<p>
-     * <p>This method is applicable to both the {@link Ext.Component Component} class and the {@link Ext.core.Element Element} class.
+     * <p>This method is applicable to both the {@link Ext.Component Component} class and the {@link Ext.Element Element} class.
      * It performs animated transitions of certain properties of this object over a specified timeline.</p>
      * <p>The sole parameter is an object which specifies start property values, end property values, and properties which
      * describe the timeline. Of the properties listed below, only <b><code>to</code></b> is mandatory.</p>
@@ -1060,7 +1083,7 @@ Ext.define('Ext.util.Animate', {
      * <li><code>listeners</code> <div class="sub-desc">This is a standard {@link Ext.util.Observable#listeners listeners} configuration object which may be used
      * to inject behaviour at either the <code>beforeanimate</code> event or the <code>afteranimate</code> event.</div></li>
      * </ul></p>
-     * <h3>Animating an {@link Ext.core.Element Element}</h3>
+     * <h3>Animating an {@link Ext.Element Element}</h3>
      * When animating an Element, the following properties may be specified in <code>from</code>, <code>to</code>, and <code>keyframe</code> objects:<ul>
      * <li><code>x</code> <div class="sub-desc">The page X position in pixels.</div></li>
      * <li><code>y</code> <div class="sub-desc">The page Y position in pixels</div></li>
@@ -1154,7 +1177,7 @@ myWindow.header.el.on('click', function() {
      * @deprecated 4.0 Replaced by {@link #stopAnimation}
      * Stops any running effects and clears this object's internal effects queue if it contains
      * any additional effects that haven't started yet.
-     * @return {Ext.core.Element} The Element
+     * @return {Ext.Element} The Element
      * @method
      */
     stopFx: Ext.Function.alias(Ext.util.Animate, 'stopAnimation'),
@@ -1162,7 +1185,7 @@ myWindow.header.el.on('click', function() {
     /**
      * Stops any running effects and clears this object's internal effects queue if it contains
      * any additional effects that haven't started yet.
-     * @return {Ext.core.Element} The Element
+     * @return {Ext.Element} The Element
      */
     stopAnimation: function() {
         Ext.fx.Manager.stopAnimation(this.id);
@@ -1195,22 +1218,21 @@ myWindow.header.el.on('click', function() {
 
     /**
      * @deprecated 4.0 Replaced by {@link #getActiveAnimation}
-     * Returns thq current animation if this object has any effects actively running or queued, else returns false.
-     * @return {Mixed} anim if element has active effects, else false
+     * @alias Ext.util.Animate#getActiveAnimation
      * @method
      */
     hasActiveFx: Ext.Function.alias(Ext.util.Animate, 'getActiveAnimation'),
 
     /**
-     * Returns thq current animation if this object has any effects actively running or queued, else returns false.
-     * @return {Mixed} anim if element has active effects, else false
+     * Returns the current animation if this object has any effects actively running or queued, else returns false.
+     * @return {Ext.fx.Anim/Boolean} Anim if element has active effects, else false
      */
     getActiveAnimation: function() {
         return Ext.fx.Manager.getActiveAnimation(this.id);
     }
 }, function(){
     // Apply Animate mixin manually until Element is defined in the proper 4.x way
-    Ext.applyIf(Ext.core.Element.prototype, this.prototype);
+    Ext.applyIf(Ext.Element.prototype, this.prototype);
     // We need to call this again so the animation methods get copied over to CE
     Ext.CompositeElementLite.importElementMethods();
 });
@@ -1244,7 +1266,7 @@ Ext.define('Ext.state.Provider', {
         /**
          * @event statechange
          * Fires when a state change occurs.
-         * @param {Provider} this This state provider
+         * @param {Ext.state.Provider} this This state provider
          * @param {String} key The state key which was changed
          * @param {String} value The encoded value for the state
          */
@@ -1256,8 +1278,8 @@ Ext.define('Ext.state.Provider', {
     /**
      * Returns the current value for a key
      * @param {String} name The key name
-     * @param {Mixed} defaultValue A default value to return if the key's value is not found
-     * @return {Mixed} The state data
+     * @param {Object} defaultValue A default value to return if the key's value is not found
+     * @return {Object} The state data
      */
     get : function(name, defaultValue){
         return typeof this.state[name] == "undefined" ?
@@ -1277,7 +1299,7 @@ Ext.define('Ext.state.Provider', {
     /**
      * Sets the value for a key
      * @param {String} name The key name
-     * @param {Mixed} value The value to set
+     * @param {Object} value The value to set
      */
     set : function(name, value){
         var me = this;
@@ -1288,7 +1310,7 @@ Ext.define('Ext.state.Provider', {
     /**
      * Decodes a string previously encoded with {@link #encodeValue}.
      * @param {String} value The value to decode
-     * @return {Mixed} The decoded value
+     * @return {Object} The decoded value
      */
     decodeValue : function(value){
 
@@ -1347,7 +1369,7 @@ Ext.define('Ext.state.Provider', {
 
     /**
      * Encodes a value including type information.  Decode with {@link #decodeValue}.
-     * @param {Mixed} value The value to encode
+     * @param {Object} value The value to encode
      * @return {String} The encoded value
      */
     encodeValue : function(value){
@@ -1387,236 +1409,751 @@ Ext.define('Ext.state.Provider', {
     }
 });
 /**
- * @class Ext.util.HashMap
- * <p>
- * Represents a collection of a set of key and value pairs. Each key in the HashMap
- * must be unique, the same key cannot exist twice. Access to items is provided via
- * the key only. Sample usage:
- * <pre><code>
-var map = new Ext.util.HashMap();
-map.add('key1', 1);
-map.add('key2', 2);
-map.add('key3', 3);
-
-map.each(function(key, value, length){
-    console.log(key, value, length);
-});
- * </code></pre>
- * </p>
+ * Provides searching of Components within Ext.ComponentManager (globally) or a specific
+ * Ext.container.Container on the document with a similar syntax to a CSS selector.
  *
- * <p>The HashMap is an unordered class,
- * there is no guarantee when iterating over the items that they will be in any particular
- * order. If this is required, then use a {@link Ext.util.MixedCollection}.
- * </p>
+ * Components can be retrieved by using their {@link Ext.Component xtype} with an optional . prefix
+ *
+ * - `component` or `.component`
+ * - `gridpanel` or `.gridpanel`
+ *
+ * An itemId or id must be prefixed with a #
+ *
+ * - `#myContainer`
+ *
+ * Attributes must be wrapped in brackets
+ *
+ * - `component[autoScroll]`
+ * - `panel[title="Test"]`
+ *
+ * Member expressions from candidate Components may be tested. If the expression returns a *truthy* value,
+ * the candidate Component will be included in the query:
+ *
+ *     var disabledFields = myFormPanel.query("{isDisabled()}");
+ *
+ * Pseudo classes may be used to filter results in the same way as in {@link Ext.DomQuery DomQuery}:
+ *
+ *     // Function receives array and returns a filtered array.
+ *     Ext.ComponentQuery.pseudos.invalid = function(items) {
+ *         var i = 0, l = items.length, c, result = [];
+ *         for (; i < l; i++) {
+ *             if (!(c = items[i]).isValid()) {
+ *                 result.push(c);
+ *             }
+ *         }
+ *         return result;
+ *     };
+ *      
+ *     var invalidFields = myFormPanel.query('field:invalid');
+ *     if (invalidFields.length) {
+ *         invalidFields[0].getEl().scrollIntoView(myFormPanel.body);
+ *         for (var i = 0, l = invalidFields.length; i < l; i++) {
+ *             invalidFields[i].getEl().frame("red");
+ *         }
+ *     }
+ *
+ * Default pseudos include:
+ *
+ * - not
+ * - last
+ *
+ * Queries return an array of components.
+ * Here are some example queries.
+ *
+ *     // retrieve all Ext.Panels in the document by xtype
+ *     var panelsArray = Ext.ComponentQuery.query('panel');
+ *
+ *     // retrieve all Ext.Panels within the container with an id myCt
+ *     var panelsWithinmyCt = Ext.ComponentQuery.query('#myCt panel');
+ *
+ *     // retrieve all direct children which are Ext.Panels within myCt
+ *     var directChildPanel = Ext.ComponentQuery.query('#myCt > panel');
+ *
+ *     // retrieve all grids and trees
+ *     var gridsAndTrees = Ext.ComponentQuery.query('gridpanel, treepanel');
+ *
+ * For easy access to queries based from a particular Container see the {@link Ext.container.Container#query},
+ * {@link Ext.container.Container#down} and {@link Ext.container.Container#child} methods. Also see
+ * {@link Ext.Component#up}.
  */
-Ext.define('Ext.util.HashMap', {
+Ext.define('Ext.ComponentQuery', {
+    singleton: true,
+    uses: ['Ext.ComponentManager']
+}, function() {
 
-    /**
-     * @cfg {Function} keyFn A function that is used to retrieve a default key for a passed object.
-     * A default is provided that returns the <b>id</b> property on the object. This function is only used
-     * if the add method is called with a single argument.
-     */
+    var cq = this,
 
-    mixins: {
-        observable: 'Ext.util.Observable'
-    },
+        // A function source code pattern with a placeholder which accepts an expression which yields a truth value when applied
+        // as a member on each item in the passed array.
+        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(''),
 
-    /**
-     * Creates new HashMap.
-     * @param {Object} config (optional) Config object.
-     */
-    constructor: function(config) {
-        config = config || {};
-        
-        var me = this,
-            keyFn = config.keyFn;
+        filterItems = function(items, operation) {
+            // Argument list for the operation is [ itemsArray, operationArg1, operationArg2...]
+            // The operation's method loops over each item in the candidate array and
+            // returns an array of items which match its criteria
+            return operation.method.apply(this, [ items ].concat(operation.args));
+        },
 
-        me.addEvents(
-            /**
-             * @event add
-             * Fires when a new item is added to the hash
-             * @param {Ext.util.HashMap} this.
-             * @param {String} key The key of the added item.
-             * @param {Object} value The value of the added item.
-             */
-            'add',
-            /**
-             * @event clear
-             * Fires when the hash is cleared.
-             * @param {Ext.util.HashMap} this.
-             */
-            'clear',
-            /**
-             * @event remove
-             * Fires when an item is removed from the hash.
-             * @param {Ext.util.HashMap} this.
-             * @param {String} key The key of the removed item.
-             * @param {Object} value The value of the removed item.
-             */
-            'remove',
-            /**
-             * @event replace
-             * Fires when an item is replaced in the hash.
-             * @param {Ext.util.HashMap} this.
-             * @param {String} key The key of the replaced item.
-             * @param {Object} value The new value for the item.
-             * @param {Object} old The old value for the item.
-             */
-            'replace'
-        );
+        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;
+        },
 
-        me.mixins.observable.constructor.call(me, config);
-        me.clear(true);
-        
-        if (keyFn) {
-            me.getKey = keyFn;
-        }
-    },
+        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;
+        },
 
-    /**
-     * Gets the number of items in the hash.
-     * @return {Number} The number of items in the hash.
-     */
-    getCount: function() {
-        return this.length;
-    },
+        // Filters the passed candidate array and returns only items which match the passed xtype
+        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;
+            }
+        },
 
-    /**
-     * Implementation for being able to extract the key from an object if only
-     * a single argument is passed.
-     * @private
-     * @param {String} key The key
-     * @param {Object} value The value
-     * @return {Array} [key, value]
-     */
-    getData: function(key, value) {
-        // if we have no value, it means we need to get the key from the object
-        if (value === undefined) {
-            value = key;
-            key = this.getKey(value);
-        }
+        // Filters the passed candidate array and returns only items which have the passed className
+        filterByClassName = function(items, className) {
+            var EA = Ext.Array,
+                result = [],
+                i = 0,
+                length = items.length,
+                candidate;
+            for (; i < length; i++) {
+                candidate = items[i];
+                if (candidate.el ? candidate.el.hasCls(className) : EA.contains(candidate.initCls(), className)) {
+                    result.push(candidate);
+                }
+            }
+            return result;
+        },
 
-        return [key, value];
-    },
+        // Filters the passed candidate array and returns only items which have the specified property match
+        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;
+        },
 
-    /**
-     * Extracts the key from an object. This is a default implementation, it may be overridden
-     * @param {Object} o The object to get the key from
-     * @return {String} The key to use.
-     */
-    getKey: function(o) {
-        return o.id;
-    },
+        // Filters the passed candidate array and returns only items which have the specified itemId or id
+        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;
+        },
 
-    /**
-     * Adds an item to the collection. Fires the {@link #add} event when complete.
-     * @param {String} key <p>The key to associate with the item, or the new item.</p>
-     * <p>If a {@link #getKey} implementation was specified for this HashMap,
-     * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
-     * the HashMap will be able to <i>derive</i> the key for the new item.
-     * In this case just pass the new item in this parameter.</p>
-     * @param {Object} o The item to add.
-     * @return {Object} The item added.
-     */
-    add: function(key, value) {
-        var me = this,
-            data;
+        // Filters the passed candidate array and returns only items which the named pseudo class matcher filters in
+        filterByPseudo = function(items, name, value) {
+            return cq.pseudos[name](items, value);
+        },
 
-        if (arguments.length === 1) {
-            value = key;
-            key = me.getKey(value);
-        }
+        // Determines leading mode
+        // > for direct child, and ^ to switch to ownerCt axis
+        modeRe = /^(\s?([>\^])\s?|\s|$)/,
 
-        if (me.containsKey(key)) {
-            me.replace(key, value);
-        }
+        // Matches a token with possibly (true|false) appended for the "shallow" parameter
+        tokenRe = /^(#)?([\w\-]+|\*)(?:\((true|false)\))?/,
 
-        data = me.getData(key, value);
-        key = data[0];
-        value = data[1];
-        me.map[key] = value;
-        ++me.length;
-        me.fireEvent('add', me, key, value);
-        return value;
-    },
+        matchers = [{
+            // Checks for .xtype with possibly (true|false) appended for the "shallow" parameter
+            re: /^\.([\w\-]+)(?:\((true|false)\))?/,
+            method: filterByXType
+        },{
+            // checks for [attribute=value]
+            re: /^(?:[\[](?:@)?([\w\-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]])/,
+            method: filterByAttribute
+        }, {
+            // checks for #cmpItemId
+            re: /^#([\w\-]+)/,
+            method: filterById
+        }, {
+            // checks for :<pseudo_class>(<selector>)
+            re: /^\:([\w\-]+)(?:\(((?:\{[^\}]+\})|(?:(?!\{)[^\s>\/]*?(?!\})))\))?/,
+            method: filterByPseudo
+        }, {
+            // checks for {<member_expression>}
+            re: /^(?:\{([^\}]+)\})/,
+            method: filterFnPattern
+        }];
 
-    /**
-     * Replaces an item in the hash. If the key doesn't exist, the
-     * {@link #add} method will be used.
-     * @param {String} key The key of the item.
-     * @param {Object} value The new value for the item.
-     * @return {Object} The new value of the item.
-     */
-    replace: function(key, value) {
-        var me = this,
-            map = me.map,
-            old;
+    // @class Ext.ComponentQuery.Query
+    // This internal class is completely hidden in documentation.
+    cq.Query = Ext.extend(Object, {
+        constructor: function(cfg) {
+            cfg = cfg || {};
+            Ext.apply(this, cfg);
+        },
 
-        if (!me.containsKey(key)) {
-            me.add(key, value);
-        }
-        old = map[key];
-        map[key] = value;
-        me.fireEvent('replace', me, key, value, old);
-        return value;
-    },
+        // Executes this Query upon the selected root.
+        // The root provides the initial source of candidate Component matches which are progressively
+        // filtered by iterating through this Query's operations cache.
+        // If no root is provided, all registered Components are searched via the ComponentManager.
+        // root may be a Container who's descendant Components are filtered
+        // root may be a Component with an implementation of getRefItems which provides some nested Components such as the
+        // docked items within a Panel.
+        // root may be an array of candidate Components to filter using this Query.
+        execute : function(root) {
+            var operations = this.operations,
+                i = 0,
+                length = operations.length,
+                operation,
+                workingItems;
 
-    /**
-     * Remove an item from the hash.
-     * @param {Object} o The value of the item to remove.
-     * @return {Boolean} True if the item was successfully removed.
-     */
-    remove: function(o) {
-        var key = this.findKey(o);
-        if (key !== undefined) {
-            return this.removeAtKey(key);
-        }
-        return false;
-    },
+            // no root, use all Components in the document
+            if (!root) {
+                workingItems = Ext.ComponentManager.all.getArray();
+            }
+            // Root is a candidate Array
+            else if (Ext.isArray(root)) {
+                workingItems = root;
+            }
 
-    /**
-     * Remove an item from the hash.
-     * @param {String} key The key to remove.
-     * @return {Boolean} True if the item was successfully removed.
-     */
-    removeAtKey: function(key) {
-        var me = this,
-            value;
+            // We are going to loop over our operations and take care of them
+            // one by one.
+            for (; i < length; i++) {
+                operation = operations[i];
 
-        if (me.containsKey(key)) {
-            value = me.map[key];
-            delete me.map[key];
-            --me.length;
-            me.fireEvent('remove', me, key, value);
-            return true;
-        }
-        return false;
-    },
+                // The mode operation requires some custom handling.
+                // All other operations essentially filter down our current
+                // working items, while mode replaces our current working
+                // items by getting children from each one of our current
+                // working items. The type of mode determines the type of
+                // children we get. (e.g. > only gets direct children)
+                if (operation.mode === '^') {
+                    workingItems = getAncestors(workingItems || [root]);
+                }
+                else if (operation.mode) {
+                    workingItems = getItems(workingItems || [root], operation.mode);
+                }
+                else {
+                    workingItems = filterItems(workingItems || getItems([root]), operation);
+                }
 
-    /**
-     * Retrieves an item with a particular key.
-     * @param {String} key The key to lookup.
-     * @return {Object} The value at that key. If it doesn't exist, <tt>undefined</tt> is returned.
-     */
-    get: function(key) {
-        return this.map[key];
-    },
+                // If this is the last operation, it means our current working
+                // items are the final matched items. Thus return them!
+                if (i === length -1) {
+                    return workingItems;
+                }
+            }
+            return [];
+        },
 
-    /**
-     * Removes all items from the hash.
-     * @return {Ext.util.HashMap} this
-     */
-    clear: function(/* private */ initial) {
-        var me = this;
-        me.map = {};
-        me.length = 0;
-        if (initial !== true) {
-            me.fireEvent('clear', me);
-        }
-        return me;
-    },
+        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, {
+
+        // private cache of selectors and matching ComponentQuery.Query objects
+        cache: {},
+
+        // private cache of pseudo class filter functions
+        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;
+            },
+            last: function(components) {
+                return components[components.length - 1];
+            }
+        },
+
+        /**
+         * Returns an array of matched Components from within the passed root object.
+         *
+         * This method filters returned Components in a similar way to how CSS selector based DOM
+         * queries work using a textual selector string.
+         *
+         * See class summary for details.
+         *
+         * @param {String} selector The selector string to filter returned Components
+         * @param {Ext.container.Container} root The Container within which to perform the query.
+         * If omitted, all Components within the document are included in the search.
+         * 
+         * This parameter may also be an array of Components to filter according to the selector.</p>
+         * @returns {Ext.Component[]} The matched Components.
+         * 
+         * @member Ext.ComponentQuery
+         */
+        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];
+                if (!query) {
+                    this.cache[selector] = query = this.parse(selector);
+                }
+                results = results.concat(query.execute(root));
+            }
+
+            // multiple selectors, potential to find duplicates
+            // lets filter them out.
+            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;
+        },
+
+        /**
+         * Tests whether the passed Component matches the selector string.
+         * @param {Ext.Component} component The Component to test
+         * @param {String} selector The selector string to test against.
+         * @return {Boolean} True if the Component matches the selector.
+         * @member Ext.ComponentQuery
+         */
+        is: function(component, selector) {
+            if (!selector) {
+                return true;
+            }
+            var query = this.cache[selector];
+            if (!query) {
+                this.cache[selector] = query = this.parse(selector);
+            }
+            return query.is(component);
+        },
+
+        parse: function(selector) {
+            var operations = [],
+                length = matchers.length,
+                lastSelector,
+                tokenMatch,
+                matchedChar,
+                modeMatch,
+                selectorMatch,
+                i, matcher, method;
+
+            // We are going to parse the beginning of the selector over and
+            // over again, slicing off the selector any portions we converted into an
+            // operation, until it is an empty string.
+            while (selector && lastSelector !== selector) {
+                lastSelector = selector;
+
+                // First we check if we are dealing with a token like #, * or an xtype
+                tokenMatch = selector.match(tokenRe);
+
+                if (tokenMatch) {
+                    matchedChar = tokenMatch[1];
+
+                    // If the token is prefixed with a # we push a filterById operation to our stack
+                    if (matchedChar === '#') {
+                        operations.push({
+                            method: filterById,
+                            args: [Ext.String.trim(tokenMatch[2])]
+                        });
+                    }
+                    // If the token is prefixed with a . we push a filterByClassName operation to our stack
+                    // FIXME: Not enabled yet. just needs \. adding to the tokenRe prefix
+                    else if (matchedChar === '.') {
+                        operations.push({
+                            method: filterByClassName,
+                            args: [Ext.String.trim(tokenMatch[2])]
+                        });
+                    }
+                    // If the token is a * or an xtype string, we push a filterByXType
+                    // operation to the stack.
+                    else {
+                        operations.push({
+                            method: filterByXType,
+                            args: [Ext.String.trim(tokenMatch[2]), Boolean(tokenMatch[3])]
+                        });
+                    }
+
+                    // Now we slice of the part we just converted into an operation
+                    selector = selector.replace(tokenMatch[0], '');
+                }
+
+                // If the next part of the query is not a space or > or ^, it means we
+                // are going to check for more things that our current selection
+                // has to comply to.
+                while (!(modeMatch = selector.match(modeRe))) {
+                    // Lets loop over each type of matcher and execute it
+                    // on our current selector.
+                    for (i = 0; selector && i < length; i++) {
+                        matcher = matchers[i];
+                        selectorMatch = selector.match(matcher.re);
+                        method = matcher.method;
+
+                        // If we have a match, add an operation with the method
+                        // associated with this matcher, and pass the regular
+                        // expression matches are arguments to the operation.
+                        if (selectorMatch) {
+                            operations.push({
+                                method: Ext.isString(matcher.method)
+                                    // Turn a string method into a function by formatting the string with our selector matche expression
+                                    // A new method is created for different match expressions, eg {id=='textfield-1024'}
+                                    // Every expression may be different in different selectors.
+                                    ? 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; // Break on match
+                        }
+                        //<debug>
+                        // Exhausted all matches: It's an error
+                        if (i === (length - 1)) {
+                            Ext.Error.raise('Invalid ComponentQuery selector: "' + arguments[0] + '"');
+                        }
+                        //</debug>
+                    }
+                }
+
+                // Now we are going to check for a mode change. This means a space
+                // or a > to determine if we are going to select all the children
+                // of the currently matched items, or a ^ if we are going to use the
+                // ownerCt axis as the candidate source.
+                if (modeMatch[1]) { // Assignment, and test for truthiness!
+                    operations.push({
+                        mode: modeMatch[2]||modeMatch[1]
+                    });
+                    selector = selector.replace(modeMatch[0], '');
+                }
+            }
+
+            //  Now that we have all our operations in an array, we are going
+            // to create a new Query using these operations.
+            return new cq.Query({
+                operations: operations
+            });
+        }
+    });
+});
+/**
+ * @class Ext.util.HashMap
+ * <p>
+ * Represents a collection of a set of key and value pairs. Each key in the HashMap
+ * must be unique, the same key cannot exist twice. Access to items is provided via
+ * the key only. Sample usage:
+ * <pre><code>
+var map = new Ext.util.HashMap();
+map.add('key1', 1);
+map.add('key2', 2);
+map.add('key3', 3);
+
+map.each(function(key, value, length){
+    console.log(key, value, length);
+});
+ * </code></pre>
+ * </p>
+ *
+ * <p>The HashMap is an unordered class,
+ * there is no guarantee when iterating over the items that they will be in any particular
+ * order. If this is required, then use a {@link Ext.util.MixedCollection}.
+ * </p>
+ */
+Ext.define('Ext.util.HashMap', {
+    mixins: {
+        observable: 'Ext.util.Observable'
+    },
+
+    /**
+     * @cfg {Function} keyFn A function that is used to retrieve a default key for a passed object.
+     * A default is provided that returns the <b>id</b> property on the object. This function is only used
+     * if the add method is called with a single argument.
+     */
+
+    /**
+     * Creates new HashMap.
+     * @param {Object} config (optional) Config object.
+     */
+    constructor: function(config) {
+        config = config || {};
+        
+        var me = this,
+            keyFn = config.keyFn;
+
+        me.addEvents(
+            /**
+             * @event add
+             * Fires when a new item is added to the hash
+             * @param {Ext.util.HashMap} this.
+             * @param {String} key The key of the added item.
+             * @param {Object} value The value of the added item.
+             */
+            'add',
+            /**
+             * @event clear
+             * Fires when the hash is cleared.
+             * @param {Ext.util.HashMap} this.
+             */
+            'clear',
+            /**
+             * @event remove
+             * Fires when an item is removed from the hash.
+             * @param {Ext.util.HashMap} this.
+             * @param {String} key The key of the removed item.
+             * @param {Object} value The value of the removed item.
+             */
+            'remove',
+            /**
+             * @event replace
+             * Fires when an item is replaced in the hash.
+             * @param {Ext.util.HashMap} this.
+             * @param {String} key The key of the replaced item.
+             * @param {Object} value The new value for the item.
+             * @param {Object} old The old value for the item.
+             */
+            'replace'
+        );
+
+        me.mixins.observable.constructor.call(me, config);
+        me.clear(true);
+        
+        if (keyFn) {
+            me.getKey = keyFn;
+        }
+    },
+
+    /**
+     * Gets the number of items in the hash.
+     * @return {Number} The number of items in the hash.
+     */
+    getCount: function() {
+        return this.length;
+    },
+
+    /**
+     * Implementation for being able to extract the key from an object if only
+     * a single argument is passed.
+     * @private
+     * @param {String} key The key
+     * @param {Object} value The value
+     * @return {Array} [key, value]
+     */
+    getData: function(key, value) {
+        // if we have no value, it means we need to get the key from the object
+        if (value === undefined) {
+            value = key;
+            key = this.getKey(value);
+        }
+
+        return [key, value];
+    },
+
+    /**
+     * Extracts the key from an object. This is a default implementation, it may be overridden
+     * @param {Object} o The object to get the key from
+     * @return {String} The key to use.
+     */
+    getKey: function(o) {
+        return o.id;
+    },
+
+    /**
+     * Adds an item to the collection. Fires the {@link #add} event when complete.
+     * @param {String} key <p>The key to associate with the item, or the new item.</p>
+     * <p>If a {@link #getKey} implementation was specified for this HashMap,
+     * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
+     * the HashMap will be able to <i>derive</i> the key for the new item.
+     * In this case just pass the new item in this parameter.</p>
+     * @param {Object} o The item to add.
+     * @return {Object} The item added.
+     */
+    add: function(key, value) {
+        var me = this,
+            data;
+
+        if (arguments.length === 1) {
+            value = key;
+            key = me.getKey(value);
+        }
+
+        if (me.containsKey(key)) {
+            return me.replace(key, value);
+        }
+
+        data = me.getData(key, value);
+        key = data[0];
+        value = data[1];
+        me.map[key] = value;
+        ++me.length;
+        me.fireEvent('add', me, key, value);
+        return value;
+    },
+
+    /**
+     * Replaces an item in the hash. If the key doesn't exist, the
+     * {@link #add} method will be used.
+     * @param {String} key The key of the item.
+     * @param {Object} value The new value for the item.
+     * @return {Object} The new value of the item.
+     */
+    replace: function(key, value) {
+        var me = this,
+            map = me.map,
+            old;
+
+        if (!me.containsKey(key)) {
+            me.add(key, value);
+        }
+        old = map[key];
+        map[key] = value;
+        me.fireEvent('replace', me, key, value, old);
+        return value;
+    },
+
+    /**
+     * Remove an item from the hash.
+     * @param {Object} o The value of the item to remove.
+     * @return {Boolean} True if the item was successfully removed.
+     */
+    remove: function(o) {
+        var key = this.findKey(o);
+        if (key !== undefined) {
+            return this.removeAtKey(key);
+        }
+        return false;
+    },
+
+    /**
+     * Remove an item from the hash.
+     * @param {String} key The key to remove.
+     * @return {Boolean} True if the item was successfully removed.
+     */
+    removeAtKey: function(key) {
+        var me = this,
+            value;
+
+        if (me.containsKey(key)) {
+            value = me.map[key];
+            delete me.map[key];
+            --me.length;
+            me.fireEvent('remove', me, key, value);
+            return true;
+        }
+        return false;
+    },
+
+    /**
+     * Retrieves an item with a particular key.
+     * @param {String} key The key to lookup.
+     * @return {Object} The value at that key. If it doesn't exist, <tt>undefined</tt> is returned.
+     */
+    get: function(key) {
+        return this.map[key];
+    },
+
+    /**
+     * Removes all items from the hash.
+     * @return {Ext.util.HashMap} this
+     */
+    clear: function(/* private */ initial) {
+        var me = this;
+        me.map = {};
+        me.length = 0;
+        if (initial !== true) {
+            me.fireEvent('clear', me);
+        }
+        return me;
+    },
+
+    /**
      * Checks whether a key exists in the hash.
      * @param {String} key The key to check for.
      * @return {Boolean} True if they key exists in the hash.
@@ -1738,16882 +2275,16693 @@ Ext.define('Ext.util.HashMap', {
 });
 
 /**
- * @class Ext.Template
- * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
- * for greater performance.</p>
- * An instance of this class may be created by passing to the constructor either
- * a single argument, or multiple arguments:
- * <div class="mdetail-params"><ul>
- * <li><b>single argument</b> : String/Array
- * <div class="sub-desc">
- * The single argument may be either a String or an Array:<ul>
- * <li><tt>String</tt> : </li><pre><code>
-var t = new Ext.Template("&lt;div>Hello {0}.&lt;/div>");
-t.{@link #append}('some-element', ['foo']);
-   </code></pre>
- * <li><tt>Array</tt> : </li>
- * An Array will be combined with <code>join('')</code>.
-<pre><code>
-var t = new Ext.Template([
-    '&lt;div name="{id}"&gt;',
-        '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
-    '&lt;/div&gt;',
-]);
-t.{@link #compile}();
-t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
-   </code></pre>
- * </ul></div></li>
- * <li><b>multiple arguments</b> : String, Object, Array, ...
- * <div class="sub-desc">
- * Multiple arguments will be combined with <code>join('')</code>.
- * <pre><code>
-var t = new Ext.Template(
-    '&lt;div name="{id}"&gt;',
-        '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',
-    '&lt;/div&gt;',
-    // a configuration object:
-    {
-        compiled: true,      // {@link #compile} immediately
-    }
-);
-   </code></pre>
- * <p><b>Notes</b>:</p>
- * <div class="mdetail-params"><ul>
- * <li>For a list of available format functions, see {@link Ext.util.Format}.</li>
- * <li><code>disableFormats</code> reduces <code>{@link #apply}</code> time
- * when no formatting is required.</li>
- * </ul></div>
- * </div></li>
- * </ul></div>
- * @param {Mixed} config
+ * @class Ext.state.Manager
+ * This is the global state manager. By default all components that are "state aware" check this class
+ * for state information if you don't pass them a custom state provider. In order for this class
+ * to be useful, it must be initialized with a provider when your application initializes. Example usage:
+ <pre><code>
+// in your initialization function
+init : function(){
+   Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
+   var win = new Window(...);
+   win.restoreState();
+}
+ </code></pre>
+ * This class passes on calls from components to the underlying {@link Ext.state.Provider} so that
+ * there is a common interface that can be used without needing to refer to a specific provider instance
+ * in every component.
+ * @singleton
+ * @docauthor Evan Trimboli <evan@sencha.com>
  */
+Ext.define('Ext.state.Manager', {
+    singleton: true,
+    requires: ['Ext.state.Provider'],
+    constructor: function() {
+        this.provider = Ext.create('Ext.state.Provider');
+    },
+    
+    
+    /**
+     * Configures the default state provider for your application
+     * @param {Ext.state.Provider} stateProvider The state provider to set
+     */
+    setProvider : function(stateProvider){
+        this.provider = stateProvider;
+    },
 
-Ext.define('Ext.Template', {
-
-    /* Begin Definitions */
-
-    requires: ['Ext.core.DomHelper', 'Ext.util.Format'],
+    /**
+     * Returns the current value for a key
+     * @param {String} name The key name
+     * @param {Object} defaultValue The default value to return if the key lookup does not match
+     * @return {Object} The state data
+     */
+    get : function(key, defaultValue){
+        return this.provider.get(key, defaultValue);
+    },
 
-    statics: {
-        /**
-         * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
-         * @param {String/HTMLElement} el A DOM element or its id
-         * @param {Object} config A configuration object
-         * @return {Ext.Template} The created template
-         * @static
-         */
-        from: function(el, config) {
-            el = Ext.getDom(el);
-            return new this(el.value || el.innerHTML, config || '');
-        }
+    /**
+     * Sets the value for a key
+     * @param {String} name The key name
+     * @param {Object} value The state data
+     */
+     set : function(key, value){
+        this.provider.set(key, value);
     },
 
+    /**
+     * Clears a value from the state
+     * @param {String} name The key name
+     */
+    clear : function(key){
+        this.provider.clear(key);
+    },
+
+    /**
+     * Gets the currently configured state provider
+     * @return {Ext.state.Provider} The state provider
+     */
+    getProvider : function(){
+        return this.provider;
+    }
+});
+/**
+ * @class Ext.state.Stateful
+ * A mixin for being able to save the state of an object to an underlying
+ * {@link Ext.state.Provider}.
+ */
+Ext.define('Ext.state.Stateful', {
+
+    /* Begin Definitions */
+
+   mixins: {
+        observable: 'Ext.util.Observable'
+    },
+
+    requires: ['Ext.state.Manager'],
+
     /* End Definitions */
 
-    constructor: function(html) {
-        var me = this,
-            args = arguments,
-            buffer = [],
-            i = 0,
-            length = args.length,
-            value;
+    /**
+     * @cfg {Boolean} stateful
+     * <p>A flag which causes the object to attempt to restore the state of
+     * internal properties from a saved state on startup. The object must have
+     * a <code>{@link #stateId}</code> for state to be managed.
+     * Auto-generated ids are not guaranteed to be stable across page loads and
+     * cannot be relied upon to save and restore the same state for a object.<p>
+     * <p>For state saving to work, the state manager's provider must have been
+     * set to an implementation of {@link Ext.state.Provider} which overrides the
+     * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
+     * methods to save and recall name/value pairs. A built-in implementation,
+     * {@link Ext.state.CookieProvider} is available.</p>
+     * <p>To set the state provider for the current page:</p>
+     * <pre><code>
+Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
+    expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
+}));
+     * </code></pre>
+     * <p>A stateful object attempts to save state when one of the events
+     * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
+     * <p>To save state, a stateful object first serializes its state by
+     * calling <b><code>{@link #getState}</code></b>. By default, this function does
+     * nothing. The developer must provide an implementation which returns an
+     * object hash which represents the restorable state of the object.</p>
+     * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
+     * which uses the configured {@link Ext.state.Provider} to save the object
+     * keyed by the <code>{@link #stateId}</code>.</p>
+     * <p>During construction, a stateful object attempts to <i>restore</i>
+     * its state by calling {@link Ext.state.Manager#get} passing the
+     * <code>{@link #stateId}</code></p>
+     * <p>The resulting object is passed to <b><code>{@link #applyState}</code></b>.
+     * The default implementation of <code>{@link #applyState}</code> simply copies
+     * properties into the object, but a developer may override this to support
+     * more behaviour.</p>
+     * <p>You can perform extra processing on state save and restore by attaching
+     * handlers to the {@link #beforestaterestore}, {@link #staterestore},
+     * {@link #beforestatesave} and {@link #statesave} events.</p>
+     */
+    stateful: true,
 
-        me.initialConfig = {};
+    /**
+     * @cfg {String} stateId
+     * The unique id for this object to use for state management purposes.
+     * <p>See {@link #stateful} for an explanation of saving and restoring state.</p>
+     */
 
-        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);
-                }
-            }
-            html = buffer.join('');
-        } else {
-            if (Ext.isArray(html)) {
-                buffer.push(html.join(''));
-            } else {
-                buffer.push(html);
-            }
+    /**
+     * @cfg {String[]} stateEvents
+     * <p>An array of events that, when fired, should trigger this object to
+     * save its state. Defaults to none. <code>stateEvents</code> may be any type
+     * of event supported by this object, including browser or custom events
+     * (e.g., <tt>['click', 'customerchange']</tt>).</p>
+     * <p>See <code>{@link #stateful}</code> for an explanation of saving and
+     * restoring object state.</p>
+     */
+
+    /**
+     * @cfg {Number} saveDelay
+     * A buffer to be applied if many state events are fired within a short period.
+     */
+    saveDelay: 100,
+
+    autoGenIdRe: /^((\w+-)|(ext-comp-))\d{4,}$/i,
+
+    constructor: function(config) {
+        var me = this;
+
+        config = config || {};
+        if (Ext.isDefined(config.stateful)) {
+            me.stateful = config.stateful;
+        }
+        if (Ext.isDefined(config.saveDelay)) {
+            me.saveDelay = config.saveDelay;
         }
+        me.stateId = me.stateId || config.stateId;
 
-        // @private
-        me.html = buffer.join('');
+        if (!me.stateEvents) {
+            me.stateEvents = [];
+        }
+        if (config.stateEvents) {
+            me.stateEvents.concat(config.stateEvents);
+        }
+        this.addEvents(
+            /**
+             * @event beforestaterestore
+             * Fires before the state of the object is restored. Return false from an event handler to stop the restore.
+             * @param {Ext.state.Stateful} this
+             * @param {Object} state The hash of state values returned from the StateProvider. If this
+             * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
+             * that simply copies property values into this object. The method maybe overriden to
+             * provide custom state restoration.
+             */
+            'beforestaterestore',
 
-        if (me.compiled) {
-            me.compile();
+            /**
+             * @event staterestore
+             * Fires after the state of the object is restored.
+             * @param {Ext.state.Stateful} this
+             * @param {Object} state The hash of state values returned from the StateProvider. This is passed
+             * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
+             * object. The method maybe overriden to provide custom state restoration.
+             */
+            'staterestore',
+
+            /**
+             * @event beforestatesave
+             * Fires before the state of the object is saved to the configured state provider. Return false to stop the save.
+             * @param {Ext.state.Stateful} this
+             * @param {Object} state The hash of state values. This is determined by calling
+             * <b><tt>getState()</tt></b> on the object. This method must be provided by the
+             * developer to return whetever representation of state is required, by default, Ext.state.Stateful
+             * has a null implementation.
+             */
+            'beforestatesave',
+
+            /**
+             * @event statesave
+             * Fires after the state of the object is saved to the configured state provider.
+             * @param {Ext.state.Stateful} this
+             * @param {Object} state The hash of state values. This is determined by calling
+             * <b><tt>getState()</tt></b> on the object. This method must be provided by the
+             * developer to return whetever representation of state is required, by default, Ext.state.Stateful
+             * has a null implementation.
+             */
+            'statesave'
+        );
+        me.mixins.observable.constructor.call(me);
+        if (me.stateful !== false) {
+            me.initStateEvents();
+            me.initState();
         }
     },
-    isTemplate: true,
+
     /**
-     * @cfg {Boolean} disableFormats true to disable format functions in the template. If the template doesn't contain format functions, setting
-     * disableFormats to true will reduce apply time (defaults to false)
+     * Initializes any state events for this object.
+     * @private
      */
-    disableFormats: false,
+    initStateEvents: function() {
+        this.addStateEvents(this.stateEvents);
+    },
 
-    re: /\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
     /**
-     * Returns an HTML fragment of this template with the specified values applied.
-     * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
-     * @return {String} The HTML fragment
+     * Add events that will trigger the state to be saved.
+     * @param {String/String[]} events The event name or an array of event names.
      */
-    applyTemplate: function(values) {
+    addStateEvents: function(events){
+        if (!Ext.isArray(events)) {
+            events = [events];
+        }
+
         var me = this,
-            useFormat = me.disableFormats !== true,
-            fm = Ext.util.Format,
-            tpl = me;
+            i = 0,
+            len = events.length;
 
-        if (me.compiled) {
-            return me.compiled(values);
-        }
-        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] : "";
-            }
+        for (; i < len; ++i) {
+            me.on(events[i], me.onStateChange, me);
         }
-        return me.html.replace(me.re, fn);
     },
 
     /**
-     * Sets the HTML used as the template and optionally compiles it.
-     * @param {String} html
-     * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
-     * @return {Ext.Template} this
+     * This method is called when any of the {@link #stateEvents} are fired.
+     * @private
      */
-    set: function(html, compile) {
-        var me = this;
-        me.html = html;
-        me.compiled = null;
-        return compile ? me.compile() : me;
+    onStateChange: function(){
+        var me = this,
+            delay = me.saveDelay;
+
+        if (delay > 0) {
+            if (!me.stateTask) {
+                me.stateTask = Ext.create('Ext.util.DelayedTask', me.saveState, me);
+            }
+            me.stateTask.delay(me.saveDelay);
+        } else {
+            me.saveState();
+        }
     },
 
-    compileARe: /\\/g,
-    compileBRe: /(\r\n|\n)/g,
-    compileCRe: /'/g,
     /**
-     * Compiles the template into an internal function, eliminating the RegEx overhead.
-     * @return {Ext.Template} this
+     * Saves the state of the object to the persistence store.
+     * @private
      */
-    compile: function() {
+    saveState: function() {
         var me = this,
-            fm = Ext.util.Format,
-            useFormat = me.disableFormats !== true,
-            body, bodyReturn;
+            id,
+            state;
 
-        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) + '(';
+        if (me.stateful !== false) {
+            id = me.getStateId();
+            if (id) {
+                state = me.getState();
+                if (me.fireEvent('beforestatesave', me, state) !== false) {
+                    Ext.state.Manager.set(id, state);
+                    me.fireEvent('statesave', me, state);
                 }
             }
-            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 + "'].join('');};";
-        eval(body);
-        return me;
+    /**
+     * Gets the current state of the object. By default this function returns null,
+     * it should be overridden in subclasses to implement methods for getting the state.
+     * @return {Object} The current state
+     */
+    getState: function(){
+        return null;
     },
 
     /**
-     * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
-     * @param {Mixed} el The context element
-     * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
-     * @param {Boolean} returnElement (optional) true to return a Ext.core.Element (defaults to undefined)
-     * @return {HTMLElement/Ext.core.Element} The new node or Element
+     * Applies the state to the object. This should be overridden in subclasses to do
+     * more complex state operations. By default it applies the state properties onto
+     * the current object.
+     * @param {Object} state The state
      */
-    insertFirst: function(el, values, returnElement) {
-        return this.doInsert('afterBegin', el, values, returnElement);
+    applyState: function(state) {
+        if (state) {
+            Ext.apply(this, state);
+        }
     },
 
     /**
-     * Applies the supplied values to the template and inserts the new node(s) before el.
-     * @param {Mixed} el The context element
-     * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
-     * @param {Boolean} returnElement (optional) true to return a Ext.core.Element (defaults to undefined)
-     * @return {HTMLElement/Ext.core.Element} The new node or Element
+     * Gets the state id for this object.
+     * @return {String} The state id, null if not found.
      */
-    insertBefore: function(el, values, returnElement) {
-        return this.doInsert('beforeBegin', el, values, returnElement);
+    getStateId: function() {
+        var me = this,
+            id = me.stateId;
+
+        if (!id) {
+            id = me.autoGenIdRe.test(String(me.id)) ? null : me.id;
+        }
+        return id;
     },
 
     /**
-     * Applies the supplied values to the template and inserts the new node(s) after el.
-     * @param {Mixed} el The context element
-     * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
-     * @param {Boolean} returnElement (optional) true to return a Ext.core.Element (defaults to undefined)
-     * @return {HTMLElement/Ext.core.Element} The new node or Element
+     * Initializes the state of the object upon construction.
+     * @private
      */
-    insertAfter: function(el, values, returnElement) {
-        return this.doInsert('afterEnd', el, values, returnElement);
+    initState: function(){
+        var me = this,
+            id = me.getStateId(),
+            state;
+
+        if (me.stateful !== false) {
+            if (id) {
+                state = Ext.state.Manager.get(id);
+                if (state) {
+                    state = Ext.apply({}, state);
+                    if (me.fireEvent('beforestaterestore', me, state) !== false) {
+                        me.applyState(state);
+                        me.fireEvent('staterestore', me, state);
+                    }
+                }
+            }
+        }
     },
 
     /**
-     * Applies the supplied <code>values</code> to the template and appends
-     * the new node(s) to the specified <code>el</code>.
-     * <p>For example usage {@link #Template see the constructor}.</p>
-     * @param {Mixed} el The context element
-     * @param {Object/Array} values
-     * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
-     * or an object (i.e. <code>{foo: 'bar'}</code>).
-     * @param {Boolean} returnElement (optional) true to return an Ext.core.Element (defaults to undefined)
-     * @return {HTMLElement/Ext.core.Element} The new node or Element
+     * Conditionally saves a single property from this object to the given state object.
+     * The idea is to only save state which has changed from the initial state so that
+     * current software settings do not override future software settings. Only those
+     * values that are user-changed state should be saved.
+     *
+     * @param {String} propName The name of the property to save.
+     * @param {Object} state The state object in to which to save the property.
+     * @param {String} stateName (optional) The name to use for the property in state.
+     * @return {Boolean} True if the property was saved, false if not.
      */
-    append: function(el, values, returnElement) {
-        return this.doInsert('beforeEnd', el, values, returnElement);
+    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;
     },
 
-    doInsert: function(where, el, values, returnEl) {
-        el = Ext.getDom(el);
-        var newNode = Ext.core.DomHelper.insertHtml(where, el, this.applyTemplate(values));
-        return returnEl ? Ext.get(newNode, true) : newNode;
+    savePropsToState: function (propNames, state) {
+        var me = this;
+        Ext.each(propNames, function (propName) {
+            me.savePropToState(propName, state);
+        });
+        return state;
     },
 
     /**
-     * Applies the supplied values to the template and overwrites the content of el with the new node(s).
-     * @param {Mixed} el The context element
-     * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
-     * @param {Boolean} returnElement (optional) true to return a Ext.core.Element (defaults to undefined)
-     * @return {HTMLElement/Ext.core.Element} The new node or Element
+     * Destroys this stateful object.
      */
-    overwrite: function(el, values, returnElement) {
-        el = Ext.getDom(el);
-        el.innerHTML = this.applyTemplate(values);
-        return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
+    destroy: function(){
+        var task = this.stateTask;
+        if (task) {
+            task.cancel();
+        }
+        this.clearListeners();
+
     }
-}, function() {
 
-    /**
-     * Alias for {@link #applyTemplate}
-     * Returns an HTML fragment of this template with the specified <code>values</code> applied.
-     * @param {Object/Array} values
-     * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
-     * or an object (i.e. <code>{foo: 'bar'}</code>).
-     * @return {String} The HTML fragment
-     * @member Ext.Template
-     * @method apply
-     */
-    this.createAlias('apply', 'applyTemplate');
 });
 
 /**
- * @class Ext.ComponentQuery
- * @extends Object
- * @singleton
- *
- * Provides searching of Components within Ext.ComponentManager (globally) or a specific
- * Ext.container.Container on the document with a similar syntax to a CSS selector.
- *
- * Components can be retrieved by using their {@link Ext.Component xtype} with an optional . prefix
- *
- * - `component` or `.component`
- * - `gridpanel` or `.gridpanel`
- *
- * An itemId or id must be prefixed with a #
- *
- * - `#myContainer`
- *
- * Attributes must be wrapped in brackets
- *
- * - `component[autoScroll]`
- * - `panel[title="Test"]`
- *
- * Member expressions from candidate Components may be tested. If the expression returns a *truthy* value,
- * the candidate Component will be included in the query:
- *
- *     var disabledFields = myFormPanel.query("{isDisabled()}");
- *
- * Pseudo classes may be used to filter results in the same way as in {@link Ext.DomQuery DomQuery}:
- *
- *     // Function receives array and returns a filtered array.
- *     Ext.ComponentQuery.pseudos.invalid = function(items) {
- *         var i = 0, l = items.length, c, result = [];
- *         for (; i < l; i++) {
- *             if (!(c = items[i]).isValid()) {
- *                 result.push(c);
- *             }
- *         }
- *         return result;
- *     };
- *      
- *     var invalidFields = myFormPanel.query('field:invalid');
- *     if (invalidFields.length) {
- *         invalidFields[0].getEl().scrollIntoView(myFormPanel.body);
- *         for (var i = 0, l = invalidFields.length; i < l; i++) {
- *             invalidFields[i].getEl().frame("red");
- *         }
- *     }
- *
- * Default pseudos include:
- *
- * - not
- *
- * Queries return an array of components.
- * Here are some example queries.
- *
- *     // retrieve all Ext.Panels in the document by xtype
- *     var panelsArray = Ext.ComponentQuery.query('panel');
- *
- *     // retrieve all Ext.Panels within the container with an id myCt
- *     var panelsWithinmyCt = Ext.ComponentQuery.query('#myCt panel');
- *
- *     // retrieve all direct children which are Ext.Panels within myCt
- *     var directChildPanel = Ext.ComponentQuery.query('#myCt > panel');
- *
- *     // retrieve all grids and trees
- *     var gridsAndTrees = Ext.ComponentQuery.query('gridpanel, treepanel');
- *
- * For easy access to queries based from a particular Container see the {@link Ext.container.Container#query},
- * {@link Ext.container.Container#down} and {@link Ext.container.Container#child} methods. Also see
- * {@link Ext.Component#up}.
+ * Base Manager class
  */
-Ext.define('Ext.ComponentQuery', {
-    singleton: true,
-    uses: ['Ext.ComponentManager']
-}, function() {
+Ext.define('Ext.AbstractManager', {
 
-    var cq = this,
+    /* Begin Definitions */
 
-        // A function source code pattern with a placeholder which accepts an expression which yields a truth value when applied
-        // as a member on each item in the passed array.
-        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(''),
+    requires: ['Ext.util.HashMap'],
 
-        filterItems = function(items, operation) {
-            // Argument list for the operation is [ itemsArray, operationArg1, operationArg2...]
-            // The operation's method loops over each item in the candidate array and
-            // returns an array of items which match its criteria
-            return operation.method.apply(this, [ items ].concat(operation.args));
-        },
+    /* End Definitions */
 
-        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;
-        },
+    typeName: 'type',
 
-        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;
-        },
-
-        // Filters the passed candidate array and returns only items which match the passed xtype
-        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;
-            }
-        },
-
-        // Filters the passed candidate array and returns only items which have the passed className
-        filterByClassName = function(items, className) {
-            var EA = Ext.Array,
-                result = [],
-                i = 0,
-                length = items.length,
-                candidate;
-            for (; i < length; i++) {
-                candidate = items[i];
-                if (candidate.el ? candidate.el.hasCls(className) : EA.contains(candidate.initCls(), className)) {
-                    result.push(candidate);
-                }
-            }
-            return result;
-        },
-
-        // Filters the passed candidate array and returns only items which have the specified property match
-        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;
-        },
-
-        // Filters the passed candidate array and returns only items which have the specified itemId or id
-        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;
-        },
-
-        // Filters the passed candidate array and returns only items which the named pseudo class matcher filters in
-        filterByPseudo = function(items, name, value) {
-            return cq.pseudos[name](items, value);
-        },
-
-        // Determines leading mode
-        // > for direct child, and ^ to switch to ownerCt axis
-        modeRe = /^(\s?([>\^])\s?|\s|$)/,
-
-        // Matches a token with possibly (true|false) appended for the "shallow" parameter
-        tokenRe = /^(#)?([\w\-]+|\*)(?:\((true|false)\))?/,
-
-        matchers = [{
-            // Checks for .xtype with possibly (true|false) appended for the "shallow" parameter
-            re: /^\.([\w\-]+)(?:\((true|false)\))?/,
-            method: filterByXType
-        },{
-            // checks for [attribute=value]
-            re: /^(?:[\[](?:@)?([\w\-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]])/,
-            method: filterByAttribute
-        }, {
-            // checks for #cmpItemId
-            re: /^#([\w\-]+)/,
-            method: filterById
-        }, {
-            // checks for :<pseudo_class>(<selector>)
-            re: /^\:([\w\-]+)(?:\(((?:\{[^\}]+\})|(?:(?!\{)[^\s>\/]*?(?!\})))\))?/,
-            method: filterByPseudo
-        }, {
-            // checks for {<member_expression>}
-            re: /^(?:\{([^\}]+)\})/,
-            method: filterFnPattern
-        }];
-
-    /**
-     * @class Ext.ComponentQuery.Query
-     * @extends Object
-     * @private
-     */
-    cq.Query = Ext.extend(Object, {
-        constructor: function(cfg) {
-            cfg = cfg || {};
-            Ext.apply(this, cfg);
-        },
-
-        /**
-         * @private
-         * Executes this Query upon the selected root.
-         * The root provides the initial source of candidate Component matches which are progressively
-         * filtered by iterating through this Query's operations cache.
-         * If no root is provided, all registered Components are searched via the ComponentManager.
-         * root may be a Container who's descendant Components are filtered
-         * root may be a Component with an implementation of getRefItems which provides some nested Components such as the
-         * docked items within a Panel.
-         * root may be an array of candidate Components to filter using this Query.
-         */
-        execute : function(root) {
-            var operations = this.operations,
-                i = 0,
-                length = operations.length,
-                operation,
-                workingItems;
-
-            // no root, use all Components in the document
-            if (!root) {
-                workingItems = Ext.ComponentManager.all.getArray();
-            }
-            // Root is a candidate Array
-            else if (Ext.isArray(root)) {
-                workingItems = root;
-            }
-
-            // We are going to loop over our operations and take care of them
-            // one by one.
-            for (; i < length; i++) {
-                operation = operations[i];
-
-                // The mode operation requires some custom handling.
-                // All other operations essentially filter down our current
-                // working items, while mode replaces our current working
-                // items by getting children from each one of our current
-                // working items. The type of mode determines the type of
-                // children we get. (e.g. > only gets direct children)
-                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 this is the last operation, it means our current working
-                // items are the final matched items. Thus return them!
-                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, {
-
-        // private cache of selectors and matching ComponentQuery.Query objects
-        cache: {},
-
-        // private cache of pseudo class filter functions
-        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;
-            }
-        },
-
-        /**
-         * Returns an array of matched Components from within the passed root object.
-         *
-         * This method filters returned Components in a similar way to how CSS selector based DOM
-         * queries work using a textual selector string.
-         *
-         * See class summary for details.
-         *
-         * @param {String} selector The selector string to filter returned Components
-         * @param {Ext.container.Container} root The Container within which to perform the query.
-         * If omitted, all Components within the document are included in the search.
-         * 
-         * This parameter may also be an array of Components to filter according to the selector.</p>
-         * @returns {[Ext.Component]} The matched Components.
-         * 
-         * @member Ext.ComponentQuery
-         */
-        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];
-                if (!query) {
-                    this.cache[selector] = query = this.parse(selector);
-                }
-                results = results.concat(query.execute(root));
-            }
-
-            // multiple selectors, potential to find duplicates
-            // lets filter them out.
-            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;
-        },
+    constructor: function(config) {
+        Ext.apply(this, config || {});
 
         /**
-         * Tests whether the passed Component matches the selector string.
-         * @param {Ext.Component} component The Component to test
-         * @param {String} selector The selector string to test against.
-         * @return {Boolean} True if the Component matches the selector.
-         * @member Ext.ComponentQuery
+         * @property {Ext.util.HashMap} all
+         * Contains all of the items currently managed
          */
-        is: function(component, selector) {
-            if (!selector) {
-                return true;
-            }
-            var query = this.cache[selector];
-            if (!query) {
-                this.cache[selector] = query = this.parse(selector);
-            }
-            return query.is(component);
-        },
-
-        parse: function(selector) {
-            var operations = [],
-                length = matchers.length,
-                lastSelector,
-                tokenMatch,
-                matchedChar,
-                modeMatch,
-                selectorMatch,
-                i, matcher, method;
-
-            // We are going to parse the beginning of the selector over and
-            // over again, slicing off the selector any portions we converted into an
-            // operation, until it is an empty string.
-            while (selector && lastSelector !== selector) {
-                lastSelector = selector;
-
-                // First we check if we are dealing with a token like #, * or an xtype
-                tokenMatch = selector.match(tokenRe);
-
-                if (tokenMatch) {
-                    matchedChar = tokenMatch[1];
-
-                    // If the token is prefixed with a # we push a filterById operation to our stack
-                    if (matchedChar === '#') {
-                        operations.push({
-                            method: filterById,
-                            args: [Ext.String.trim(tokenMatch[2])]
-                        });
-                    }
-                    // If the token is prefixed with a . we push a filterByClassName operation to our stack
-                    // FIXME: Not enabled yet. just needs \. adding to the tokenRe prefix
-                    else if (matchedChar === '.') {
-                        operations.push({
-                            method: filterByClassName,
-                            args: [Ext.String.trim(tokenMatch[2])]
-                        });
-                    }
-                    // If the token is a * or an xtype string, we push a filterByXType
-                    // operation to the stack.
-                    else {
-                        operations.push({
-                            method: filterByXType,
-                            args: [Ext.String.trim(tokenMatch[2]), Boolean(tokenMatch[3])]
-                        });
-                    }
-
-                    // Now we slice of the part we just converted into an operation
-                    selector = selector.replace(tokenMatch[0], '');
-                }
-
-                // If the next part of the query is not a space or > or ^, it means we
-                // are going to check for more things that our current selection
-                // has to comply to.
-                while (!(modeMatch = selector.match(modeRe))) {
-                    // Lets loop over each type of matcher and execute it
-                    // on our current selector.
-                    for (i = 0; selector && i < length; i++) {
-                        matcher = matchers[i];
-                        selectorMatch = selector.match(matcher.re);
-                        method = matcher.method;
-
-                        // If we have a match, add an operation with the method
-                        // associated with this matcher, and pass the regular
-                        // expression matches are arguments to the operation.
-                        if (selectorMatch) {
-                            operations.push({
-                                method: Ext.isString(matcher.method)
-                                    // Turn a string method into a function by formatting the string with our selector matche expression
-                                    // A new method is created for different match expressions, eg {id=='textfield-1024'}
-                                    // Every expression may be different in different selectors.
-                                    ? 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; // Break on match
-                        }
-                        //<debug>
-                        // Exhausted all matches: It's an error
-                        if (i === (length - 1)) {
-                            Ext.Error.raise('Invalid ComponentQuery selector: "' + arguments[0] + '"');
-                        }
-                        //</debug>
-                    }
-                }
-
-                // Now we are going to check for a mode change. This means a space
-                // or a > to determine if we are going to select all the children
-                // of the currently matched items, or a ^ if we are going to use the
-                // ownerCt axis as the candidate source.
-                if (modeMatch[1]) { // Assignment, and test for truthiness!
-                    operations.push({
-                        mode: modeMatch[2]||modeMatch[1]
-                    });
-                    selector = selector.replace(modeMatch[0], '');
-                }
-            }
-
-            //  Now that we have all our operations in an array, we are going
-            // to create a new Query using these operations.
-            return new cq.Query({
-                operations: operations
-            });
-        }
-    });
-});
-/**
- * @class Ext.util.Filter
- * @extends Object
- * <p>Represents a filter that can be applied to a {@link Ext.util.MixedCollection MixedCollection}. Can either simply
- * filter on a property/value pair or pass in a filter function with custom logic. Filters are always used in the context
- * of MixedCollections, though {@link Ext.data.Store Store}s frequently create them when filtering and searching on their
- * records. Example usage:</p>
-<pre><code>
-//set up a fictional MixedCollection containing a few people to filter on
-var allNames = new Ext.util.MixedCollection();
-allNames.addAll([
-    {id: 1, name: 'Ed',    age: 25},
-    {id: 2, name: 'Jamie', age: 37},
-    {id: 3, name: 'Abe',   age: 32},
-    {id: 4, name: 'Aaron', age: 26},
-    {id: 5, name: 'David', age: 32}
-]);
-
-var ageFilter = new Ext.util.Filter({
-    property: 'age',
-    value   : 32
-});
-
-var longNameFilter = new Ext.util.Filter({
-    filterFn: function(item) {
-        return item.name.length > 4;
-    }
-});
-
-//a new MixedCollection with the 3 names longer than 4 characters
-var longNames = allNames.filter(longNameFilter);
-
-//a new MixedCollection with the 2 people of age 24:
-var youngFolk = allNames.filter(ageFilter);
-</code></pre>
- */
-Ext.define('Ext.util.Filter', {
+        this.all = Ext.create('Ext.util.HashMap');
 
-    /* Begin Definitions */
+        this.types = {};
+    },
 
-    /* End Definitions */
-    /**
-     * @cfg {String} property The property to filter on. Required unless a {@link #filterFn} is passed
-     */
-    
     /**
-     * @cfg {Function} filterFn A custom filter function which is passed each item in the {@link Ext.util.MixedCollection} 
-     * in turn. Should return true to accept each item or false to reject it
+     * Returns an item by id.
+     * For additional details see {@link Ext.util.HashMap#get}.
+     * @param {String} id The id of the item
+     * @return {Object} The item, undefined if not found.
      */
-    
+    get : function(id) {
+        return this.all.get(id);
+    },
+
     /**
-     * @cfg {Boolean} anyMatch True to allow any match - no regex start/end line anchors will be added. Defaults to false
+     * Registers an item to be managed
+     * @param {Object} item The item to register
      */
-    anyMatch: false,
-    
+    register: function(item) {
+        //<debug>
+        var all = this.all,
+            key = all.getKey(item);
+            
+        if (all.containsKey(key)) {
+            Ext.Error.raise('Registering duplicate id "' + key + '" with this manager');
+        }
+        //</debug>
+        this.all.add(item);
+    },
+
     /**
-     * @cfg {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false.
-     * Ignored if anyMatch is true.
+     * Unregisters an item by removing it from this manager
+     * @param {Object} item The item to unregister
      */
-    exactMatch: false,
-    
+    unregister: function(item) {
+        this.all.remove(item);
+    },
+
     /**
-     * @cfg {Boolean} caseSensitive True to make the regex case sensitive (adds 'i' switch to regex). Defaults to false.
+     * Registers a new item constructor, keyed by a type key.
+     * @param {String} type The mnemonic string by which the class may be looked up.
+     * @param {Function} cls The new instance class.
      */
-    caseSensitive: false,
-    
+    registerType : function(type, cls) {
+        this.types[type] = cls;
+        cls[this.typeName] = type;
+    },
+
     /**
-     * @cfg {String} root Optional root property. This is mostly useful when filtering a Store, in which case we set the
-     * root to 'data' to make the filter pull the {@link #property} out of the data object of each item
+     * Checks if an item type is registered.
+     * @param {String} type The mnemonic string by which the class may be looked up
+     * @return {Boolean} Whether the type is registered.
      */
+    isRegistered : function(type){
+        return this.types[type] !== undefined;
+    },
 
     /**
-     * Creates new Filter.
-     * @param {Object} config (optional) Config object
+     * Creates and returns an instance of whatever this manager manages, based on the supplied type and
+     * config object.
+     * @param {Object} config The config object
+     * @param {String} defaultType If no type is discovered in the config object, we fall back to this type
+     * @return {Object} The instance of whatever this manager is managing
      */
-    constructor: function(config) {
-        Ext.apply(this, config);
-        
-        //we're aliasing filter to filterFn mostly for API cleanliness reasons, despite the fact it dirties the code here.
-        //Ext.util.Sorter takes a sorterFn property but allows .sort to be called - we do the same here
-        this.filter = this.filter || this.filterFn;
-        
-        if (this.filter == undefined) {
-            if (this.property == undefined || this.value == undefined) {
-                // Commented this out temporarily because it stops us using string ids in models. TODO: Remove this once
-                // Model has been updated to allow string ids
-                
-                // Ext.Error.raise("A Filter requires either a property or a filterFn to be set");
-            } else {
-                this.filter = this.createFilterFn();
-            }
-            
-            this.filterFn = this.filter;
+    create: function(config, defaultType) {
+        var type        = config[this.typeName] || config.type || defaultType,
+            Constructor = this.types[type];
+
+        //<debug>
+        if (Constructor === undefined) {
+            Ext.Error.raise("The '" + type + "' type has not been registered with this manager");
         }
+        //</debug>
+
+        return new Constructor(config);
     },
-    
+
     /**
-     * @private
-     * Creates a filter function for the configured property/value/anyMatch/caseSensitive options for this Filter
+     * Registers a function that will be called when an item with the specified id is added to the manager.
+     * This will happen on instantiation.
+     * @param {String} id The item id
+     * @param {Function} fn The callback function. Called with a single parameter, the item.
+     * @param {Object} scope The scope (this reference) in which the callback is executed.
+     * Defaults to the item.
      */
-    createFilterFn: function() {
-        var me       = this,
-            matcher  = me.createValueMatcher(),
-            property = me.property;
+    onAvailable : function(id, fn, scope){
+        var all = this.all,
+            item;
         
-        return function(item) {
-            return matcher.test(me.getRoot.call(me, item)[property]);
-        };
+        if (all.containsKey(id)) {
+            item = all.get(id);
+            fn.call(scope || item, item);
+        } else {
+            all.on('add', function(map, key, item){
+                if (key == id) {
+                    fn.call(scope || item, item);
+                    all.un('add', fn, scope);
+                }
+            });
+        }
     },
     
     /**
-     * @private
-     * Returns the root property of the given item, based on the configured {@link #root} property
-     * @param {Object} item The item
-     * @return {Object} The root property of the object
+     * Executes the specified function once for each item in the collection.
+     * @param {Function} fn The function to execute.
+     * @param {String} fn.key The key of the item
+     * @param {Number} fn.value The value of the item
+     * @param {Number} fn.length The total number of items in the collection
+     * @param {Boolean} fn.return False to cease iteration.
+     * @param {Object} scope The scope to execute in. Defaults to `this`.
      */
-    getRoot: function(item) {
-        return this.root == undefined ? item : item[this.root];
+    each: function(fn, scope){
+        this.all.each(fn, scope || this);    
     },
     
     /**
-     * @private
-     * Returns a regular expression based on the given value and matching options
+     * Gets the number of items in the collection.
+     * @return {Number} The number of items in the collection.
      */
-    createValueMatcher : function() {
-        var me            = this,
-            value         = me.value,
-            anyMatch      = me.anyMatch,
-            exactMatch    = me.exactMatch,
-            caseSensitive = me.caseSensitive,
-            escapeRe      = Ext.String.escapeRegex;
-        
-        if (!value.exec) { // not a regex
-            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;
+    getCount: function(){
+        return this.all.getCount();
     }
 });
-/**
- * @class Ext.util.Sorter
- * @extends Object
-
-Represents a single sorter that can be applied to a Store. The sorter is used
-to compare two values against each other for the purpose of ordering them. Ordering
-is achieved by specifying either:
-- {@link #property A sorting property}
-- {@link #sorterFn A sorting function} 
-
-As a contrived example, we can specify a custom sorter that sorts by rank:
 
-    Ext.define('Person', {
-        extend: 'Ext.data.Model',
-        fields: ['name', 'rank']
-    });
-
-    Ext.create('Ext.data.Store', {
-        model: 'Person',
-        proxy: 'memory',
-        sorters: [{
-            sorterFn: function(o1, o2){
-                var getRank = function(o){
-                    var name = o.get('rank');
-                    if (name === 'first') {
-                        return 1;
-                    } else if (name === 'second') {
-                        return 2;
-                    } else {
-                        return 3;
-                    }
-                },
-                rank1 = getRank(o1),
-                rank2 = getRank(o2);
-                
-                if (rank1 === rank2) {
-                    return 0;
-                }
-                
-                return rank1 < rank2 ? -1 : 1;
-            }
-        }],
-        data: [{
-            name: 'Person1',
-            rank: 'second'
-        }, {
-            name: 'Person2',
-            rank: 'third'
-        }, {
-            name: 'Person3',
-            rank: 'first'
-        }] 
-    });
-
- * @markdown
+/**
+ * @class Ext.ComponentManager
+ * @extends Ext.AbstractManager
+ * <p>Provides a registry of all Components (instances of {@link Ext.Component} or any subclass
+ * thereof) on a page so that they can be easily accessed by {@link Ext.Component component}
+ * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).</p>
+ * <p>This object also provides a registry of available Component <i>classes</i>
+ * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}.
+ * The <code>xtype</code> provides a way to avoid instantiating child Components
+ * when creating a full, nested config object for a complete Ext page.</p>
+ * <p>A child Component may be specified simply as a <i>config object</i>
+ * as long as the correct <code>{@link Ext.Component#xtype xtype}</code> is specified so that if and when the Component
+ * needs rendering, the correct type can be looked up for lazy instantiation.</p>
+ * <p>For a list of all available <code>{@link Ext.Component#xtype xtypes}</code>, see {@link Ext.Component}.</p>
+ * @singleton
  */
-Ext.define('Ext.util.Sorter', {
-
-    /**
-     * @cfg {String} property The property to sort by. Required unless {@link #sorterFn} is provided.
-     * The property is extracted from the object directly and compared for sorting using the built in
-     * comparison operators.
-     */
-    
-    /**
-     * @cfg {Function} sorterFn A specific sorter function to execute. Can be passed instead of {@link #property}.
-     * This sorter function allows for any kind of custom/complex comparisons.
-     * The sorterFn receives two arguments, the objects being compared. The function should return:
-     * <ul>
-     * <li>-1 if o1 is "less than" o2</li>
-     * <li>0 if o1 is "equal" to o2</li>
-     * <li>1 if o1 is "greater than" o2</li>
-     * </ul>
-     */
+Ext.define('Ext.ComponentManager', {
+    extend: 'Ext.AbstractManager',
+    alternateClassName: 'Ext.ComponentMgr',
     
-    /**
-     * @cfg {String} root Optional root property. This is mostly useful when sorting a Store, in which case we set the
-     * root to 'data' to make the filter pull the {@link #property} out of the data object of each item
-     */
+    singleton: true,
     
-    /**
-     * @cfg {Function} transform A function that will be run on each value before
-     * it is compared in the sorter. The function will receive a single argument,
-     * the value.
-     */
+    typeName: 'xtype',
     
     /**
-     * @cfg {String} direction The direction to sort by. Defaults to ASC
+     * Creates a new Component from the specified config object using the
+     * config object's xtype to determine the class to instantiate.
+     * @param {Object} config A configuration object for the Component you wish to create.
+     * @param {Function} defaultType (optional) The constructor to provide the default Component type if
+     * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
+     * @return {Ext.Component} The newly instantiated Component.
      */
-    direction: "ASC",
-    
-    constructor: function(config) {
-        var me = this;
-        
-        Ext.apply(me, config);
-        
-        //<debug>
-        if (me.property === undefined && me.sorterFn === undefined) {
-            Ext.Error.raise("A Sorter requires either a property or a sorter function");
+    create: function(component, defaultType){
+        if (component instanceof Ext.AbstractComponent) {
+            return component;
         }
-        //</debug>
-        
-        me.updateSortFunction();
-    },
-    
-    /**
-     * @private
-     * Creates and returns a function which sorts an array by the given property and direction
-     * @return {Function} A function which sorts by the property/direction combination provided
-     */
-    createSortFunction: function(sorterFn) {
-        var me        = this,
-            property  = me.property,
-            direction = me.direction || "ASC",
-            modifier  = direction.toUpperCase() == "DESC" ? -1 : 1;
-        
-        //create a comparison function. Takes 2 objects, returns 1 if object 1 is greater,
-        //-1 if object 2 is greater or 0 if they are equal
-        return function(o1, o2) {
-            return modifier * sorterFn.call(me, o1, o2);
-        };
-    },
-    
-    /**
-     * @private
-     * Basic default sorter function that just compares the defined property of each object
-     */
-    defaultSorterFn: function(o1, o2) {
-        var me = this,
-            transform = me.transform,
-            v1 = me.getRoot(o1)[me.property],
-            v2 = me.getRoot(o2)[me.property];
+        else if (Ext.isString(component)) {
+            return Ext.createByAlias('widget.' + component);
+        }
+        else {
+            var type = component.xtype || defaultType,
+                config = component;
             
-        if (transform) {
-            v1 = transform(v1);
-            v2 = transform(v2);
+            return Ext.createByAlias('widget.' + type, config);
         }
-
-        return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
-    },
-    
-    /**
-     * @private
-     * Returns the root property of the given item, based on the configured {@link #root} property
-     * @param {Object} item The item
-     * @return {Object} The root property of the object
-     */
-    getRoot: function(item) {
-        return this.root === undefined ? item : item[this.root];
-    },
-    
-    /**
-     * Set the sorting direction for this sorter.
-     * @param {String} direction The direction to sort in. Should be either 'ASC' or 'DESC'.
-     */
-    setDirection: function(direction) {
-        var me = this;
-        me.direction = direction;
-        me.updateSortFunction();
-    },
-    
-    /**
-     * Toggles the sorting direction for this sorter.
-     */
-    toggle: function() {
-        var me = this;
-        me.direction = Ext.String.toggle(me.direction, "ASC", "DESC");
-        me.updateSortFunction();
     },
-    
-    /**
-     * Update the sort function for this sorter.
-     * @param {Function} fn (Optional) A new sorter function for this sorter. If not specified it will use the
-     * default sorting function.
-     */
-    updateSortFunction: function(fn) {
-        var me = this;
-        fn = fn || me.sorterFn || me.defaultSorterFn;
-        me.sort = me.createSortFunction(fn);
+
+    registerType: function(type, cls) {
+        this.types[type] = cls;
+        cls[this.typeName] = type;
+        cls.prototype[this.typeName] = type;
     }
 });
 /**
- * @class Ext.ElementLoader
- * A class used to load remote content to an Element. Sample usage:
- * <pre><code>
-Ext.get('el').load({
-    url: 'myPage.php',
-    scripts: true,
-    params: {
-        id: 1
-    }
-});
- * </code></pre>
- * <p>
- * In general this class will not be instanced directly, rather the {@link Ext.core.Element#load} method
- * will be used.
- * </p>
+ * An abstract base class which provides shared methods for Components across the Sencha product line.
+ *
+ * Please refer to sub class's documentation
+ * @private
  */
-Ext.define('Ext.ElementLoader', {
+Ext.define('Ext.AbstractComponent', {
 
     /* Begin Definitions */
+    requires: [
+        'Ext.ComponentQuery',
+        'Ext.ComponentManager'
+    ],
 
     mixins: {
-        observable: 'Ext.util.Observable'
+        observable: 'Ext.util.Observable',
+        animate: 'Ext.util.Animate',
+        state: 'Ext.state.Stateful'
     },
 
+    // The "uses" property specifies class which are used in an instantiated AbstractComponent.
+    // They do *not* have to be loaded before this class may be defined - that is what "requires" is for.
     uses: [
-        'Ext.data.Connection',
-        'Ext.Ajax'
+        'Ext.PluginManager',
+        'Ext.ComponentManager',
+        'Ext.Element',
+        'Ext.DomHelper',
+        'Ext.XTemplate',
+        'Ext.ComponentQuery',
+        'Ext.ComponentLoader',
+        'Ext.EventManager',
+        'Ext.layout.Layout',
+        'Ext.layout.component.Auto',
+        'Ext.LoadMask',
+        'Ext.ZIndexManager'
     ],
-    
+
     statics: {
-        Renderer: {
-            Html: function(loader, response, active){
-                loader.getTarget().update(response.responseText, active.scripts === true);
-                return true;
-            }
-        }     
+        AUTO_ID: 1000
     },
 
     /* End Definitions */
 
+    isComponent: true,
+
+    getAutoId: function() {
+        return ++Ext.AbstractComponent.AUTO_ID;
+    },
+
+
     /**
-     * @cfg {String} url The url to retrieve the content from. Defaults to <tt>null</tt>.
+     * @cfg {String} id
+     * The **unique id of this component instance.**
+     *
+     * It should not be necessary to use this configuration except for singleton objects in your application. Components
+     * created with an id may be accessed globally using {@link Ext#getCmp Ext.getCmp}.
+     *
+     * Instead of using assigned ids, use the {@link #itemId} config, and {@link Ext.ComponentQuery ComponentQuery}
+     * which provides selector-based searching for Sencha Components analogous to DOM querying. The {@link
+     * Ext.container.Container Container} class contains {@link Ext.container.Container#down shortcut methods} to query
+     * its descendant Components by selector.
+     *
+     * Note that this id will also be used as the element id for the containing HTML element that is rendered to the
+     * page for this component. This allows you to write id-based CSS rules to style the specific instance of this
+     * component uniquely, and also to select sub-elements using this component's id as the parent.
+     *
+     * **Note**: to avoid complications imposed by a unique id also see `{@link #itemId}`.
+     *
+     * **Note**: to access the container of a Component see `{@link #ownerCt}`.
+     *
+     * Defaults to an {@link #getId auto-assigned id}.
      */
-    url: null,
 
     /**
-     * @cfg {Object} params Any params to be attached to the Ajax request. These parameters will
-     * be overridden by any params in the load options. Defaults to <tt>null</tt>.
+     * @cfg {String} itemId
+     * An itemId can be used as an alternative way to get a reference to a component when no object reference is
+     * available. Instead of using an `{@link #id}` with {@link Ext}.{@link Ext#getCmp getCmp}, use `itemId` with
+     * {@link Ext.container.Container}.{@link Ext.container.Container#getComponent getComponent} which will retrieve
+     * `itemId`'s or {@link #id}'s. Since `itemId`'s are an index to the container's internal MixedCollection, the
+     * `itemId` is scoped locally to the container -- avoiding potential conflicts with {@link Ext.ComponentManager}
+     * which requires a **unique** `{@link #id}`.
+     *
+     *     var c = new Ext.panel.Panel({ //
+     *         {@link Ext.Component#height height}: 300,
+     *         {@link #renderTo}: document.body,
+     *         {@link Ext.container.Container#layout layout}: 'auto',
+     *         {@link Ext.container.Container#items items}: [
+     *             {
+     *                 itemId: 'p1',
+     *                 {@link Ext.panel.Panel#title title}: 'Panel 1',
+     *                 {@link Ext.Component#height height}: 150
+     *             },
+     *             {
+     *                 itemId: 'p2',
+     *                 {@link Ext.panel.Panel#title title}: 'Panel 2',
+     *                 {@link Ext.Component#height height}: 150
+     *             }
+     *         ]
+     *     })
+     *     p1 = c.{@link Ext.container.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
+     *     p2 = p1.{@link #ownerCt}.{@link Ext.container.Container#getComponent getComponent}('p2'); // reference via a sibling
+     *
+     * Also see {@link #id}, `{@link Ext.container.Container#query}`, `{@link Ext.container.Container#down}` and
+     * `{@link Ext.container.Container#child}`.
+     *
+     * **Note**: to access the container of an item see {@link #ownerCt}.
      */
-    params: null,
 
     /**
-     * @cfg {Object} baseParams Params that will be attached to every request. These parameters
-     * will not be overridden by any params in the load options. Defaults to <tt>null</tt>.
+     * @property {Ext.Container} ownerCt
+     * This Component's owner {@link Ext.container.Container Container} (is set automatically
+     * when this Component is added to a Container). Read-only.
+     *
+     * **Note**: to access items within the Container see {@link #itemId}.
      */
-    baseParams: null,
 
     /**
-     * @cfg {Boolean/Object} autoLoad True to have the loader make a request as soon as it is created. Defaults to <tt>false</tt>.
-     * This argument can also be a set of options that will be passed to {@link #load} is called.
+     * @property {Boolean} layoutManagedWidth
+     * @private
+     * Flag set by the container layout to which this Component is added.
+     * If the layout manages this Component's width, it sets the value to 1.
+     * If it does NOT manage the width, it sets it to 2.
+     * If the layout MAY affect the width, but only if the owning Container has a fixed width, this is set to 0.
      */
-    autoLoad: false,
 
     /**
-     * @cfg {Mixed} target The target element for the loader. It can be the DOM element, the id or an Ext.Element.
+     * @property {Boolean} layoutManagedHeight
+     * @private
+     * Flag set by the container layout to which this Component is added.
+     * If the layout manages this Component's height, it sets the value to 1.
+     * If it does NOT manage the height, it sets it to 2.
+     * If the layout MAY affect the height, but only if the owning Container has a fixed height, this is set to 0.
      */
-    target: null,
 
     /**
-     * @cfg {Mixed} loadMask True or a string to show when the element is loading.
+     * @cfg {String/Object} autoEl
+     * A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
+     * encapsulate this Component.
+     *
+     * You do not normally need to specify this. For the base classes {@link Ext.Component} and
+     * {@link Ext.container.Container}, this defaults to **'div'**. The more complex Sencha classes use a more
+     * complex DOM structure specified by their own {@link #renderTpl}s.
+     *
+     * This is intended to allow the developer to create application-specific utility Components encapsulated by
+     * different DOM elements. Example usage:
+     *
+     *     {
+     *         xtype: 'component',
+     *         autoEl: {
+     *             tag: 'img',
+     *             src: 'http://www.example.com/example.jpg'
+     *         }
+     *     }, {
+     *         xtype: 'component',
+     *         autoEl: {
+     *             tag: 'blockquote',
+     *             html: 'autoEl is cool!'
+     *         }
+     *     }, {
+     *         xtype: 'container',
+     *         autoEl: 'ul',
+     *         cls: 'ux-unordered-list',
+     *         items: {
+     *             xtype: 'component',
+     *             autoEl: 'li',
+     *             html: 'First list item'
+     *         }
+     *     }
      */
-    loadMask: false,
 
     /**
-     * @cfg {Object} ajaxOptions Any additional options to be passed to the request, for example timeout or headers. Defaults to <tt>null</tt>.
+     * @cfg {Ext.XTemplate/String/String[]} renderTpl
+     * An {@link Ext.XTemplate XTemplate} used to create the internal structure inside this Component's encapsulating
+     * {@link #getEl Element}.
+     *
+     * You do not normally need to specify this. For the base classes {@link Ext.Component} and
+     * {@link Ext.container.Container}, this defaults to **`null`** which means that they will be initially rendered
+     * with no internal structure; they render their {@link #getEl Element} empty. The more specialized ExtJS and Touch
+     * classes which use a more complex DOM structure, provide their own template definitions.
+     *
+     * This is intended to allow the developer to create application-specific utility Components with customized
+     * internal structure.
+     *
+     * Upon rendering, any created child elements may be automatically imported into object properties using the
+     * {@link #renderSelectors} and {@link #childEls} options.
      */
-    ajaxOptions: null,
-    
+    renderTpl: null,
+
     /**
-     * @cfg {Boolean} scripts True to parse any inline script tags in the response.
+     * @cfg {Object} renderData
+     *
+     * The data used by {@link #renderTpl} in addition to the following property values of the component:
+     *
+     * - id
+     * - ui
+     * - uiCls
+     * - baseCls
+     * - componentCls
+     * - frame
+     *
+     * See {@link #renderSelectors} and {@link #childEls} for usage examples.
      */
-    scripts: false,
 
     /**
-     * @cfg {Function} success A function to be called when a load request is successful.
+     * @cfg {Object} renderSelectors
+     * An object containing properties specifying {@link Ext.DomQuery DomQuery} selectors which identify child elements
+     * created by the render process.
+     *
+     * After the Component's internal structure is rendered according to the {@link #renderTpl}, this object is iterated through,
+     * and the found Elements are added as properties to the Component using the `renderSelector` property name.
+     *
+     * For example, a Component which renderes a title and description into its element:
+     *
+     *     Ext.create('Ext.Component', {
+     *         renderTo: Ext.getBody(),
+     *         renderTpl: [
+     *             '<h1 class="title">{title}</h1>',
+     *             '<p>{desc}</p>'
+     *         ],
+     *         renderData: {
+     *             title: "Error",
+     *             desc: "Something went wrong"
+     *         },
+     *         renderSelectors: {
+     *             titleEl: 'h1.title',
+     *             descEl: 'p'
+     *         },
+     *         listeners: {
+     *             afterrender: function(cmp){
+     *                 // After rendering the component will have a titleEl and descEl properties
+     *                 cmp.titleEl.setStyle({color: "red"});
+     *             }
+     *         }
+     *     });
+     *
+     * For a faster, but less flexible, alternative that achieves the same end result (properties for child elements on the
+     * Component after render), see {@link #childEls} and {@link #addChildEls}.
      */
 
     /**
-     * @cfg {Function} failure A function to be called when a load request fails.
+     * @cfg {Object[]} childEls
+     * An array describing the child elements of the Component. Each member of the array
+     * is an object with these properties:
+     *
+     * - `name` - The property name on the Component for the child element.
+     * - `itemId` - The id to combine with the Component's id that is the id of the child element.
+     * - `id` - The id of the child element.
+     *
+     * If the array member is a string, it is equivalent to `{ name: m, itemId: m }`.
+     *
+     * For example, a Component which renders a title and body text:
+     *
+     *     Ext.create('Ext.Component', {
+     *         renderTo: Ext.getBody(),
+     *         renderTpl: [
+     *             '<h1 id="{id}-title">{title}</h1>',
+     *             '<p>{msg}</p>',
+     *         ],
+     *         renderData: {
+     *             title: "Error",
+     *             msg: "Something went wrong"
+     *         },
+     *         childEls: ["title"],
+     *         listeners: {
+     *             afterrender: function(cmp){
+     *                 // After rendering the component will have a title property
+     *                 cmp.title.setStyle({color: "red"});
+     *             }
+     *         }
+     *     });
+     *
+     * A more flexible, but somewhat slower, approach is {@link #renderSelectors}.
      */
 
     /**
-     * @cfg {Object} scope The scope to execute the {@link #success} and {@link #failure} functions in.
+     * @cfg {String/HTMLElement/Ext.Element} renderTo
+     * Specify the id of the element, a DOM element or an existing Element that this component will be rendered into.
+     *
+     * **Notes:**
+     *
+     * Do *not* use this option if the Component is to be a child item of a {@link Ext.container.Container Container}.
+     * It is the responsibility of the {@link Ext.container.Container Container}'s
+     * {@link Ext.container.Container#layout layout manager} to render and manage its child items.
+     *
+     * When using this config, a call to render() is not required.
+     *
+     * See `{@link #render}` also.
      */
-    
+
     /**
-     * @cfg {Function} renderer A custom function to render the content to the element. The passed parameters
-     * are
-     * <ul>
-     * <li>The loader</li>
-     * <li>The response</li>
-     * <li>The active request</li>
-     * </ul>
+     * @cfg {Boolean} frame
+     * Specify as `true` to have the Component inject framing elements within the Component at render time to provide a
+     * graphical rounded frame around the Component content.
+     *
+     * This is only necessary when running on outdated, or non standard-compliant browsers such as Microsoft's Internet
+     * Explorer prior to version 9 which do not support rounded corners natively.
+     *
+     * The extra space taken up by this framing is available from the read only property {@link #frameSize}.
      */
 
-    isLoader: true,
+    /**
+     * @property {Object} frameSize
+     * Read-only property indicating the width of any framing elements which were added within the encapsulating element
+     * to provide graphical, rounded borders. See the {@link #frame} config.
+     *
+     * This is an object containing the frame width in pixels for all four sides of the Component containing the
+     * following properties:
+     *
+     * @property {Number} frameSize.top The width of the top framing element in pixels.
+     * @property {Number} frameSize.right The width of the right framing element in pixels.
+     * @property {Number} frameSize.bottom The width of the bottom framing element in pixels.
+     * @property {Number} frameSize.left The width of the left framing element in pixels.
+     */
 
-    constructor: function(config) {
-        var me = this,
-            autoLoad;
-        
-        config = config || {};
-        Ext.apply(me, config);
-        me.setTarget(me.target);
-        me.addEvents(
-            /**
-             * @event beforeload
-             * Fires before a load request is made to the server.
-             * Returning false from an event listener can prevent the load
-             * from occurring.
-             * @param {Ext.ElementLoader} this
-             * @param {Object} options The options passed to the request
-             */
-            'beforeload',
+    /**
+     * @cfg {String/Object} componentLayout
+     * The sizing and positioning of a Component's internal Elements is the responsibility of the Component's layout
+     * manager which sizes a Component's internal structure in response to the Component being sized.
+     *
+     * Generally, developers will not use this configuration as all provided Components which need their internal
+     * elements sizing (Such as {@link Ext.form.field.Base input fields}) come with their own componentLayout managers.
+     *
+     * The {@link Ext.layout.container.Auto default layout manager} will be used on instances of the base Ext.Component
+     * class which simply sizes the Component's encapsulating element to the height and width specified in the
+     * {@link #setSize} method.
+     */
 
-            /**
-             * @event exception
-             * Fires after an unsuccessful load.
-             * @param {Ext.ElementLoader} this
-             * @param {Object} response The response from the server
-             * @param {Object} options The options passed to the request
-             */
-            'exception',
+    /**
+     * @cfg {Ext.XTemplate/Ext.Template/String/String[]} tpl
+     * An {@link Ext.Template}, {@link Ext.XTemplate} or an array of strings to form an Ext.XTemplate. Used in
+     * conjunction with the `{@link #data}` and `{@link #tplWriteMode}` configurations.
+     */
 
-            /**
-             * @event exception
-             * Fires after a successful load.
-             * @param {Ext.ElementLoader} this
-             * @param {Object} response The response from the server
-             * @param {Object} options The options passed to the request
-             */
-            'load'
-        );
+    /**
+     * @cfg {Object} data
+     * The initial set of data to apply to the `{@link #tpl}` to update the content area of the Component.
+     */
 
-        // don't pass config because we have already applied it.
-        me.mixins.observable.constructor.call(me);
+    /**
+     * @cfg {String} xtype
+     * The `xtype` configuration option can be used to optimize Component creation and rendering. It serves as a
+     * shortcut to the full componet name. For example, the component `Ext.button.Button` has an xtype of `button`.
+     *
+     * You can define your own xtype on a custom {@link Ext.Component component} by specifying the
+     * {@link Ext.Class#alias alias} config option with a prefix of `widget`. For example:
+     *
+     *     Ext.define('PressMeButton', {
+     *         extend: 'Ext.button.Button',
+     *         alias: 'widget.pressmebutton',
+     *         text: 'Press Me'
+     *     })
+     *
+     * Any Component can be created implicitly as an object config with an xtype specified, allowing it to be
+     * declared and passed into the rendering pipeline without actually being instantiated as an object. Not only is
+     * rendering deferred, but the actual creation of the object itself is also deferred, saving memory and resources
+     * until they are actually needed. In complex, nested layouts containing many Components, this can make a
+     * noticeable improvement in performance.
+     *
+     *     // Explicit creation of contained Components:
+     *     var panel = new Ext.Panel({
+     *        ...
+     *        items: [
+     *           Ext.create('Ext.button.Button', {
+     *              text: 'OK'
+     *           })
+     *        ]
+     *     };
+     *
+     *     // Implicit creation using xtype:
+     *     var panel = new Ext.Panel({
+     *        ...
+     *        items: [{
+     *           xtype: 'button',
+     *           text: 'OK'
+     *        }]
+     *     };
+     *
+     * In the first example, the button will always be created immediately during the panel's initialization. With
+     * many added Components, this approach could potentially slow the rendering of the page. In the second example,
+     * the button will not be created or rendered until the panel is actually displayed in the browser. If the panel
+     * is never displayed (for example, if it is a tab that remains hidden) then the button will never be created and
+     * will never consume any resources whatsoever.
+     */
 
-        if (me.autoLoad) {
-            autoLoad = me.autoLoad;
-            if (autoLoad === true) {
-                autoLoad = {};
-            }
-            me.load(autoLoad);
-        }
-    },
+    /**
+     * @cfg {String} tplWriteMode
+     * The Ext.(X)Template method to use when updating the content area of the Component.
+     * See `{@link Ext.XTemplate#overwrite}` for information on default mode.
+     */
+    tplWriteMode: 'overwrite',
 
     /**
-     * Set an {Ext.Element} as the target of this loader. Note that if the target is changed,
-     * any active requests will be aborted.
-     * @param {Mixed} target The element
+     * @cfg {String} [baseCls='x-component']
+     * The base CSS class to apply to this components's element. This will also be prepended to elements within this
+     * component like Panel's body will get a class x-panel-body. This means that if you create a subclass of Panel, and
+     * you want it to get all the Panels styling for the element and the body, you leave the baseCls x-panel and use
+     * componentCls to add specific styling for this component.
      */
-    setTarget: function(target){
-        var me = this;
-        target = Ext.get(target);
-        if (me.target && me.target != target) {
-            me.abort();
-        }
-        me.target = target;
-    },
+    baseCls: Ext.baseCSSPrefix + 'component',
 
     /**
-     * Get the target of this loader.
-     * @return {Ext.Component} target The target, null if none exists.
+     * @cfg {String} componentCls
+     * CSS Class to be added to a components root level element to give distinction to it via styling.
      */
-    getTarget: function(){
-        return this.target || null;
-    },
 
     /**
-     * Aborts the active load request
+     * @cfg {String} [cls='']
+     * An optional extra CSS class that will be added to this component's Element. This can be useful
+     * for adding customized styles to the component or any of its children using standard CSS rules.
      */
-    abort: function(){
-        var active = this.active;
-        if (active !== undefined) {
-            Ext.Ajax.abort(active.request);
-            if (active.mask) {
-                this.removeMask();
-            }
-            delete this.active;
-        }
-    },
-    
+
     /**
-     * Remove the mask on the target
-     * @private
+     * @cfg {String} [overCls='']
+     * An optional extra CSS class that will be added to this component's Element when the mouse moves over the Element,
+     * and removed when the mouse moves out. This can be useful for adding customized 'active' or 'hover' styles to the
+     * component or any of its children using standard CSS rules.
      */
-    removeMask: function(){
-        this.target.unmask();
-    },
-    
+
     /**
-     * Add the mask on the target
-     * @private
-     * @param {Mixed} mask The mask configuration
+     * @cfg {String} [disabledCls='x-item-disabled']
+     * CSS class to add when the Component is disabled. Defaults to 'x-item-disabled'.
      */
-    addMask: function(mask){
-        this.target.mask(mask === true ? null : mask);
-    },
+    disabledCls: Ext.baseCSSPrefix + 'item-disabled',
 
     /**
-     * Load new data from the server.
-     * @param {Object} options The options for the request. They can be any configuration option that can be specified for
-     * the class, with the exception of the target option. Note that any options passed to the method will override any
-     * class defaults.
+     * @cfg {String/String[]} ui
+     * A set style for a component. Can be a string or an Array of multiple strings (UIs)
      */
-    load: function(options) {
-        //<debug>
-        if (!this.target) {
-            Ext.Error.raise('A valid target is required when loading content');
-        }
-        //</debug>
+    ui: 'default',
 
-        options = Ext.apply({}, options);
+    /**
+     * @cfg {String[]} uiCls
+     * An array of of classNames which are currently applied to this component
+     * @private
+     */
+    uiCls: [],
 
-        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;
+    /**
+     * @cfg {String} style
+     * A custom style specification to be applied to this component's Element. Should be a valid argument to
+     * {@link Ext.Element#applyStyles}.
+     *
+     *     new Ext.panel.Panel({
+     *         title: 'Some Title',
+     *         renderTo: Ext.getBody(),
+     *         width: 400, height: 300,
+     *         layout: 'form',
+     *         items: [{
+     *             xtype: 'textarea',
+     *             style: {
+     *                 width: '95%',
+     *                 marginBottom: '10px'
+     *             }
+     *         },
+     *         new Ext.button.Button({
+     *             text: 'Send',
+     *             minWidth: '100',
+     *             style: {
+     *                 marginBottom: '10px'
+     *             }
+     *         })
+     *         ]
+     *     });
+     */
 
-        Ext.applyIf(ajaxOptions, me.ajaxOptions);
-        Ext.applyIf(options, ajaxOptions);
+    /**
+     * @cfg {Number} width
+     * The width of this component in pixels.
+     */
 
-        Ext.applyIf(params, me.params);
-        Ext.apply(params, me.baseParams);
+    /**
+     * @cfg {Number} height
+     * The height of this component in pixels.
+     */
 
-        Ext.applyIf(options, {
-            url: me.url
-        });
+    /**
+     * @cfg {Number/String} border
+     * Specifies the border for this component. The border can be a single numeric value to apply to all sides or it can
+     * be a CSS style specification for each style, for example: '10 5 3 10'.
+     */
 
-        //<debug>
-        if (!options.url) {
-            Ext.Error.raise('You must specify the URL from which content should be loaded');
-        }
-        //</debug>
+    /**
+     * @cfg {Number/String} padding
+     * Specifies the padding for this component. The padding can be a single numeric value to apply to all sides or it
+     * can be a CSS style specification for each style, for example: '10 5 3 10'.
+     */
 
-        Ext.apply(options, {
-            scope: me,
-            params: params,
-            callback: me.onComplete
-        });
+    /**
+     * @cfg {Number/String} margin
+     * Specifies the margin for this component. The margin can be a single numeric value to apply to all sides or it can
+     * be a CSS style specification for each style, for example: '10 5 3 10'.
+     */
 
-        if (me.fireEvent('beforeload', me, options) === false) {
-            return;
-        }
+    /**
+     * @cfg {Boolean} hidden
+     * True to hide the component.
+     */
+    hidden: false,
 
-        if (mask) {
-            me.addMask(mask);
-        }
+    /**
+     * @cfg {Boolean} disabled
+     * True to disable the component.
+     */
+    disabled: false,
 
-        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);
-    },
-    
     /**
-     * Set any additional options on the active request
-     * @private
-     * @param {Object} active The active request
-     * @param {Object} options The initial options
+     * @cfg {Boolean} [draggable=false]
+     * Allows the component to be dragged.
      */
-    setOptions: Ext.emptyFn,
 
     /**
-     * Parse the response after the request completes
-     * @private
-     * @param {Object} options Ajax options
-     * @param {Boolean} success Success status of the request
-     * @param {Object} response The response object
+     * @property {Boolean} draggable
+     * Read-only property indicating whether or not the component can be dragged
      */
-    onComplete: function(options, success, response) {
-        var me = this,
-            active = me.active,
-            scope = active.scope,
-            renderer = me.getRenderer(active.renderer);
+    draggable: false,
 
+    /**
+     * @cfg {Boolean} floating
+     * Create the Component as a floating and use absolute positioning.
+     *
+     * The z-index of floating Components is handled by a ZIndexManager. If you simply render a floating Component into the DOM, it will be managed
+     * by the global {@link Ext.WindowManager WindowManager}.
+     *
+     * If you include a floating Component as a child item of a Container, then upon render, ExtJS will seek an ancestor floating Component to house a new
+     * ZIndexManager instance to manage its descendant floaters. If no floating ancestor can be found, the global WindowManager will be used.
+     *
+     * When a floating Component which has a ZindexManager managing descendant floaters is destroyed, those descendant floaters will also be destroyed.
+     */
+    floating: false,
 
-        if (success) {
-            success = renderer.call(me, me, response, active);
-        }
+    /**
+     * @cfg {String} hideMode
+     * A String which specifies how this Component's encapsulating DOM element will be hidden. Values may be:
+     *
+     *   - `'display'` : The Component will be hidden using the `display: none` style.
+     *   - `'visibility'` : The Component will be hidden using the `visibility: hidden` style.
+     *   - `'offsets'` : The Component will be hidden by absolutely positioning it out of the visible area of the document.
+     *     This is useful when a hidden Component must maintain measurable dimensions. Hiding using `display` results in a
+     *     Component having zero dimensions.
+     */
+    hideMode: 'display',
 
-        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]);
+    /**
+     * @cfg {String} contentEl
+     * Specify an existing HTML element, or the `id` of an existing HTML element to use as the content for this component.
+     *
+     * This config option is used to take an existing HTML element and place it in the layout element of a new component
+     * (it simply moves the specified DOM element _after the Component is rendered_ to use as the content.
+     *
+     * **Notes:**
+     *
+     * The specified HTML element is appended to the layout element of the component _after any configured
+     * {@link #html HTML} has been inserted_, and so the document will not contain this element at the time
+     * the {@link #render} event is fired.
+     *
+     * The specified HTML element used will not participate in any **`{@link Ext.container.Container#layout layout}`**
+     * scheme that the Component may use. It is just HTML. Layouts operate on child
+     * **`{@link Ext.container.Container#items items}`**.
+     *
+     * Add either the `x-hidden` or the `x-hide-display` CSS class to prevent a brief flicker of the content before it
+     * is rendered to the panel.
+     */
 
-        if (active.mask) {
-            me.removeMask();
-        }
+    /**
+     * @cfg {String/Object} [html='']
+     * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element content.
+     * The HTML content is added after the component is rendered, so the document will not contain this HTML at the time
+     * the {@link #render} event is fired. This content is inserted into the body _before_ any configured {@link #contentEl}
+     * is appended.
+     */
 
-        delete me.active;
-    },
+    /**
+     * @cfg {Boolean} styleHtmlContent
+     * True to automatically style the html inside the content target of this component (body for panels).
+     */
+    styleHtmlContent: false,
 
     /**
-     * Gets the renderer to use
-     * @private
-     * @param {String/Function} renderer The renderer to use
-     * @return {Function} A rendering function to use.
+     * @cfg {String} [styleHtmlCls='x-html']
+     * The class that is added to the content target when you set styleHtmlContent to true.
      */
-    getRenderer: function(renderer){
-        if (Ext.isFunction(renderer)) {
-            return renderer;
-        }
-        return this.statics().Renderer.Html;
-    },
-    
+    styleHtmlCls: Ext.baseCSSPrefix + 'html',
+
     /**
-     * Automatically refreshes the content over a specified period.
-     * @param {Number} interval The interval to refresh in ms.
-     * @param {Object} options (optional) The options to pass to the load method. See {@link #load}
+     * @cfg {Number} minHeight
+     * The minimum value in pixels which this Component will set its height to.
+     *
+     * **Warning:** This will override any size management applied by layout managers.
      */
-    startAutoRefresh: function(interval, options){
-        var me = this;
-        me.stopAutoRefresh();
-        me.autoRefresh = setInterval(function(){
-            me.load(options);
-        }, interval);
-    },
-    
     /**
-     * Clears any auto refresh. See {@link #startAutoRefresh}.
+     * @cfg {Number} minWidth
+     * The minimum value in pixels which this Component will set its width to.
+     *
+     * **Warning:** This will override any size management applied by layout managers.
      */
-    stopAutoRefresh: function(){
-        clearInterval(this.autoRefresh);
-        delete this.autoRefresh;
-    },
-    
     /**
-     * Checks whether the loader is automatically refreshing. See {@link #startAutoRefresh}.
-     * @return {Boolean} True if the loader is automatically refreshing
+     * @cfg {Number} maxHeight
+     * The maximum value in pixels which this Component will set its height to.
+     *
+     * **Warning:** This will override any size management applied by layout managers.
      */
-    isAutoRefreshing: function(){
-        return Ext.isDefined(this.autoRefresh);
-    },
-
     /**
-     * Destroys the loader. Any active requests will be aborted.
+     * @cfg {Number} maxWidth
+     * The maximum value in pixels which this Component will set its width to.
+     *
+     * **Warning:** This will override any size management applied by layout managers.
      */
-    destroy: function(){
-        var me = this;
-        me.stopAutoRefresh();
-        delete me.target;
-        me.abort();
-        me.clearListeners();
-    }
-});
-
-/**
- * @class Ext.layout.Layout
- * @extends Object
- * Base Layout class - extended by ComponentLayout and ContainerLayout
- */
-Ext.define('Ext.layout.Layout', {
-
-    /* Begin Definitions */
-
-    /* End Definitions */
-
-    isLayout: true,
-    initialized: false,
-
-    statics: {
-        create: function(layout, defaultType) {
-            var type;
-            if (layout instanceof Ext.layout.Layout) {
-                return Ext.createByAlias('layout.' + layout);
-            } else {
-                if (!layout || typeof layout === 'string') {
-                    type = layout || defaultType;
-                    layout = {};                    
-                }
-                else {
-                    type = layout.type;
-                }
-                return Ext.createByAlias('layout.' + type, layout || {});
-            }
-        }
-    },
-
-    constructor : function(config) {
-        this.id = Ext.id(null, this.type + '-');
-        Ext.apply(this, config);
-    },
 
     /**
-     * @private
+     * @cfg {Ext.ComponentLoader/Object} loader
+     * A configuration object or an instance of a {@link Ext.ComponentLoader} to load remote content for this Component.
      */
-    layout : function() {
-        var me = this;
-        me.layoutBusy = true;
-        me.initLayout();
-
-        if (me.beforeLayout.apply(me, arguments) !== false) {
-            me.layoutCancelled = false;
-            me.onLayout.apply(me, arguments);
-            me.childrenChanged = false;
-            me.owner.needsLayout = false;
-            me.layoutBusy = false;
-            me.afterLayout.apply(me, arguments);
-        }
-        else {
-            me.layoutCancelled = true;
-        }
-        me.layoutBusy = false;
-        me.doOwnerCtLayouts();
-    },
 
-    beforeLayout : function() {
-        this.renderItems(this.getLayoutItems(), this.getRenderTarget());
-        return true;
-    },
+    /**
+     * @cfg {Boolean} autoShow
+     * True to automatically show the component upon creation. This config option may only be used for
+     * {@link #floating} components or components that use {@link #autoRender}. Defaults to false.
+     */
+    autoShow: false,
 
     /**
-     * @private
-     * Iterates over all passed items, ensuring they are rendered.  If the items are already rendered,
-     * also determines if the items are in the proper place dom.
+     * @cfg {Boolean/String/HTMLElement/Ext.Element} autoRender
+     * This config is intended mainly for non-{@link #floating} Components which may or may not be shown. Instead of using
+     * {@link #renderTo} in the configuration, and rendering upon construction, this allows a Component to render itself
+     * upon first _{@link #show}_. If {@link #floating} is true, the value of this config is omited as if it is `true`.
+     *
+     * Specify as `true` to have this Component render to the document body upon first show.
+     *
+     * Specify as an element, or the ID of an element to have this Component render to a specific element upon first
+     * show.
+     *
+     * **This defaults to `true` for the {@link Ext.window.Window Window} class.**
      */
-    renderItems : function(items, target) {
-        var ln = items.length,
-            i = 0,
-            item;
+    autoRender: false,
 
-        for (; i < ln; i++) {
-            item = items[i];
-            if (item && !item.rendered) {
-                this.renderItem(item, target, i);
-            }
-            else if (!this.isValidParent(item, target, i)) {
-                this.moveItem(item, target, i);
-            }
-        }
-    },
+    needsLayout: false,
 
-    // @private - Validates item is in the proper place in the dom.
-    isValidParent : function(item, target, position) {
-        var dom = item.el ? item.el.dom : Ext.getDom(item);
-        if (dom && target && target.dom) {
-            if (Ext.isNumber(position) && dom !== target.dom.childNodes[position]) {
-                return false;
-            }
-            return (dom.parentNode == (target.dom || target));
-        }
-        return false;
-    },
+    // @private
+    allowDomMove: true,
 
     /**
-     * @private
-     * Renders the given Component into the target Element.
-     * @param {Ext.Component} item The Component to render
-     * @param {Ext.core.Element} target The target Element
-     * @param {Number} position The position within the target to render the item to
+     * @cfg {Object/Object[]} plugins
+     * An object or array of objects that will provide custom functionality for this component. The only requirement for
+     * a valid plugin is that it contain an init method that accepts a reference of type Ext.Component. When a component
+     * is created, if any plugins are available, the component will call the init method on each plugin, passing a
+     * reference to itself. Each plugin can then call methods or respond to events on the component as needed to provide
+     * its functionality.
      */
-    renderItem : function(item, target, position) {
-        var me = this;
-        if (!item.rendered) {
-            if (me.itemCls) {
-                item.addCls(me.itemCls);
-            }
-            if (me.owner.itemCls) {
-                item.addCls(me.owner.itemCls);
-            }
-            item.render(target, position);
-            me.configureItem(item);
-            me.childrenChanged = true;
-        }
-    },
 
     /**
-     * @private
-     * Moved Component to the provided target instead.
+     * @property {Boolean} rendered
+     * Read-only property indicating whether or not the component has been rendered.
      */
-    moveItem : function(item, target, position) {
-        // Make sure target is a dom element
-        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);
-        this.childrenChanged = true;
-    },
+    rendered: false,
 
     /**
+     * @property {Number} componentLayoutCounter
      * @private
-     * Adds the layout's targetCls if necessary and sets
-     * initialized flag when complete.
+     * The number of component layout calls made on this object.
      */
-    initLayout : function() {
-        if (!this.initialized && !Ext.isEmpty(this.targetCls)) {
-            this.getTarget().addCls(this.targetCls);
-        }
-        this.initialized = true;
-    },
+    componentLayoutCounter: 0,
 
-    // @private Sets the layout owner
-    setOwner : function(owner) {
-        this.owner = owner;
-    },
+    weight: 0,
+
+    trimRe: /^\s+|\s+$/g,
+    spacesRe: /\s+/,
 
-    // @private - Returns empty array
-    getLayoutItems : function() {
-        return [];
-    },
 
     /**
-     * @private
-     * Applies itemCls
-     * Empty template method
+     * @property {Boolean} maskOnDisable
+     * This is an internal flag that you use when creating custom components. By default this is set to true which means
+     * that every component gets a mask when its disabled. Components like FieldContainer, FieldSet, Field, Button, Tab
+     * override this property to false since they want to implement custom disable logic.
      */
-    configureItem: Ext.emptyFn,
-    
-    // Placeholder empty functions for subclasses to extend
-    onLayout : Ext.emptyFn,
-    afterLayout : Ext.emptyFn,
-    onRemove : Ext.emptyFn,
-    onDestroy : Ext.emptyFn,
-    doOwnerCtLayouts : Ext.emptyFn,
+    maskOnDisable: true,
 
     /**
-     * @private
-     * Removes itemCls
+     * Creates new Component.
+     * @param {Object} config  (optional) Config object.
      */
-    afterRemove : function(item) {
+    constructor : function(config) {
         var me = this,
-            el = item.el,
-            owner = me.owner;
-            
-        // Clear managed dimensions flag when removed from the layout.
-        if (item.rendered) {
-            if (me.itemCls) {
-                el.removeCls(me.itemCls);
-            }
-            if (owner.itemCls) {
-                el.removeCls(owner.itemCls);
-            }
-        }
+            i, len;
 
-        // These flags are set at the time a child item is added to a layout.
-        // The layout must decide if it is managing the item's width, or its height, or both.
-        // See AbstractComponent for docs on these properties.
-        delete item.layoutManagedWidth;
-        delete item.layoutManagedHeight;
-    },
+        config = config || {};
+        me.initialConfig = config;
+        Ext.apply(me, config);
 
-    /*
-     * Destroys this layout. This is a template method that is empty by default, but should be implemented
-     * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
-     * @protected
-     */
-    destroy : function() {
-        if (!Ext.isEmpty(this.targetCls)) {
-            var target = this.getTarget();
-            if (target) {
-                target.removeCls(this.targetCls);
-            }
-        }
-        this.onDestroy();
-    }
-});
-/**
- * @class Ext.layout.component.Component
- * @extends Ext.layout.Layout
- * @private
- * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.Component#componentLayout layout}</b></tt>
- * configuration property.  See <tt><b>{@link Ext.Component#componentLayout}</b></tt> for additional details.</p>
- */
+        me.addEvents(
+            /**
+             * @event beforeactivate
+             * Fires before a Component has been visually activated. Returning false from an event listener can prevent
+             * the activate from occurring.
+             * @param {Ext.Component} this
+             */
+            'beforeactivate',
+            /**
+             * @event activate
+             * Fires after a Component has been visually activated.
+             * @param {Ext.Component} this
+             */
+            'activate',
+            /**
+             * @event beforedeactivate
+             * Fires before a Component has been visually deactivated. Returning false from an event listener can
+             * prevent the deactivate from occurring.
+             * @param {Ext.Component} this
+             */
+            'beforedeactivate',
+            /**
+             * @event deactivate
+             * Fires after a Component has been visually deactivated.
+             * @param {Ext.Component} this
+             */
+            'deactivate',
+            /**
+             * @event added
+             * Fires after a Component had been added to a Container.
+             * @param {Ext.Component} this
+             * @param {Ext.container.Container} container Parent Container
+             * @param {Number} pos position of Component
+             */
+            'added',
+            /**
+             * @event disable
+             * Fires after the component is disabled.
+             * @param {Ext.Component} this
+             */
+            'disable',
+            /**
+             * @event enable
+             * Fires after the component is enabled.
+             * @param {Ext.Component} this
+             */
+            'enable',
+            /**
+             * @event beforeshow
+             * Fires before the component is shown when calling the {@link #show} method. Return false from an event
+             * handler to stop the show.
+             * @param {Ext.Component} this
+             */
+            'beforeshow',
+            /**
+             * @event show
+             * Fires after the component is shown when calling the {@link #show} method.
+             * @param {Ext.Component} this
+             */
+            'show',
+            /**
+             * @event beforehide
+             * Fires before the component is hidden when calling the {@link #hide} method. Return false from an event
+             * handler to stop the hide.
+             * @param {Ext.Component} this
+             */
+            'beforehide',
+            /**
+             * @event hide
+             * Fires after the component is hidden. Fires after the component is hidden when calling the {@link #hide}
+             * method.
+             * @param {Ext.Component} this
+             */
+            'hide',
+            /**
+             * @event removed
+             * Fires when a component is removed from an Ext.container.Container
+             * @param {Ext.Component} this
+             * @param {Ext.container.Container} ownerCt Container which holds the component
+             */
+            'removed',
+            /**
+             * @event beforerender
+             * Fires before the component is {@link #rendered}. Return false from an event handler to stop the
+             * {@link #render}.
+             * @param {Ext.Component} this
+             */
+            'beforerender',
+            /**
+             * @event render
+             * Fires after the component markup is {@link #rendered}.
+             * @param {Ext.Component} this
+             */
+            'render',
+            /**
+             * @event afterrender
+             * Fires after the component rendering is finished.
+             *
+             * The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed by any
+             * afterRender method defined for the Component.
+             * @param {Ext.Component} this
+             */
+            'afterrender',
+            /**
+             * @event beforedestroy
+             * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the
+             * {@link #destroy}.
+             * @param {Ext.Component} this
+             */
+            'beforedestroy',
+            /**
+             * @event destroy
+             * Fires after the component is {@link #destroy}ed.
+             * @param {Ext.Component} this
+             */
+            'destroy',
+            /**
+             * @event resize
+             * Fires after the component is resized.
+             * @param {Ext.Component} this
+             * @param {Number} adjWidth The box-adjusted width that was set
+             * @param {Number} adjHeight The box-adjusted height that was set
+             */
+            'resize',
+            /**
+             * @event move
+             * Fires after the component is moved.
+             * @param {Ext.Component} this
+             * @param {Number} x The new x position
+             * @param {Number} y The new y position
+             */
+            'move'
+        );
 
-Ext.define('Ext.layout.component.Component', {
+        me.getId();
 
-    /* Begin Definitions */
+        me.mons = [];
+        me.additionalCls = [];
+        me.renderData = me.renderData || {};
+        me.renderSelectors = me.renderSelectors || {};
 
-    extend: 'Ext.layout.Layout',
+        if (me.plugins) {
+            me.plugins = [].concat(me.plugins);
+            me.constructPlugins();
+        }
 
-    /* End Definitions */
+        me.initComponent();
 
-    type: 'component',
+        // ititComponent gets a chance to change the id property before registering
+        Ext.ComponentManager.register(me);
 
-    monitorChildren: true,
+        // Dont pass the config so that it is not applied to 'this' again
+        me.mixins.observable.constructor.call(me);
+        me.mixins.state.constructor.call(me, config);
 
-    initLayout : function() {
-        var me = this,
-            owner = me.owner,
-            ownerEl = owner.el;
+        // Save state on resize.
+        this.addStateEvents('resize');
 
-        if (!me.initialized) {
-            if (owner.frameSize) {
-                me.frameSize = owner.frameSize;
-            }
-            else {
-                owner.frameSize = me.frameSize = {
-                    top: 0,
-                    left: 0,
-                    bottom: 0,
-                    right: 0
-                }; 
+        // Move this into Observable?
+        if (me.plugins) {
+            me.plugins = [].concat(me.plugins);
+            for (i = 0, len = me.plugins.length; i < len; i++) {
+                me.plugins[i] = me.initPlugin(me.plugins[i]);
             }
         }
-        me.callParent(arguments);
-    },
 
-    beforeLayout : function(width, height, isSetSize, callingContainer) {
-        this.callParent(arguments);
-
-        var me = this,
-            owner = me.owner,
-            ownerCt = owner.ownerCt,
-            layout = owner.layout,
-            isVisible = owner.isVisible(true),
-            ownerElChild = owner.el.child,
-            layoutCollection;
+        me.loader = me.getLoader();
 
-        // Cache the size we began with so we can see if there has been any effect.
-        me.previousComponentSize = me.lastComponentSize;
+        if (me.renderTo) {
+            me.render(me.renderTo);
+            // EXTJSIV-1935 - should be a way to do afterShow or something, but that
+            // won't work. Likewise, rendering hidden and then showing (w/autoShow) has
+            // implications to afterRender so we cannot do that.
+        }
 
-        //Do not allow autoing of any dimensions which are fixed, unless we are being told to do so by the ownerCt's layout.
-        if (!isSetSize && ((!Ext.isNumber(width) && owner.isFixedWidth()) || (!Ext.isNumber(height) && owner.isFixedHeight())) && callingContainer !== ownerCt) {
-            me.doContainerLayout();
-            return false;
+        if (me.autoShow) {
+            me.show();
         }
 
-        // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
-        // If the owner itself is a directly hidden floater, set the needsLayout object on that for when it is shown.
-        if (!isVisible && (owner.hiddenAncestor || owner.floating)) {
-            if (owner.hiddenAncestor) {
-                layoutCollection = owner.hiddenAncestor.layoutOnShow;
-                layoutCollection.remove(owner);
-                layoutCollection.add(owner);
+        //<debug>
+        if (Ext.isDefined(me.disabledClass)) {
+            if (Ext.isDefined(Ext.global.console)) {
+                Ext.global.console.warn('Ext.Component: disabledClass has been deprecated. Please use disabledCls.');
             }
-            owner.needsLayout = {
-                width: width,
-                height: height,
-                isSetSize: false
-            };
+            me.disabledCls = me.disabledClass;
+            delete me.disabledClass;
         }
+        //</debug>
+    },
 
-        if (isVisible && this.needsLayout(width, height)) {
-            return owner.beforeComponentLayout(width, height, isSetSize, callingContainer);
-        }
-        else {
-            return false;
-        }
+    initComponent: function () {
+        // This is called again here to allow derived classes to add plugin configs to the
+        // plugins array before calling down to this, the base initComponent.
+        this.constructPlugins();
     },
 
     /**
-    * Check if the new size is different from the current size and only
-    * trigger a layout if it is necessary.
-    * @param {Mixed} width The new width to set.
-    * @param {Mixed} height The new height to set.
-    */
-    needsLayout : function(width, height) {
+     * The supplied default state gathering method for the AbstractComponent class.
+     *
+     * This method returns dimension settings such as `flex`, `anchor`, `width` and `height` along with `collapsed`
+     * state.
+     *
+     * Subclasses which implement more complex state should call the superclass's implementation, and apply their state
+     * to the result if this basic state is to be saved.
+     *
+     * Note that Component state will only be saved if the Component has a {@link #stateId} and there as a StateProvider
+     * configured for the document.
+     *
+     * @return {Object}
+     */
+    getState: function() {
         var me = this,
-            widthBeingChanged,
-            heightBeingChanged;
-            me.lastComponentSize = me.lastComponentSize || {
-                width: -Infinity,
-                height: -Infinity
-            };
-        
-        // If autoWidthing, or an explicitly different width is passed, then the width is being changed.
-        widthBeingChanged  = !Ext.isDefined(width)  || me.lastComponentSize.width  !== width;
-
-        // If autoHeighting, or an explicitly different height is passed, then the height is being changed.
-        heightBeingChanged = !Ext.isDefined(height) || me.lastComponentSize.height !== height;
-
+            layout = me.ownerCt ? (me.shadowOwnerCt || me.ownerCt).getLayout() : null,
+            state = {
+                collapsed: me.collapsed
+            },
+            width = me.width,
+            height = me.height,
+            cm = me.collapseMemento,
+            anchors;
 
-        // isSizing flag added to prevent redundant layouts when going up the layout chain
-        return !me.isSizing && (me.childrenChanged || widthBeingChanged || heightBeingChanged);
-    },
+        // If a Panel-local collapse has taken place, use remembered values as the dimensions.
+        // TODO: remove this coupling with Panel's privates! All collapse/expand logic should be refactored into one place.
+        if (me.collapsed && cm) {
+            if (Ext.isDefined(cm.data.width)) {
+                width = cm.width;
+            }
+            if (Ext.isDefined(cm.data.height)) {
+                height = cm.height;
+            }
+        }
 
-    /**
-    * Set the size of any element supporting undefined, null, and values.
-    * @param {Mixed} width The new width to set.
-    * @param {Mixed} height The new height to set.
-    */
-    setElementSize: function(el, width, height) {
-        if (width !== undefined && height !== undefined) {
-            el.setSize(width, height);
+        // If we have flex, only store the perpendicular dimension.
+        if (layout && me.flex) {
+            state.flex = me.flex;
+            if (layout.perpendicularPrefix) {
+                state[layout.perpendicularPrefix] = me['get' + layout.perpendicularPrefixCap]();
+            } else {
+                //<debug>
+                if (Ext.isDefined(Ext.global.console)) {
+                    Ext.global.console.warn('Ext.Component: Specified a flex value on a component not inside a Box layout');
+                }
+                //</debug>
+            }
         }
-        else if (height !== undefined) {
-            el.setHeight(height);
+        // If we have anchor, only store dimensions which are *not* being anchored
+        else if (layout && me.anchor) {
+            state.anchor = me.anchor;
+            anchors = me.anchor.split(' ').concat(null);
+            if (!anchors[0]) {
+                if (me.width) {
+                    state.width = width;
+                }
+            }
+            if (!anchors[1]) {
+                if (me.height) {
+                    state.height = height;
+                }
+            }
         }
-        else if (width !== undefined) {
-            el.setWidth(width);
+        // Store dimensions.
+        else {
+            if (me.width) {
+                state.width = width;
+            }
+            if (me.height) {
+                state.height = height;
+            }
         }
-    },
-
-    /**
-     * Returns the owner component's resize element.
-     * @return {Ext.core.Element}
-     */
-     getTarget : function() {
-         return this.owner.el;
-     },
-
-    /**
-     * <p>Returns the element into which rendering must take place. Defaults to the owner Component's encapsulating element.</p>
-     * May be overridden in Component layout managers which implement an inner element.
-     * @return {Ext.core.Element}
-     */
-    getRenderTarget : function() {
-        return this.owner.el;
-    },
-
-    /**
-    * Set the size of the target element.
-    * @param {Mixed} width The new width to set.
-    * @param {Mixed} height The new height to set.
-    */
-    setTargetSize : function(width, height) {
-        var me = this;
-        me.setElementSize(me.owner.el, width, height);
 
-        if (me.owner.frameBody) {
-            var targetInfo = me.getTargetInfo(),
-                padding = targetInfo.padding,
-                border = targetInfo.border,
-                frameSize = me.frameSize;
-
-            me.setElementSize(me.owner.frameBody,
-                Ext.isNumber(width) ? (width - frameSize.left - frameSize.right - padding.left - padding.right - border.left - border.right) : width,
-                Ext.isNumber(height) ? (height - frameSize.top - frameSize.bottom - padding.top - padding.bottom - border.top - border.bottom) : height
-            );
+        // Don't save dimensions if they are unchanged from the original configuration.
+        if (state.width == me.initialConfig.width) {
+            delete state.width;
+        }
+        if (state.height == me.initialConfig.height) {
+            delete state.height;
         }
 
-        me.autoSized = {
-            width: !Ext.isNumber(width),
-            height: !Ext.isNumber(height)
-        };
-
-        me.lastComponentSize = {
-            width: width,
-            height: height
-        };
-    },
-
-    getTargetInfo : function() {
-        if (!this.targetInfo) {
-            var target = this.getTarget(),
-                body = this.owner.getTargetEl();
-
-            this.targetInfo = {
-                padding: {
-                    top: target.getPadding('t'),
-                    right: target.getPadding('r'),
-                    bottom: target.getPadding('b'),
-                    left: target.getPadding('l')
-                },
-                border: {
-                    top: target.getBorderWidth('t'),
-                    right: target.getBorderWidth('r'),
-                    bottom: target.getBorderWidth('b'),
-                    left: target.getBorderWidth('l')
-                },
-                bodyMargin: {
-                    top: body.getMargin('t'),
-                    right: body.getMargin('r'),
-                    bottom: body.getMargin('b'),
-                    left: body.getMargin('l')
-                } 
-            };
+        // If a Box layout was managing the perpendicular dimension, don't save that dimension
+        if (layout && layout.align && (layout.align.indexOf('stretch') !== -1)) {
+            delete state[layout.perpendicularPrefix];
         }
-        return this.targetInfo;
+        return state;
     },
 
-    // Start laying out UP the ownerCt's layout when flagged to do so.
-    doOwnerCtLayouts: function() {
-        var owner = this.owner,
-            ownerCt = owner.ownerCt,
-            ownerCtComponentLayout, ownerCtContainerLayout,
-            curSize = this.lastComponentSize,
-            prevSize = this.previousComponentSize,
-            widthChange  = (prevSize && curSize && curSize.width) ? curSize.width !== prevSize.width : true,
-            heightChange = (prevSize && curSize && curSize.height) ? curSize.height !== prevSize.height : true;
+    show: Ext.emptyFn,
 
+    animate: function(animObj) {
+        var me = this,
+            to;
 
-        // If size has not changed, do not inform upstream layouts
-        if (!ownerCt || (!widthChange && !heightChange)) {
-            return;
+        animObj = animObj || {};
+        to = animObj.to || {};
+
+        if (Ext.fx.Manager.hasFxBlock(me.id)) {
+            return me;
         }
-        
-        ownerCtComponentLayout = ownerCt.componentLayout;
-        ownerCtContainerLayout = ownerCt.layout;
+        // Special processing for animating Component dimensions.
+        if (!animObj.dynamic && (to.height || to.width)) {
+            var curWidth = me.getWidth(),
+                w = curWidth,
+                curHeight = me.getHeight(),
+                h = curHeight,
+                needsResize = false;
 
-        if (!owner.floating && ownerCtComponentLayout && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
-            if (!ownerCt.suspendLayout && ownerCtContainerLayout && !ownerCtContainerLayout.layoutBusy) {
+            if (to.height && to.height > curHeight) {
+                h = to.height;
+                needsResize = true;
+            }
+            if (to.width && to.width > curWidth) {
+                w = to.width;
+                needsResize = true;
+            }
 
-                // If the owning Container may be adjusted in any of the the dimension which have changed, perform its Component layout
-                if (((widthChange && !ownerCt.isFixedWidth()) || (heightChange && !ownerCt.isFixedHeight()))) {
-                    // Set the isSizing flag so that the upstream Container layout (called after a Component layout) can omit this component from sizing operations
-                    this.isSizing = true;
-                    ownerCt.doComponentLayout();
-                    this.isSizing = false;
+            // If any dimensions are being increased, we must resize the internal structure
+            // of the Component, but then clip it by sizing its encapsulating element back to original dimensions.
+            // The animation will then progressively reveal the larger content.
+            if (needsResize) {
+                var clearWidth = !Ext.isNumber(me.width),
+                    clearHeight = !Ext.isNumber(me.height);
+
+                me.componentLayout.childrenChanged = true;
+                me.setSize(w, h, me.ownerCt);
+                me.el.setSize(curWidth, curHeight);
+                if (clearWidth) {
+                    delete me.width;
                 }
-                // Execute upstream Container layout
-                else if (ownerCtContainerLayout.bindToOwnerCtContainer === true) {
-                    ownerCtContainerLayout.layout();
+                if (clearHeight) {
+                    delete me.height;
                 }
             }
         }
+        return me.mixins.animate.animate.apply(me, arguments);
     },
 
-    doContainerLayout: function() {
-        var me = this,
-            owner = me.owner,
-            ownerCt = owner.ownerCt,
-            layout = owner.layout,
-            ownerCtComponentLayout;
+    /**
+     * This method finds the topmost active layout who's processing will eventually determine the size and position of
+     * this Component.
+     *
+     * This method is useful when dynamically adding Components into Containers, and some processing must take place
+     * after the final sizing and positioning of the Component has been performed.
+     *
+     * @return {Ext.Component}
+     */
+    findLayoutController: function() {
+        return this.findParentBy(function(c) {
+            // Return true if we are at the root of the Container tree
+            // or this Container's layout is busy but the next one up is not.
+            return !c.ownerCt || (c.layout.layoutBusy && !c.ownerCt.layout.layoutBusy);
+        });
+    },
 
-        // Run the container layout if it exists (layout for child items)
-        // **Unless automatic laying out is suspended, or the layout is currently running**
-        if (!owner.suspendLayout && layout && layout.isLayout && !layout.layoutBusy && !layout.isAutoDock) {
-            layout.layout();
+    onShow : function() {
+        // Layout if needed
+        var needsLayout = this.needsLayout;
+        if (Ext.isObject(needsLayout)) {
+            this.doComponentLayout(needsLayout.width, needsLayout.height, needsLayout.isSetSize, needsLayout.ownerCt);
         }
+    },
 
-        // Tell the ownerCt that it's child has changed and can be re-layed by ignoring the lastComponentSize cache.
-        if (ownerCt && ownerCt.componentLayout) {
-            ownerCtComponentLayout = ownerCt.componentLayout;
-            if (!owner.floating && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
-                ownerCtComponentLayout.childrenChanged = true;
-            }
+    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;
     },
 
-    afterLayout : function(width, height, isSetSize, layoutOwner) {
-        this.doContainerLayout();
-        this.owner.afterComponentLayout(width, height, isSetSize, layoutOwner);
-    }
-});
-
-/**
- * @class Ext.state.Manager
- * This is the global state manager. By default all components that are "state aware" check this class
- * for state information if you don't pass them a custom state provider. In order for this class
- * to be useful, it must be initialized with a provider when your application initializes. Example usage:
- <pre><code>
-// in your initialization function
-init : function(){
-   Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
-   var win = new Window(...);
-   win.restoreState();
-}
- </code></pre>
- * This class passes on calls from components to the underlying {@link Ext.state.Provider} so that
- * there is a common interface that can be used without needing to refer to a specific provider instance
- * in every component.
- * @singleton
- * @docauthor Evan Trimboli <evan@sencha.com>
- */
-Ext.define('Ext.state.Manager', {
-    singleton: true,
-    requires: ['Ext.state.Provider'],
-    constructor: function() {
-        this.provider = Ext.create('Ext.state.Provider');
-    },
-    
-    
     /**
-     * Configures the default state provider for your application
-     * @param {Provider} stateProvider The state provider to set
+     * Ensures that the plugins array contains fully constructed plugin instances. This converts any configs into their
+     * appropriate instances.
      */
-    setProvider : function(stateProvider){
-        this.provider = stateProvider;
-    },
+    constructPlugins: function() {
+        var me = this,
+            plugins = me.plugins,
+            i, len;
 
-    /**
-     * Returns the current value for a key
-     * @param {String} name The key name
-     * @param {Mixed} defaultValue The default value to return if the key lookup does not match
-     * @return {Mixed} The state data
-     */
-    get : function(key, defaultValue){
-        return this.provider.get(key, defaultValue);
+        if (plugins) {
+            for (i = 0, len = plugins.length; i < len; i++) {
+                // this just returns already-constructed plugin instances...
+                plugins[i] = me.constructPlugin(plugins[i]);
+            }
+        }
     },
 
-    /**
-     * Sets the value for a key
-     * @param {String} name The key name
-     * @param {Mixed} value The state data
-     */
-     set : function(key, value){
-        this.provider.set(key, value);
+    // @private
+    initPlugin : function(plugin) {
+        plugin.init(this);
+
+        return plugin;
     },
 
     /**
-     * Clears a value from the state
-     * @param {String} name The key name
+     * Handles autoRender. Floating Components may have an ownerCt. If they are asking to be constrained, constrain them
+     * within that ownerCt, and have their z-index managed locally. Floating Components are always rendered to
+     * document.body
      */
-    clear : function(key){
-        this.provider.clear(key);
+    doAutoRender: function() {
+        var me = this;
+        if (me.floating) {
+            me.render(document.body);
+        } else {
+            me.render(Ext.isBoolean(me.autoRender) ? Ext.getBody() : me.autoRender);
+        }
     },
 
-    /**
-     * Gets the currently configured state provider
-     * @return {Provider} The state provider
-     */
-    getProvider : function(){
-        return this.provider;
-    }
-});
-/**
- * @class Ext.state.Stateful
- * A mixin for being able to save the state of an object to an underlying
- * {@link Ext.state.Provider}.
- */
-Ext.define('Ext.state.Stateful', {
+    // @private
+    render : function(container, position) {
+        var me = this;
 
-    /* Begin Definitions */
+        if (!me.rendered && me.fireEvent('beforerender', me) !== false) {
 
-   mixins: {
-        observable: 'Ext.util.Observable'
-    },
+            // Flag set during the render process.
+            // It can be used to inhibit event-driven layout calls during the render phase
+            me.rendering = true;
 
-    requires: ['Ext.state.Manager'],
+            // If this.el is defined, we want to make sure we are dealing with
+            // an Ext Element.
+            if (me.el) {
+                me.el = Ext.get(me.el);
+            }
 
-    /* End Definitions */
+            // Perform render-time processing for floating Components
+            if (me.floating) {
+                me.onFloatRender();
+            }
 
-    /**
-     * @cfg {Boolean} stateful
-     * <p>A flag which causes the object to attempt to restore the state of
-     * internal properties from a saved state on startup. The object must have
-     * a <code>{@link #stateId}</code> for state to be managed.
-     * Auto-generated ids are not guaranteed to be stable across page loads and
-     * cannot be relied upon to save and restore the same state for a object.<p>
-     * <p>For state saving to work, the state manager's provider must have been
-     * set to an implementation of {@link Ext.state.Provider} which overrides the
-     * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
-     * methods to save and recall name/value pairs. A built-in implementation,
-     * {@link Ext.state.CookieProvider} is available.</p>
-     * <p>To set the state provider for the current page:</p>
-     * <pre><code>
-Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
-    expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
-}));
-     * </code></pre>
-     * <p>A stateful object attempts to save state when one of the events
-     * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
-     * <p>To save state, a stateful object first serializes its state by
-     * calling <b><code>{@link #getState}</code></b>. By default, this function does
-     * nothing. The developer must provide an implementation which returns an
-     * object hash which represents the restorable state of the object.</p>
-     * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
-     * which uses the configured {@link Ext.state.Provider} to save the object
-     * keyed by the <code>{@link #stateId}</code></p>.
-     * <p>During construction, a stateful object attempts to <i>restore</i>
-     * its state by calling {@link Ext.state.Manager#get} passing the
-     * <code>{@link #stateId}</code></p>
-     * <p>The resulting object is passed to <b><code>{@link #applyState}</code></b>.
-     * The default implementation of <code>{@link #applyState}</code> simply copies
-     * properties into the object, but a developer may override this to support
-     * more behaviour.</p>
-     * <p>You can perform extra processing on state save and restore by attaching
-     * handlers to the {@link #beforestaterestore}, {@link #staterestore},
-     * {@link #beforestatesave} and {@link #statesave} events.</p>
-     */
-    stateful: true,
+            container = me.initContainer(container);
 
-    /**
-     * @cfg {String} stateId
-     * The unique id for this object to use for state management purposes.
-     * <p>See {@link #stateful} for an explanation of saving and restoring state.</p>
-     */
+            me.onRender(container, position);
 
-    /**
-     * @cfg {Array} stateEvents
-     * <p>An array of events that, when fired, should trigger this object to
-     * save its state (defaults to none). <code>stateEvents</code> may be any type
-     * of event supported by this object, including browser or custom events
-     * (e.g., <tt>['click', 'customerchange']</tt>).</p>
-     * <p>See <code>{@link #stateful}</code> for an explanation of saving and
-     * restoring object state.</p>
-     */
+            // Tell the encapsulating element to hide itself in the way the Component is configured to hide
+            // This means DISPLAY, VISIBILITY or OFFSETS.
+            me.el.setVisibilityMode(Ext.Element[me.hideMode.toUpperCase()]);
 
-    /**
-     * @cfg {Number} saveBuffer A buffer to be applied if many state events are fired within
-     * a short period. Defaults to 100.
-     */
-    saveDelay: 100,
+            if (me.overCls) {
+                me.el.hover(me.addOverCls, me.removeOverCls, me);
+            }
 
-    autoGenIdRe: /^((\w+-)|(ext-comp-))\d{4,}$/i,
+            me.fireEvent('render', me);
 
-    constructor: function(config) {
-        var me = this;
+            me.initContent();
 
-        config = config || {};
-        if (Ext.isDefined(config.stateful)) {
-            me.stateful = config.stateful;
-        }
-        if (Ext.isDefined(config.saveDelay)) {
-            me.saveDelay = config.saveDelay;
-        }
-        me.stateId = me.stateId || config.stateId;
+            me.afterRender(container);
+            me.fireEvent('afterrender', me);
 
-        if (!me.stateEvents) {
-            me.stateEvents = [];
-        }
-        if (config.stateEvents) {
-            me.stateEvents.concat(config.stateEvents);
-        }
-        this.addEvents(
-            /**
-             * @event beforestaterestore
-             * Fires before the state of the object is restored. Return false from an event handler to stop the restore.
-             * @param {Ext.state.Stateful} this
-             * @param {Object} state The hash of state values returned from the StateProvider. If this
-             * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
-             * that simply copies property values into this object. The method maybe overriden to
-             * provide custom state restoration.
-             */
-            'beforestaterestore',
+            me.initEvents();
 
-            /**
-             * @event staterestore
-             * Fires after the state of the object is restored.
-             * @param {Ext.state.Stateful} this
-             * @param {Object} state The hash of state values returned from the StateProvider. This is passed
-             * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
-             * object. The method maybe overriden to provide custom state restoration.
-             */
-            'staterestore',
+            if (me.hidden) {
+                // Hiding during the render process should not perform any ancillary
+                // actions that the full hide process does; It is not hiding, it begins in a hidden state.'
+                // So just make the element hidden according to the configured hideMode
+                me.el.hide();
+            }
 
-            /**
-             * @event beforestatesave
-             * Fires before the state of the object is saved to the configured state provider. Return false to stop the save.
-             * @param {Ext.state.Stateful} this
-             * @param {Object} state The hash of state values. This is determined by calling
-             * <b><tt>getState()</tt></b> on the object. This method must be provided by the
-             * developer to return whetever representation of state is required, by default, Ext.state.Stateful
-             * has a null implementation.
-             */
-            'beforestatesave',
+            if (me.disabled) {
+                // pass silent so the event doesn't fire the first time.
+                me.disable(true);
+            }
 
-            /**
-             * @event statesave
-             * Fires after the state of the object is saved to the configured state provider.
-             * @param {Ext.state.Stateful} this
-             * @param {Object} state The hash of state values. This is determined by calling
-             * <b><tt>getState()</tt></b> on the object. This method must be provided by the
-             * developer to return whetever representation of state is required, by default, Ext.state.Stateful
-             * has a null implementation.
-             */
-            'statesave'
-        );
-        me.mixins.observable.constructor.call(me);
-        if (me.stateful !== false) {
-            me.initStateEvents();
-            me.initState();
+            // Delete the flag once the rendering is done.
+            delete me.rendering;
         }
+        return me;
     },
 
-    /**
-     * Initializes any state events for this object.
-     * @private
-     */
-    initStateEvents: function() {
-        this.addStateEvents(this.stateEvents);
-    },
-
-    /**
-     * Add events that will trigger the state to be saved.
-     * @param {String/Array} events The event name or an array of event names.
-     */
-    addStateEvents: function(events){
-        if (!Ext.isArray(events)) {
-            events = [events];
+    // @private
+    onRender : function(container, position) {
+        var me = this,
+            el = me.el,
+            styles = me.initStyles(),
+            renderTpl, renderData, i;
+
+        position = me.getInsertPosition(position);
+
+        if (!el) {
+            if (position) {
+                el = Ext.DomHelper.insertBefore(position, me.getElConfig(), true);
+            }
+            else {
+                el = Ext.DomHelper.append(container, me.getElConfig(), true);
+            }
+        }
+        else if (me.allowDomMove !== false) {
+            if (position) {
+                container.dom.insertBefore(el.dom, position);
+            } else {
+                container.dom.appendChild(el.dom);
+            }
         }
 
-        var me = this,
-            i = 0,
-            len = events.length;
+        if (Ext.scopeResetCSS && !me.ownerCt) {
+            // If this component's el is the body element, we add the reset class to the html tag
+            if (el.dom == Ext.getBody().dom) {
+                el.parent().addCls(Ext.baseCSSPrefix + 'reset');
+            }
+            else {
+                // Else we wrap this element in an element that adds the reset class.
+                me.resetEl = el.wrap({
+                    cls: Ext.baseCSSPrefix + 'reset'
+                });
+            }
+        }
 
-        for (; i < len; ++i) {
-            me.on(events[i], me.onStateChange, me);
+        me.setUI(me.ui);
+
+        el.addCls(me.initCls());
+        el.setStyle(styles);
+
+        // Here we check if the component has a height set through style or css.
+        // If it does then we set the this.height to that value and it won't be
+        // considered an auto height component
+        // if (this.height === undefined) {
+        //     var height = el.getHeight();
+        //     // This hopefully means that the panel has an explicit height set in style or css
+        //     if (height - el.getPadding('tb') - el.getBorderWidth('tb') > 0) {
+        //         this.height = height;
+        //     }
+        // }
+
+        me.el = el;
+
+        me.initFrame();
+
+        renderTpl = me.initRenderTpl();
+        if (renderTpl) {
+            renderData = me.initRenderData();
+            renderTpl.append(me.getTargetEl(), renderData);
         }
+
+        me.applyRenderSelectors();
+
+        me.rendered = true;
     },
 
-    /**
-     * This method is called when any of the {@link #stateEvents} are fired.
-     * @private
-     */
-    onStateChange: function(){
+    // @private
+    afterRender : function() {
         var me = this,
-            delay = me.saveDelay;
+            pos,
+            xy;
 
-        if (delay > 0) {
-            if (!me.stateTask) {
-                me.stateTask = Ext.create('Ext.util.DelayedTask', me.saveState, me);
-            }
-            me.stateTask.delay(me.saveDelay);
+        me.getComponentLayout();
+
+        // Set the size if a size is configured, or if this is the outermost Container.
+        // Also, if this is a collapsed Panel, it needs an initial component layout
+        // to lay out its header so that it can have a height determined.
+        if (me.collapsed || (!me.ownerCt || (me.height || me.width))) {
+            me.setSize(me.width, me.height);
         } else {
-            me.saveState();
+            // It is expected that child items be rendered before this method returns and
+            // the afterrender event fires. Since we aren't going to do the layout now, we
+            // must render the child items. This is handled implicitly above in the layout
+            // caused by setSize.
+            me.renderChildren();
+        }
+
+        // For floaters, calculate x and y if they aren't defined by aligning
+        // the sized element to the center of either the container or the ownerCt
+        if (me.floating && (me.x === undefined || me.y === undefined)) {
+            if (me.floatParent) {
+                xy = me.el.getAlignToXY(me.floatParent.getTargetEl(), 'c-c');
+                pos = me.floatParent.getTargetEl().translatePoints(xy[0], xy[1]);
+            } else {
+                xy = me.el.getAlignToXY(me.container, 'c-c');
+                pos = me.container.translatePoints(xy[0], xy[1]);
+            }
+            me.x = me.x === undefined ? pos.left: me.x;
+            me.y = me.y === undefined ? pos.top: me.y;
+        }
+
+        if (Ext.isDefined(me.x) || Ext.isDefined(me.y)) {
+            me.setPosition(me.x, me.y);
+        }
+
+        if (me.styleHtmlContent) {
+            me.getTargetEl().addCls(me.styleHtmlCls);
         }
     },
 
     /**
-     * Saves the state of the object to the persistence store.
      * @private
+     * Called by Component#doAutoRender
+     *
+     * Register a Container configured `floating: true` with this Component's {@link Ext.ZIndexManager ZIndexManager}.
+     *
+     * Components added in ths way will not participate in any layout, but will be rendered
+     * upon first show in the way that {@link Ext.window.Window Window}s are.
      */
-    saveState: function() {
+    registerFloatingItem: function(cmp) {
+        var me = this;
+        if (!me.floatingItems) {
+            me.floatingItems = Ext.create('Ext.ZIndexManager', me);
+        }
+        me.floatingItems.register(cmp);
+    },
+
+    renderChildren: function () {
         var me = this,
-            id,
-            state;
+            layout = me.getComponentLayout();
 
-        if (me.stateful !== false) {
-            id = me.getStateId();
-            if (id) {
-                state = me.getState();
-                if (me.fireEvent('beforestatesave', me, state) !== false) {
-                    Ext.state.Manager.set(id, state);
-                    me.fireEvent('statesave', me, state);
-                }
-            }
-        }
+        me.suspendLayout = true;
+        layout.renderChildren();
+        delete me.suspendLayout;
     },
 
-    /**
-     * Gets the current state of the object. By default this function returns null,
-     * it should be overridden in subclasses to implement methods for getting the state.
-     * @return {Object} The current state
-     */
-    getState: function(){
-        return null;
+    frameCls: Ext.baseCSSPrefix + 'frame',
+
+    frameIdRegex: /[-]frame\d+[TMB][LCR]$/,
+
+    frameElementCls: {
+        tl: [],
+        tc: [],
+        tr: [],
+        ml: [],
+        mc: [],
+        mr: [],
+        bl: [],
+        bc: [],
+        br: []
     },
 
+    frameTpl: [
+        '<tpl if="top">',
+            '<tpl if="left"><div id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" role="presentation"></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></div>',
+                '<tpl if="right"></div></tpl>',
+            '<tpl if="left"></div></tpl>',
+        '</tpl>'
+    ],
+
+    frameTableTpl: [
+        '<table><tbody>',
+            '<tpl if="top">',
+                '<tr>',
+                    '<tpl if="left"><td id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" style="background-position: 0 0;" role="presentation"></td>',
+                '<tpl if="right"><td id="{fgid}MR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></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 if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></tpl>" style="background-position: {br}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
+                '</tr>',
+            '</tpl>',
+        '</tbody></table>'
+    ],
+
     /**
-     * Applies the state to the object. This should be overridden in subclasses to do
-     * more complex state operations. By default it applies the state properties onto
-     * the current object.
-     * @param {Object} state The state
+     * @private
      */
-    applyState: function(state) {
-        if (state) {
-            Ext.apply(this, state);
+    initFrame : function() {
+        if (Ext.supports.CSS3BorderRadius) {
+            return false;
         }
-    },
 
-    /**
-     * Gets the state id for this object.
-     * @return {String} The state id, null if not found.
-     */
-    getStateId: function() {
         var me = this,
-            id = me.stateId;
+            frameInfo = me.getFrameInfo(),
+            frameWidth = frameInfo.width,
+            frameTpl = me.getFrameTpl(frameInfo.table),
+            frameGenId;
 
-        if (!id) {
-            id = me.autoGenIdRe.test(String(me.id)) ? null : me.id;
+        if (me.frame) {
+            // since we render id's into the markup and id's NEED to be unique, we have a
+            // simple strategy for numbering their generations.
+            me.frameGenId = frameGenId = (me.frameGenId || 0) + 1;
+            frameGenId = me.id + '-frame' + frameGenId;
+
+            // Here we render the frameTpl to this component. This inserts the 9point div or the table framing.
+            frameTpl.insertFirst(me.el, Ext.apply({}, {
+                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)));
+
+            // The frameBody is returned in getTargetEl, so that layouts render items to the correct target.=
+            me.frameBody = me.el.down('.' + me.frameCls + '-mc');
+
+            // Clean out the childEls for the old frame elements (the majority of the els)
+            me.removeChildEls(function (c) {
+                return c.id && me.frameIdRegex.test(c.id);
+            });
+
+            // Add the childEls for each of the new frame elements
+            Ext.each(['TL','TC','TR','ML','MC','MR','BL','BC','BR'], function (suffix) {
+                me.childEls.push({ name: 'frame' + suffix, id: frameGenId + suffix });
+            });
         }
-        return id;
     },
 
-    /**
-     * Initializes the state of the object upon construction.
-     * @private
-     */
-    initState: function(){
+    updateFrame: function() {
+        if (Ext.supports.CSS3BorderRadius) {
+            return false;
+        }
+
         var me = this,
-            id = me.getStateId(),
-            state;
+            wasTable = this.frameSize && this.frameSize.table,
+            oldFrameTL = this.frameTL,
+            oldFrameBL = this.frameBL,
+            oldFrameML = this.frameML,
+            oldFrameMC = this.frameMC,
+            newMCClassName;
 
-        if (me.stateful !== false) {
-            if (id) {
-                state = Ext.state.Manager.get(id);
-                if (state) {
-                    state = Ext.apply({}, state);
-                    if (me.fireEvent('beforestaterestore', me, state) !== false) {
-                        me.applyState(state);
-                        me.fireEvent('staterestore', me, state);
+        this.initFrame();
+
+        if (oldFrameMC) {
+            if (me.frame) {
+                // Reapply render selectors
+                delete me.frameTL;
+                delete me.frameTC;
+                delete me.frameTR;
+                delete me.frameML;
+                delete me.frameMC;
+                delete me.frameMR;
+                delete me.frameBL;
+                delete me.frameBC;
+                delete me.frameBR;
+                this.applyRenderSelectors();
+
+                // Store the class names set on the new mc
+                newMCClassName = this.frameMC.dom.className;
+
+                // Replace the new mc with the old mc
+                oldFrameMC.insertAfter(this.frameMC);
+                this.frameMC.remove();
+
+                // Restore the reference to the old frame mc as the framebody
+                this.frameBody = this.frameMC = oldFrameMC;
+
+                // Apply the new mc classes to the old mc element
+                oldFrameMC.dom.className = newMCClassName;
+
+                // Remove the old framing
+                if (wasTable) {
+                    me.el.query('> table')[1].remove();
+                }
+                else {
+                    if (oldFrameTL) {
+                        oldFrameTL.remove();
+                    }
+                    if (oldFrameBL) {
+                        oldFrameBL.remove();
                     }
+                    oldFrameML.remove();
                 }
             }
+            else {
+                // We were framed but not anymore. Move all content from the old frame to the body
+
+            }
+        }
+        else if (me.frame) {
+            this.applyRenderSelectors();
         }
     },
 
-    /**
-     * Destroys this stateful object.
-     */
-    destroy: function(){
-        var task = this.stateTask;
-        if (task) {
-            task.cancel();
+    getFrameInfo: function() {
+        if (Ext.supports.CSS3BorderRadius) {
+            return false;
         }
-        this.clearListeners();
 
-    }
+        var me = this,
+            left = me.el.getStyle('background-position-x'),
+            top = me.el.getStyle('background-position-y'),
+            info, frameInfo = false, max;
 
-});
+        // Some browsers dont support background-position-x and y, so for those
+        // browsers let's split background-position into two parts.
+        if (!left && !top) {
+            info = me.el.getStyle('background-position').split(' ');
+            left = info[0];
+            top = info[1];
+        }
 
-/**
- * @class Ext.AbstractManager
- * @extends Object
- * Base Manager class
- */
-Ext.define('Ext.AbstractManager', {
+        // We actually pass a string in the form of '[type][tl][tr]px [type][br][bl]px' as
+        // the background position of this.el from the css to indicate to IE that this component needs
+        // framing. We parse it here and change the markup accordingly.
+        if (parseInt(left, 10) >= 1000000 && parseInt(top, 10) >= 1000000) {
+            max = Math.max;
 
-    /* Begin Definitions */
+            frameInfo = {
+                // Table markup starts with 110, div markup with 100.
+                table: left.substr(0, 3) == '110',
 
-    requires: ['Ext.util.HashMap'],
+                // Determine if we are dealing with a horizontal or vertical component
+                vertical: top.substr(0, 3) == '110',
 
-    /* End Definitions */
+                // Get and parse the different border radius sizes
+                top:    max(left.substr(3, 2), left.substr(5, 2)),
+                right:  max(left.substr(5, 2), top.substr(3, 2)),
+                bottom: max(top.substr(3, 2), top.substr(5, 2)),
+                left:   max(top.substr(5, 2), left.substr(3, 2))
+            };
 
-    typeName: 'type',
+            frameInfo.width = max(frameInfo.top, frameInfo.right, frameInfo.bottom, frameInfo.left);
 
-    constructor: function(config) {
-        Ext.apply(this, config || {});
+            // Just to be sure we set the background image of the el to none.
+            me.el.setStyle('background-image', 'none');
+        }
 
-        /**
-         * Contains all of the items currently managed
-         * @property all
-         * @type Ext.util.MixedCollection
-         */
-        this.all = Ext.create('Ext.util.HashMap');
+        // This happens when you set frame: true explicitly without using the x-frame mixin in sass.
+        // This way IE can't figure out what sizes to use and thus framing can't work.
+        if (me.frame === true && !frameInfo) {
+            //<debug error>
+            Ext.Error.raise("You have set frame: true explicity on this component while it doesn't have any " +
+                            "framing defined in the CSS template. In this case IE can't figure out what sizes " +
+                            "to use and thus framing on this component will be disabled.");
+            //</debug>
+        }
 
-        this.types = {};
-    },
+        me.frame = me.frame || !!frameInfo;
+        me.frameSize = frameInfo || false;
 
-    /**
-     * Returns an item by id.
-     * For additional details see {@link Ext.util.HashMap#get}.
-     * @param {String} id The id of the item
-     * @return {Mixed} The item, <code>undefined</code> if not found.
-     */
-    get : function(id) {
-        return this.all.get(id);
+        return frameInfo;
     },
 
-    /**
-     * Registers an item to be managed
-     * @param {Mixed} item The item to register
-     */
-    register: function(item) {
-        this.all.add(item);
-    },
+    getFramePositions: function(frameInfo) {
+        var me = this,
+            frameWidth = frameInfo.width,
+            dock = me.dock,
+            positions, tc, bc, ml, mr;
 
-    /**
-     * Unregisters an item by removing it from this manager
-     * @param {Mixed} item The item to unregister
-     */
-    unregister: function(item) {
-        this.all.remove(item);
-    },
+        if (frameInfo.vertical) {
+            tc = '0 -' + (frameWidth * 0) + 'px';
+            bc = '0 -' + (frameWidth * 1) + 'px';
 
-    /**
-     * <p>Registers a new item constructor, keyed by a type key.
-     * @param {String} type The mnemonic string by which the class may be looked up.
-     * @param {Constructor} cls The new instance class.
-     */
-    registerType : function(type, cls) {
-        this.types[type] = cls;
-        cls[this.typeName] = type;
+            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;
     },
 
     /**
-     * Checks if an item type is registered.
-     * @param {String} type The mnemonic string by which the class may be looked up
-     * @return {Boolean} Whether the type is registered.
+     * @private
      */
-    isRegistered : function(type){
-        return this.types[type] !== undefined;
+    getFrameTpl : function(table) {
+        return table ? this.getTpl('frameTableTpl') : this.getTpl('frameTpl');
     },
 
     /**
-     * Creates and returns an instance of whatever this manager manages, based on the supplied type and config object
-     * @param {Object} config The config object
-     * @param {String} defaultType If no type is discovered in the config object, we fall back to this type
-     * @return {Mixed} The instance of whatever this manager is managing
+     * Creates an array of class names from the configurations to add to this Component's `el` on render.
+     *
+     * Private, but (possibly) used by ComponentQuery for selection by class name if Component is not rendered.
+     *
+     * @return {String[]} An array of class names with which the Component's element will be rendered.
+     * @private
      */
-    create: function(config, defaultType) {
-        var type        = config[this.typeName] || config.type || defaultType,
-            Constructor = this.types[type];
+    initCls: function() {
+        var me = this,
+            cls = [];
 
-        //<debug>
-        if (Constructor == undefined) {
-            Ext.Error.raise("The '" + type + "' type has not been registered with this manager");
-        }
-        //</debug>
+        cls.push(me.baseCls);
 
-        return new Constructor(config);
-    },
+        //<deprecated since=0.99>
+        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;
+        }
+        //</deprecated>
 
-    /**
-     * Registers a function that will be called when an item with the specified id is added to the manager. This will happen on instantiation.
-     * @param {String} id The item id
-     * @param {Function} fn The callback function. Called with a single parameter, the item.
-     * @param {Object} scope The scope (<code>this</code> reference) in which the callback is executed. Defaults to the item.
-     */
-    onAvailable : function(id, fn, scope){
-        var all = this.all,
-            item;
-        
-        if (all.containsKey(id)) {
-            item = all.get(id);
-            fn.call(scope || item, item);
+        if (me.componentCls) {
+            cls.push(me.componentCls);
         } else {
-            all.on('add', function(map, key, item){
-                if (key == id) {
-                    fn.call(scope || item, item);
-                    all.un('add', fn, scope);
-                }
-            });
+            me.componentCls = me.baseCls;
+        }
+        if (me.cls) {
+            cls.push(me.cls);
+            delete me.cls;
         }
+
+        return cls.concat(me.additionalCls);
     },
-    
+
     /**
-     * Executes the specified function once for each item in the collection.
-     * Returning false from the function will cease iteration.
-     * 
-     * The paramaters passed to the function are:
-     * <div class="mdetail-params"><ul>
-     * <li><b>key</b> : String<p class="sub-desc">The key of the item</p></li>
-     * <li><b>value</b> : Number<p class="sub-desc">The value of the item</p></li>
-     * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
-     * </ul></div>
-     * @param {Object} fn The function to execute.
-     * @param {Object} scope The scope to execute in. Defaults to <tt>this</tt>.
-     */
-    each: function(fn, scope){
-        this.all.each(fn, scope || this);    
-    },
-    
-    /**
-     * Gets the number of items in the collection.
-     * @return {Number} The number of items in the collection.
+     * Sets the UI for the component. This will remove any existing UIs on the component. It will also loop through any
+     * uiCls set on the component and rename them so they include the new UI
+     * @param {String} ui The new UI for the component
      */
-    getCount: function(){
-        return this.all.getCount();
-    }
-});
+    setUI: function(ui) {
+        var me = this,
+            oldUICls = Ext.Array.clone(me.uiCls),
+            newUICls = [],
+            classes = [],
+            cls,
+            i;
 
-/**
- * @class Ext.PluginManager
- * @extends Ext.AbstractManager
- * <p>Provides a registry of available Plugin <i>classes</i> indexed by a mnemonic code known as the Plugin's ptype.
- * The <code>{@link Ext.Component#xtype xtype}</code> provides a way to avoid instantiating child Components
- * when creating a full, nested config object for a complete Ext page.</p>
- * <p>A child Component may be specified simply as a <i>config object</i>
- * as long as the correct <code>{@link Ext.Component#xtype xtype}</code> is specified so that if and when the Component
- * needs rendering, the correct type can be looked up for lazy instantiation.</p>
- * <p>For a list of all available <code>{@link Ext.Component#xtype xtypes}</code>, see {@link Ext.Component}.</p>
- * @singleton
- */
-Ext.define('Ext.PluginManager', {
-    extend: 'Ext.AbstractManager',
-    alternateClassName: 'Ext.PluginMgr',
-    singleton: true,
-    typeName: 'ptype',
+        //loop through all exisiting uiCls and update the ui in them
+        for (i = 0; i < oldUICls.length; i++) {
+            cls = oldUICls[i];
 
-    /**
-     * Creates a new Plugin from the specified config object using the
-     * config object's ptype to determine the class to instantiate.
-     * @param {Object} config A configuration object for the Plugin you wish to create.
-     * @param {Constructor} defaultType The constructor to provide the default Plugin type if
-     * the config object does not contain a <code>ptype</code>. (Optional if the config contains a <code>ptype</code>).
-     * @return {Ext.Component} The newly instantiated Plugin.
-     */
-    //create: function(plugin, defaultType) {
-    //    if (plugin instanceof this) {
-    //        return plugin;
-    //    } else {
-    //        var type, config = {};
-    //
-    //        if (Ext.isString(plugin)) {
-    //            type = plugin;
-    //        }
-    //        else {
-    //            type = plugin[this.typeName] || defaultType;
-    //            config = plugin;
-    //        }
-    //
-    //        return Ext.createByAlias('plugin.' + type, config);
-    //    }
-    //},
+            classes = classes.concat(me.removeClsWithUI(cls, true));
+            newUICls.push(cls);
+        }
 
-    create : function(config, defaultType){
-        if (config.init) {
-            return config;
-        } else {
-            return Ext.createByAlias('plugin.' + (config.ptype || defaultType), config);
+        if (classes.length) {
+            me.removeCls(classes);
         }
-        
-        // Prior system supported Singleton plugins.
-        //var PluginCls = this.types[config.ptype || defaultType];
-        //if (PluginCls.init) {
-        //    return PluginCls;
-        //} else {
-        //    return new PluginCls(config);
-        //}
-    },
 
-    /**
-     * Returns all plugins registered with the given type. Here, 'type' refers to the type of plugin, not its ptype.
-     * @param {String} type The type to search for
-     * @param {Boolean} defaultsOnly True to only return plugins of this type where the plugin's isDefault property is truthy
-     * @return {Array} All matching plugins
-     */
-    findByType: function(type, defaultsOnly) {
-        var matches = [],
-            types   = this.types;
+        //remove the UI from the element
+        me.removeUIFromElement();
 
-        for (var name in types) {
-            if (!types.hasOwnProperty(name)) {
-                continue;
-            }
-            var item = types[name];
+        //set the UI
+        me.ui = ui;
 
-            if (item.type == type && (!defaultsOnly || (defaultsOnly === true && item.isDefault))) {
-                matches.push(item);
-            }
+        //add the new UI to the elemend
+        me.addUIToElement();
+
+        //loop through all exisiting uiCls and update the ui in them
+        classes = [];
+        for (i = 0; i < newUICls.length; i++) {
+            cls = newUICls[i];
+            classes = classes.concat(me.addClsWithUI(cls, true));
         }
 
-        return matches;
-    }
-}, function() {    
-    /**
-     * Shorthand for {@link Ext.PluginManager#registerType}
-     * @param {String} ptype The ptype mnemonic string by which the Plugin class
-     * may be looked up.
-     * @param {Constructor} cls The new Plugin class.
-     * @member Ext
-     * @method preg
-     */
-    Ext.preg = function() {
-        return Ext.PluginManager.registerType.apply(Ext.PluginManager, arguments);
-    };
-});
+        if (classes.length) {
+            me.addCls(classes);
+        }
+    },
 
-/**
- * @class Ext.ComponentManager
- * @extends Ext.AbstractManager
- * <p>Provides a registry of all Components (instances of {@link Ext.Component} or any subclass
- * thereof) on a page so that they can be easily accessed by {@link Ext.Component component}
- * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).</p>
- * <p>This object also provides a registry of available Component <i>classes</i>
- * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}.
- * The <code>xtype</code> provides a way to avoid instantiating child Components
- * when creating a full, nested config object for a complete Ext page.</p>
- * <p>A child Component may be specified simply as a <i>config object</i>
- * as long as the correct <code>{@link Ext.Component#xtype xtype}</code> is specified so that if and when the Component
- * needs rendering, the correct type can be looked up for lazy instantiation.</p>
- * <p>For a list of all available <code>{@link Ext.Component#xtype xtypes}</code>, see {@link Ext.Component}.</p>
- * @singleton
- */
-Ext.define('Ext.ComponentManager', {
-    extend: 'Ext.AbstractManager',
-    alternateClassName: 'Ext.ComponentMgr',
-    
-    singleton: true,
-    
-    typeName: 'xtype',
-    
     /**
-     * Creates a new Component from the specified config object using the
-     * config object's xtype to determine the class to instantiate.
-     * @param {Object} config A configuration object for the Component you wish to create.
-     * @param {Constructor} defaultType The constructor to provide the default Component type if
-     * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
-     * @return {Ext.Component} The newly instantiated Component.
+     * Adds a cls to the uiCls array, which will also call {@link #addUIClsToElement} and adds to all elements of this
+     * component.
+     * @param {String/String[]} cls A string or an array of strings to add to the uiCls
+     * @param {Object} skip (Boolean) skip True to skip adding it to the class and do it later (via the return)
      */
-    create: function(component, defaultType){
-        if (component instanceof Ext.AbstractComponent) {
-            return component;
-        }
-        else if (Ext.isString(component)) {
-            return Ext.createByAlias('widget.' + component);
-        }
-        else {
-            var type = component.xtype || defaultType,
-                config = component;
-            
-            return Ext.createByAlias('widget.' + type, config);
-        }
-    },
+    addClsWithUI: function(cls, skip) {
+        var me = this,
+            classes = [],
+            i;
 
-    registerType: function(type, cls) {
-        this.types[type] = cls;
-        cls[this.typeName] = type;
-        cls.prototype[this.typeName] = type;
-    }
-});
-/**
- * @class Ext.XTemplate
- * @extends Ext.Template
- * <p>A template class that supports advanced functionality like:<div class="mdetail-params"><ul>
- * <li>Autofilling arrays using templates and sub-templates</li>
- * <li>Conditional processing with basic comparison operators</li>
- * <li>Basic math function support</li>
- * <li>Execute arbitrary inline code with special built-in template variables</li>
- * <li>Custom member functions</li>
- * <li>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</li>
- * </ul></div></p>
- * <p>XTemplate provides the templating mechanism built into:<div class="mdetail-params"><ul>
- * <li>{@link Ext.view.View}</li>
- * </ul></div></p>
- *
- * The {@link Ext.Template} describes
- * the acceptable parameters to pass to the constructor. The following
- * examples demonstrate all of the supported features.</p>
- *
- * <div class="mdetail-params"><ul>
- *
- * <li><b><u>Sample Data</u></b>
- * <div class="sub-desc">
- * <p>This is the data object used for reference in each code example:</p>
- * <pre><code>
-var data = {
-name: 'Tommy Maintz',
-title: 'Lead Developer',
-company: 'Sencha Inc.',
-email: 'tommy@sencha.com',
-address: '5 Cups Drive',
-city: 'Palo Alto',
-state: 'CA',
-zip: '44102',
-drinks: ['Coffee', 'Soda', 'Water'],
-kids: [{
-        name: 'Joshua',
-        age:3
-    },{
-        name: 'Matthew',
-        age:2
-    },{
-        name: 'Solomon',
-        age:0
-}]
-};
- </code></pre>
- * </div>
- * </li>
- *
- *
- * <li><b><u>Auto filling of arrays</u></b>
- * <div class="sub-desc">
- * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>for</tt></b> operator are used
- * to process the provided data object:
- * <ul>
- * <li>If the value specified in <tt>for</tt> is an array, it will auto-fill,
- * repeating the template block inside the <tt>tpl</tt> tag for each item in the
- * array.</li>
- * <li>If <tt>for="."</tt> is specified, the data object provided is examined.</li>
- * <li>While processing an array, the special variable <tt>{#}</tt>
- * will provide the current array index + 1 (starts at 1, not 0).</li>
- * </ul>
- * </p>
- * <pre><code>
-&lt;tpl <b>for</b>=".">...&lt;/tpl>       // loop through array at root node
-&lt;tpl <b>for</b>="foo">...&lt;/tpl>     // loop through array at foo node
-&lt;tpl <b>for</b>="foo.bar">...&lt;/tpl> // loop through array at foo.bar node
- </code></pre>
- * Using the sample data above:
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>Kids: ',
-    '&lt;tpl <b>for</b>=".">',       // process the data.kids node
-        '&lt;p>{#}. {name}&lt;/p>',  // use current array index to autonumber
-    '&lt;/tpl>&lt;/p>'
-);
-tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
- </code></pre>
- * <p>An example illustrating how the <b><tt>for</tt></b> property can be leveraged
- * to access specified members of the provided data object to populate the template:</p>
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>Name: {name}&lt;/p>',
-    '&lt;p>Title: {title}&lt;/p>',
-    '&lt;p>Company: {company}&lt;/p>',
-    '&lt;p>Kids: ',
-    '&lt;tpl <b>for="kids"</b>>',     // interrogate the kids property within the data
-        '&lt;p>{name}&lt;/p>',
-    '&lt;/tpl>&lt;/p>'
-);
-tpl.overwrite(panel.body, data);  // pass the root node of the data object
- </code></pre>
- * <p>Flat arrays that contain values (and not objects) can be auto-rendered
- * using the special <b><tt>{.}</tt></b> variable inside a loop.  This variable
- * will represent the value of the array at the current index:</p>
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>{name}\&#39;s favorite beverages:&lt;/p>',
-    '&lt;tpl for="drinks">',
-        '&lt;div> - {.}&lt;/div>',
-    '&lt;/tpl>'
-);
-tpl.overwrite(panel.body, data);
- </code></pre>
- * <p>When processing a sub-template, for example while looping through a child array,
- * you can access the parent object's members via the <b><tt>parent</tt></b> object:</p>
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>Name: {name}&lt;/p>',
-    '&lt;p>Kids: ',
-    '&lt;tpl for="kids">',
-        '&lt;tpl if="age &amp;gt; 1">',
-            '&lt;p>{name}&lt;/p>',
-            '&lt;p>Dad: {<b>parent</b>.name}&lt;/p>',
-        '&lt;/tpl>',
-    '&lt;/tpl>&lt;/p>'
-);
-tpl.overwrite(panel.body, data);
- </code></pre>
- * </div>
- * </li>
- *
- *
- * <li><b><u>Conditional processing with basic comparison operators</u></b>
- * <div class="sub-desc">
- * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>if</tt></b> operator are used
- * to provide conditional checks for deciding whether or not to render specific
- * parts of the template. Notes:<div class="sub-desc"><ul>
- * <li>Double quotes must be encoded if used within the conditional</li>
- * <li>There is no <tt>else</tt> operator &mdash; if needed, two opposite
- * <tt>if</tt> statements should be used.</li>
- * </ul></div>
- * <pre><code>
-&lt;tpl if="age &gt; 1 &amp;&amp; age &lt; 10">Child&lt;/tpl>
-&lt;tpl if="age >= 10 && age < 18">Teenager&lt;/tpl>
-&lt;tpl <b>if</b>="this.isGirl(name)">...&lt;/tpl>
-&lt;tpl <b>if</b>="id==\'download\'">...&lt;/tpl>
-&lt;tpl <b>if</b>="needsIcon">&lt;img src="{icon}" class="{iconCls}"/>&lt;/tpl>
-// no good:
-&lt;tpl if="name == "Tommy"">Hello&lt;/tpl>
-// encode &#34; if it is part of the condition, e.g.
-&lt;tpl if="name == &#38;quot;Tommy&#38;quot;">Hello&lt;/tpl>
- * </code></pre>
- * Using the sample data above:
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>Name: {name}&lt;/p>',
-    '&lt;p>Kids: ',
-    '&lt;tpl for="kids">',
-        '&lt;tpl if="age &amp;gt; 1">',
-            '&lt;p>{name}&lt;/p>',
-        '&lt;/tpl>',
-    '&lt;/tpl>&lt;/p>'
-);
-tpl.overwrite(panel.body, data);
- </code></pre>
- * </div>
- * </li>
- *
- *
- * <li><b><u>Basic math support</u></b>
- * <div class="sub-desc">
- * <p>The following basic math operators may be applied directly on numeric
- * data values:</p><pre>
- * + - * /
- * </pre>
- * For example:
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>Name: {name}&lt;/p>',
-    '&lt;p>Kids: ',
-    '&lt;tpl for="kids">',
-        '&lt;tpl if="age &amp;gt; 1">',  // <-- Note that the &gt; is encoded
-            '&lt;p>{#}: {name}&lt;/p>',  // <-- Auto-number each item
-            '&lt;p>In 5 Years: {age+5}&lt;/p>',  // <-- Basic math
-            '&lt;p>Dad: {parent.name}&lt;/p>',
-        '&lt;/tpl>',
-    '&lt;/tpl>&lt;/p>'
-);
-tpl.overwrite(panel.body, data);
- </code></pre>
- * </div>
- * </li>
- *
- *
- * <li><b><u>Execute arbitrary inline code with special built-in template variables</u></b>
- * <div class="sub-desc">
- * <p>Anything between <code>{[ ... ]}</code> is considered code to be executed
- * in the scope of the template. There are some special variables available in that code:
- * <ul>
- * <li><b><tt>values</tt></b>: The values in the current scope. If you are using
- * scope changing sub-templates, you can change what <tt>values</tt> is.</li>
- * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li>
- * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the
- * loop you are in (1-based).</li>
- * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length
- * of the array you are looping.</li>
- * </ul>
- * This example demonstrates basic row striping using an inline code block and the
- * <tt>xindex</tt> variable:</p>
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>Name: {name}&lt;/p>',
-    '&lt;p>Company: {[values.company.toUpperCase() + ", " + values.title]}&lt;/p>',
-    '&lt;p>Kids: ',
-    '&lt;tpl for="kids">',
-        '&lt;div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
-        '{name}',
-        '&lt;/div>',
-    '&lt;/tpl>&lt;/p>'
- );
-tpl.overwrite(panel.body, data);
- </code></pre>
- * </div>
- * </li>
- *
- * <li><b><u>Template member functions</u></b>
- * <div class="sub-desc">
- * <p>One or more member functions can be specified in a configuration
- * object passed into the XTemplate constructor for more complex processing:</p>
- * <pre><code>
-var tpl = new Ext.XTemplate(
-    '&lt;p>Name: {name}&lt;/p>',
-    '&lt;p>Kids: ',
-    '&lt;tpl for="kids">',
-        '&lt;tpl if="this.isGirl(name)">',
-            '&lt;p>Girl: {name} - {age}&lt;/p>',
-        '&lt;/tpl>',
-         // use opposite if statement to simulate 'else' processing:
-        '&lt;tpl if="this.isGirl(name) == false">',
-            '&lt;p>Boy: {name} - {age}&lt;/p>',
-        '&lt;/tpl>',
-        '&lt;tpl if="this.isBaby(age)">',
-            '&lt;p>{name} is a baby!&lt;/p>',
-        '&lt;/tpl>',
-    '&lt;/tpl>&lt;/p>',
-    {
-        // XTemplate configuration:
-        compiled: true,
-        // member functions:
-        isGirl: function(name){
-           return name == 'Sara Grace';
-        },
-        isBaby: function(age){
-           return age < 1;
+        if (!Ext.isArray(cls)) {
+            cls = [cls];
         }
-    }
-);
-tpl.overwrite(panel.body, data);
- </code></pre>
- * </div>
- * </li>
- *
- * </ul></div>
- *
- * @param {Mixed} config
- */
-
-Ext.define('Ext.XTemplate', {
 
-    /* Begin Definitions */
-
-    extend: 'Ext.Template',
+        for (i = 0; i < cls.length; i++) {
+            if (cls[i] && !me.hasUICls(cls[i])) {
+                me.uiCls = Ext.Array.clone(me.uiCls);
+                me.uiCls.push(cls[i]);
 
-    statics: {
-        /**
-         * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
-         * @param {String/HTMLElement} el A DOM element or its id
-         * @return {Ext.Template} The created template
-         * @static
-         */
-        from: function(el, config) {
-            el = Ext.getDom(el);
-            return new this(el.value || el.innerHTML, config || {});
+                classes = classes.concat(me.addUIClsToElement(cls[i]));
+            }
         }
-    },
 
-    /* End Definitions */
+        if (skip !== true) {
+            me.addCls(classes);
+        }
 
-    argsRe: /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
-    nameRe: /^<tpl\b[^>]*?for="(.*?)"/,
-    ifRe: /^<tpl\b[^>]*?if="(.*?)"/,
-    execRe: /^<tpl\b[^>]*?exec="(.*?)"/,
-    constructor: function() {
-        this.callParent(arguments);
+        return classes;
+    },
 
+    /**
+     * Removes a cls to the uiCls array, which will also call {@link #removeUIClsFromElement} and removes it from all
+     * elements of this component.
+     * @param {String/String[]} cls A string or an array of strings to remove to the uiCls
+     */
+    removeClsWithUI: function(cls, skip) {
         var me = this,
-            html = me.html,
-            argsRe = me.argsRe,
-            nameRe = me.nameRe,
-            ifRe = me.ifRe,
-            execRe = me.execRe,
-            id = 0,
-            tpls = [],
-            VALUES = 'values',
-            PARENT = 'parent',
-            XINDEX = 'xindex',
-            XCOUNT = 'xcount',
-            RETURN = 'return ',
-            WITHVALUES = 'with(values){ ',
-            m, matchName, matchIf, matchExec, exp, fn, exec, name, i;
-
-        html = ['<tpl>', html, '</tpl>'].join('');
-
-        while ((m = html.match(argsRe))) {
-            exp = null;
-            fn = null;
-            exec = null;
-            matchName = m[0].match(nameRe);
-            matchIf = m[0].match(ifRe);
-            matchExec = m[0].match(execRe);
+            classes = [],
+            i;
 
-            exp = matchIf ? matchIf[1] : null;
-            if (exp) {
-                fn = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + 'try{' + RETURN + Ext.String.htmlDecode(exp) + ';}catch(e){return;}}');
-            }
+        if (!Ext.isArray(cls)) {
+            cls = [cls];
+        }
 
-            exp = matchExec ? matchExec[1] : null;
-            if (exp) {
-                exec = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + Ext.String.htmlDecode(exp) + ';}');
-            }
+        for (i = 0; i < cls.length; i++) {
+            if (cls[i] && me.hasUICls(cls[i])) {
+                me.uiCls = Ext.Array.remove(me.uiCls, cls[i]);
 
-            name = matchName ? matchName[1] : null;
-            if (name) {
-                if (name === '.') {
-                    name = VALUES;
-                } else if (name === '..') {
-                    name = PARENT;
-                }
-                name = Ext.functionFactory(VALUES, PARENT, 'try{' + WITHVALUES + RETURN + name + ';}}catch(e){return;}');
+                classes = classes.concat(me.removeUIClsFromElement(cls[i]));
             }
-
-            tpls.push({
-                id: id,
-                target: name,
-                exec: exec,
-                test: fn,
-                body: m[1] || ''
-            });
-
-            html = html.replace(m[0], '{xtpl' + id + '}');
-            id = id + 1;
         }
 
-        for (i = tpls.length - 1; i >= 0; --i) {
-            me.compileTpl(tpls[i]);
+        if (skip !== true) {
+            me.removeCls(classes);
         }
-        me.master = tpls[tpls.length - 1];
-        me.tpls = tpls;
-    },
 
-    // @private
-    applySubTemplate: function(id, values, parent, xindex, xcount) {
-        var me = this, t = me.tpls[id];
-        return t.compiled.call(me, values, parent, xindex, xcount);
+        return classes;
     },
+
     /**
-     * @cfg {RegExp} codeRe The regular expression used to match code variables (default: matches <tt>{[expression]}</tt>).
+     * Checks if there is currently a specified uiCls
+     * @param {String} cls The cls to check
      */
-    codeRe: /\{\[((?:\\\]|.|\n)*?)\]\}/g,
+    hasUICls: function(cls) {
+        var me = this,
+            uiCls = me.uiCls || [];
 
-    re: /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?\}/g,
+        return Ext.Array.contains(uiCls, cls);
+    },
 
-    // @private
-    compileTpl: function(tpl) {
-        var fm = Ext.util.Format,
-            me = this,
-            useFormat = me.disableFormats !== true,
-            body, bodyReturn, evaluatedFn;
+    /**
+     * Method which adds a specified UI + uiCls to the components element. Can be overridden to remove the UI from more
+     * than just the components element.
+     * @param {String} ui The UI to remove from the element
+     */
+    addUIClsToElement: function(cls, force) {
+        var me = this,
+            result = [],
+            frameElementCls = me.frameElementCls;
 
-        function fn(m, name, format, args, math) {
-            var v;
-            // name is what is inside the {}
-            // Name begins with xtpl, use a Sub Template
-            if (name.substr(0, 4) == 'xtpl') {
-                return "',this.applySubTemplate(" + name.substr(4) + ", values, parent, xindex, xcount),'";
-            }
-            // name = "." - Just use the values object.
-            if (name == '.') {
-                // filter to not include arrays/objects/nulls
-                v = 'Ext.Array.indexOf(["string", "number", "boolean"], typeof values) > -1 || Ext.isDate(values) ? values : ""';
-            }
+        result.push(Ext.baseCSSPrefix + cls);
+        result.push(me.baseCls + '-' + cls);
+        result.push(me.baseCls + '-' + me.ui + '-' + cls);
 
-            // name = "#" - Use the xindex
-            else if (name == '#') {
-                v = 'xindex';
-            }
-            else if (name.substr(0, 7) == "parent.") {
-                v = name;
-            }
-            // name has a . in it - Use object literal notation, starting from values
-            else if (name.indexOf('.') != -1) {
-                v = "values." + name;
-            }
+        if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
+            // define each element of the frame
+            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
+                classes, i, j, el;
 
-            // name is a property of values
-            else {
-                v = "values['" + name + "']";
-            }
-            if (math) {
-                v = '(' + v + math + ')';
-            }
-            if (format && useFormat) {
-                args = args ? ',' + args : "";
-                if (format.substr(0, 5) != "this.") {
-                    format = "fm." + format + '(';
-                }
-                else {
-                    format = 'this.' + format.substr(5) + '(';
+            // loop through each of them, and if they are defined add the ui
+            for (i = 0; i < els.length; i++) {
+                el = me['frame' + els[i].toUpperCase()];
+                classes = [me.baseCls + '-' + me.ui + '-' + els[i], me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i]];
+                if (el && el.dom) {
+                    el.addCls(classes);
+                } else {
+                    for (j = 0; j < classes.length; j++) {
+                        if (Ext.Array.indexOf(frameElementCls[els[i]], classes[j]) == -1) {
+                            frameElementCls[els[i]].push(classes[j]);
+                        }
+                    }
                 }
             }
-            else {
-                args = '';
-                format = "(" + v + " === undefined ? '' : ";
-            }
-            return "'," + format + v + args + "),'";
-        }
-
-        function codeFn(m, code) {
-            // Single quotes get escaped when the template is compiled, however we want to undo this when running code.
-            return "',(" + code.replace(me.compileARe, "'") + "),'";
         }
 
-        bodyReturn = tpl.body.replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn).replace(me.codeRe, codeFn);
-        body = "evaluatedFn = function(values, parent, xindex, xcount){return ['" + bodyReturn + "'].join('');};";
-        eval(body);
+        me.frameElementCls = frameElementCls;
 
-        tpl.compiled = function(values, parent, xindex, xcount) {
-            var vs,
-                length,
-                buffer,
-                i;
+        return result;
+    },
 
-            if (tpl.test && !tpl.test.call(me, values, parent, xindex, xcount)) {
-                return '';
-            }
+    /**
+     * Method which removes a specified UI + uiCls from the components element. The cls which is added to the element
+     * will be: `this.baseCls + '-' + ui`
+     * @param {String} ui The UI to add to the element
+     */
+    removeUIClsFromElement: function(cls, force) {
+        var me = this,
+            result = [],
+            frameElementCls = me.frameElementCls;
 
-            vs = tpl.target ? tpl.target.call(me, values, parent) : values;
-            if (!vs) {
-               return '';
-            }
+        result.push(Ext.baseCSSPrefix + cls);
+        result.push(me.baseCls + '-' + cls);
+        result.push(me.baseCls + '-' + me.ui + '-' + cls);
 
-            parent = tpl.target ? values : parent;
-            if (tpl.target && Ext.isArray(vs)) {
-                buffer = [];
-                length = vs.length;
-                if (tpl.exec) {
-                    for (i = 0; i < length; i++) {
-                        buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
-                        tpl.exec.call(me, vs[i], parent, i + 1, length);
-                    }
+        if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
+            // define each element of the frame
+            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
+                i, el;
+            cls = me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i];
+            // loop through each of them, and if they are defined add the ui
+            for (i = 0; i < els.length; i++) {
+                el = me['frame' + els[i].toUpperCase()];
+                if (el && el.dom) {
+                    el.removeCls(cls);
                 } else {
-                    for (i = 0; i < length; i++) {
-                        buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
-                    }
+                    Ext.Array.remove(frameElementCls[els[i]], cls);
                 }
-                return buffer.join('');
             }
+        }
 
-            if (tpl.exec) {
-                tpl.exec.call(me, vs, parent, xindex, xcount);
-            }
-            return evaluatedFn.call(me, vs, parent, xindex, xcount);
-        };
+        me.frameElementCls = frameElementCls;
 
-        return this;
+        return result;
     },
 
     /**
-     * Returns an HTML fragment of this template with the specified values applied.
-     * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
-     * @return {String} The HTML fragment
+     * Method which adds a specified UI to the components element.
+     * @private
      */
-    applyTemplate: function(values) {
-        return this.master.compiled.call(this, values, {}, 1, 1);
-    },
-
-    /**
-     * Compile the template to a function for optimized performance.  Recommended if the template will be used frequently.
-     * @return {Function} The compiled function
-     */
-    compile: function() {
-        return this;
-    }
-}, function() {
-    /**
-     * Alias for {@link #applyTemplate}
-     * Returns an HTML fragment of this template with the specified values applied.
-     * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
-     * @return {String} The HTML fragment
-     * @member Ext.XTemplate
-     * @method apply
-     */
-    this.createAlias('apply', 'applyTemplate');
-});
+    addUIToElement: function(force) {
+        var me = this,
+            frameElementCls = me.frameElementCls;
 
-/**
- * @class Ext.util.AbstractMixedCollection
- */
-Ext.define('Ext.util.AbstractMixedCollection', {
-    requires: ['Ext.util.Filter'],
-    
-    mixins: {
-        observable: 'Ext.util.Observable'
-    },
+        me.addCls(me.baseCls + '-' + me.ui);
 
-    constructor: function(allowFunctions, keyFn) {
-        var me = this;
+        if (me.frame && !Ext.supports.CSS3BorderRadius) {
+            // define each element of the frame
+            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
+                i, el, cls;
 
-        me.items = [];
-        me.map = {};
-        me.keys = [];
-        me.length = 0;
+            // loop through each of them, and if they are defined add the ui
+            for (i = 0; i < els.length; i++) {
+                el = me['frame' + els[i].toUpperCase()];
+                cls = me.baseCls + '-' + me.ui + '-' + els[i];
+                if (el) {
+                    el.addCls(cls);
+                } else {
+                    if (!Ext.Array.contains(frameElementCls[els[i]], cls)) {
+                        frameElementCls[els[i]].push(cls);
+                    }
+                }
+            }
+        }
+    },
 
-        me.addEvents(
-            /**
-             * @event clear
-             * Fires when the collection is cleared.
-             */
-            'clear',
+    /**
+     * Method which removes a specified UI from the components element.
+     * @private
+     */
+    removeUIFromElement: function() {
+        var me = this,
+            frameElementCls = me.frameElementCls;
 
-            /**
-             * @event add
-             * Fires when an item is added to the collection.
-             * @param {Number} index The index at which the item was added.
-             * @param {Object} o The item added.
-             * @param {String} key The key associated with the added item.
-             */
-            'add',
+        me.removeCls(me.baseCls + '-' + me.ui);
 
-            /**
-             * @event replace
-             * Fires when an item is replaced in the collection.
-             * @param {String} key he key associated with the new added.
-             * @param {Object} old The item being replaced.
-             * @param {Object} new The new item.
-             */
-            'replace',
+        if (me.frame && !Ext.supports.CSS3BorderRadius) {
+            // define each element of the frame
+            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
+                i, j, el, cls;
 
-            /**
-             * @event remove
-             * Fires when an item is removed from the collection.
-             * @param {Object} o The item being removed.
-             * @param {String} key (optional) The key associated with the removed item.
-             */
-            'remove'
-        );
+            // loop through each of them, and if they are defined add the ui
+            for (i = 0; i < els.length; i++) {
+                el = me['frame' + els[i].toUpperCase()];
+                cls = me.baseCls + '-' + me.ui + '-' + els[i];
 
-        me.allowFunctions = allowFunctions === true;
+                if (el) {
+                    el.removeCls(cls);
+                } else {
+                    Ext.Array.remove(frameElementCls[els[i]], cls);
+                }
+            }
+        }
+    },
 
-        if (keyFn) {
-            me.getKey = keyFn;
+    getElConfig : function() {
+        if (Ext.isString(this.autoEl)) {
+            this.autoEl = {
+                tag: this.autoEl
+            };
         }
 
-        me.mixins.observable.constructor.call(me);
+        var result = this.autoEl || {tag: 'div'};
+        result.id = this.id;
+        return result;
     },
-    
-    /**
-     * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
-     * function should add function references to the collection. Defaults to
-     * <tt>false</tt>.
-     */
-    allowFunctions : false,
 
     /**
-     * Adds an item to the collection. Fires the {@link #add} event when complete.
-     * @param {String} key <p>The key to associate with the item, or the new item.</p>
-     * <p>If a {@link #getKey} implementation was specified for this MixedCollection,
-     * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
-     * the MixedCollection will be able to <i>derive</i> the key for the new item.
-     * In this case just pass the new item in this parameter.</p>
-     * @param {Object} o The item to add.
-     * @return {Object} The item added.
+     * This function takes the position argument passed to onRender and returns a DOM element that you can use in the
+     * insertBefore.
+     * @param {String/Number/Ext.Element/HTMLElement} position Index, element id or element you want to put this
+     * component before.
+     * @return {HTMLElement} DOM element that you can use in the insertBefore
      */
-    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);
+    getInsertPosition: function(position) {
+        // Convert the position to an element to insert before
+        if (position !== undefined) {
+            if (Ext.isNumber(position)) {
+                position = this.container.dom.childNodes[position];
+            }
+            else {
+                position = Ext.getDom(position);
             }
-            me.map[myKey] = myObj;
         }
-        me.length++;
-        me.items.push(myObj);
-        me.keys.push(myKey);
-        me.fireEvent('add', me.length - 1, myObj, myKey);
-        return myObj;
+
+        return position;
     },
 
     /**
-      * MixedCollection has a generic way to fetch keys if you implement getKey.  The default implementation
-      * simply returns <b><code>item.id</code></b> but you can provide your own implementation
-      * to return a different value as in the following examples:<pre><code>
-// normal way
-var mc = new Ext.util.MixedCollection();
-mc.add(someEl.dom.id, someEl);
-mc.add(otherEl.dom.id, otherEl);
-//and so on
+     * Adds ctCls to container.
+     * @return {Ext.Element} The initialized container
+     * @private
+     */
+    initContainer: function(container) {
+        var me = this;
 
-// using getKey
-var mc = new Ext.util.MixedCollection();
-mc.getKey = function(el){
-   return el.dom.id;
-};
-mc.add(someEl);
-mc.add(otherEl);
+        // If you render a component specifying the el, we get the container
+        // of the el, and make sure we dont move the el around in the dom
+        // during the render
+        if (!container && me.el) {
+            container = me.el.dom.parentNode;
+            me.allowDomMove = false;
+        }
 
-// or via the constructor
-var mc = new Ext.util.MixedCollection(false, function(el){
-   return el.dom.id;
-});
-mc.add(someEl);
-mc.add(otherEl);
-     * </code></pre>
-     * @param {Object} item The item for which to find the key.
-     * @return {Object} The key for the passed item.
-     */
-    getKey : function(o){
-         return o.id;
+        me.container = Ext.get(container);
+
+        if (me.ctCls) {
+            me.container.addCls(me.ctCls);
+        }
+
+        return me.container;
     },
 
     /**
-     * Replaces an item in the collection. Fires the {@link #replace} event when complete.
-     * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>
-     * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
-     * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
-     * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item
-     * with one having the same key value, then just pass the replacement item in this parameter.</p>
-     * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate
-     * with that key.
-     * @return {Object}  The new item.
+     * Initialized the renderData to be used when rendering the renderTpl.
+     * @return {Object} Object with keys and values that are going to be applied to the renderTpl
+     * @private
      */
-    replace : function(key, o){
-        var me = this,
-            old,
-            index;
+    initRenderData: function() {
+        var me = this;
 
-        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);
-        }
-        index = me.indexOfKey(key);
-        me.items[index] = o;
-        me.map[key] = o;
-        me.fireEvent('replace', key, old, o);
-        return o;
+        return Ext.applyIf(me.renderData, {
+            id: me.id,
+            ui: me.ui,
+            uiCls: me.uiCls,
+            baseCls: me.baseCls,
+            componentCls: me.componentCls,
+            frame: me.frame
+        });
     },
 
     /**
-     * Adds all elements of an Array or an Object to the collection.
-     * @param {Object/Array} objs An Object containing properties which will be added
-     * to the collection, or an Array of values, each of which are added to the collection.
-     * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>
-     * has been set to <tt>true</tt>.
+     * @private
      */
-    addAll : function(objs){
+    getTpl: function(name) {
         var me = this,
-            i = 0,
-            args,
-            len,
-            key;
+            prototype = me.self.prototype,
+            ownerPrototype,
+            tpl;
 
-        if (arguments.length > 1 || Ext.isArray(objs)) {
-            args = arguments.length > 1 ? arguments : objs;
-            for (len = args.length; i < len; i++) {
-                me.add(args[i]);
+        if (me.hasOwnProperty(name)) {
+            tpl = me[name];
+            if (tpl && !(tpl instanceof Ext.XTemplate)) {
+                me[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
             }
-        } else {
-            for (key in objs) {
-                if (objs.hasOwnProperty(key)) {
-                    if (me.allowFunctions || typeof objs[key] != 'function') {
-                        me.add(key, objs[key]);
+
+            return me[name];
+        }
+
+        if (!(prototype[name] instanceof Ext.XTemplate)) {
+            ownerPrototype = prototype;
+
+            do {
+                if (ownerPrototype.hasOwnProperty(name)) {
+                    tpl = ownerPrototype[name];
+                    if (tpl && !(tpl instanceof Ext.XTemplate)) {
+                        ownerPrototype[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
+                        break;
                     }
                 }
-            }
+
+                ownerPrototype = ownerPrototype.superclass;
+            } while (ownerPrototype);
         }
+
+        return prototype[name];
     },
 
     /**
-     * Executes the specified function once for every item in the collection, passing the following arguments:
-     * <div class="mdetail-params"><ul>
-     * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>
-     * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>
-     * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
-     * </ul></div>
-     * The function should return a boolean value. Returning false from the function will stop the iteration.
-     * @param {Function} fn The function to execute for each item.
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current item in the iteration.
+     * Initializes the renderTpl.
+     * @return {Ext.XTemplate} The renderTpl XTemplate instance.
+     * @private
      */
-    each : function(fn, scope){
-        var items = [].concat(this.items), // each safe for removal
-            i = 0,
-            len = items.length,
-            item;
-
-        for (; i < len; i++) {
-            item = items[i];
-            if (fn.call(scope || item, item, i, len) === false) {
-                break;
-            }
-        }
+    initRenderTpl: function() {
+        return this.getTpl('renderTpl');
     },
 
     /**
-     * Executes the specified function once for every key in the collection, passing each
-     * key, and its associated item as the first two parameters.
-     * @param {Function} fn The function to execute for each item.
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
+     * Converts style definitions to String.
+     * @return {String} A CSS style string with style, padding, margin and border.
+     * @private
      */
-    eachKey : function(fn, scope){
-        var keys = this.keys,
-            items = this.items,
-            i = 0,
-            len = keys.length;
+    initStyles: function() {
+        var style = {},
+            me = this,
+            Element = Ext.Element;
 
-        for (; i < len; i++) {
-            fn.call(scope || window, keys[i], items[i], i, len);
+        if (Ext.isString(me.style)) {
+            style = Element.parseStyles(me.style);
+        } else {
+            style = Ext.apply({}, me.style);
         }
-    },
 
-    /**
-     * Returns the first item in the collection which elicits a true return value from the
-     * passed selection function.
-     * @param {Function} fn The selection function to execute for each item.
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
-     * @return {Object} The first item in the collection which returned true from the selection function.
-     */
-    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];
-            }
+        // Convert the padding, margin and border properties from a space seperated string
+        // into a proper style string
+        if (me.padding !== undefined) {
+            style.padding = Element.unitizeBox((me.padding === true) ? 5 : me.padding);
         }
-        return null;
-    },
 
-    //<deprecated since="0.99">
-    find : function() {
-        if (Ext.isDefined(Ext.global.console)) {
-            Ext.global.console.warn('Ext.util.MixedCollection: find has been deprecated. Use findBy instead.');
+        if (me.margin !== undefined) {
+            style.margin = Element.unitizeBox((me.margin === true) ? 5 : me.margin);
         }
-        return this.findBy.apply(this, arguments);
+
+        delete me.style;
+        return style;
     },
-    //</deprecated>
 
     /**
-     * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.
-     * @param {Number} index The index to insert the item at.
-     * @param {String} key The key to associate with the new item, or the item itself.
-     * @param {Object} o (optional) If the second parameter was a key, the new item.
-     * @return {Object} The item inserted.
+     * Initializes this components contents. It checks for the properties html, contentEl and tpl/data.
+     * @private
      */
-    insert : function(index, key, obj){
+    initContent: function() {
         var me = this,
-            myKey = key,
-            myObj = obj;
+            target = me.getTargetEl(),
+            contentEl,
+            pre;
 
-        if (arguments.length == 2) {
-            myObj = myKey;
-            myKey = me.getKey(myObj);
+        if (me.html) {
+            target.update(Ext.DomHelper.markup(me.html));
+            delete me.html;
         }
-        if (me.containsKey(myKey)) {
-            me.suspendEvents();
-            me.removeAtKey(myKey);
-            me.resumeEvents();
+
+        if (me.contentEl) {
+            contentEl = Ext.get(me.contentEl);
+            pre = Ext.baseCSSPrefix;
+            contentEl.removeCls([pre + 'hidden', pre + 'hide-display', pre + 'hide-offsets', pre + 'hide-nosize']);
+            target.appendChild(contentEl.dom);
         }
-        if (index >= me.length) {
-            return me.add(myKey, myObj);
+
+        if (me.tpl) {
+            // Make sure this.tpl is an instantiated XTemplate
+            if (!me.tpl.isTemplate) {
+                me.tpl = Ext.create('Ext.XTemplate', me.tpl);
+            }
+
+            if (me.data) {
+                me.tpl[me.tplWriteMode](target, me.data);
+                delete me.data;
+            }
         }
-        me.length++;
-        Ext.Array.splice(me.items, index, 0, myObj);
-        if (typeof myKey != 'undefined' && myKey !== null) {
-            me.map[myKey] = myObj;
+    },
+
+    // @private
+    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);
+                    }
+                }
+            }
         }
-        Ext.Array.splice(me.keys, index, 0, myKey);
-        me.fireEvent('add', index, myObj, myKey);
-        return myObj;
     },
 
     /**
-     * Remove an item from the collection.
-     * @param {Object} o The item to remove.
-     * @return {Object} The item removed or false if no item was removed.
+     * Adds each argument passed to this method to the {@link #childEls} array.
      */
-    remove : function(o){
-        return this.removeAt(this.indexOf(o));
+    addChildEls: function () {
+        var me = this,
+            childEls = me.childEls || (me.childEls = []);
+
+        childEls.push.apply(childEls, arguments);
     },
 
     /**
-     * Remove all items in the passed array from the collection.
-     * @param {Array} items An array of items to be removed.
-     * @return {Ext.util.MixedCollection} this object
+     * Removes items in the childEls array based on the return value of a supplied test function. The function is called
+     * with a entry in childEls and if the test function return true, that entry is removed. If false, that entry is
+     * kept.
+     * @param {Function} testFn The test function.
      */
-    removeAll : function(items){
-        Ext.each(items || [], function(item) {
-            this.remove(item);
-        }, this);
+    removeChildEls: function (testFn) {
+        var me = this,
+            old = me.childEls,
+            keepers = (me.childEls = []),
+            n, i, cel;
 
-        return this;
+        for (i = 0, n = old.length; i < n; ++i) {
+            cel = old[i];
+            if (!testFn(cel)) {
+                keepers.push(cel);
+            }
+        }
     },
 
     /**
-     * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.
-     * @param {Number} index The index within the collection of the item to remove.
-     * @return {Object} The item removed or false if no item was removed.
+     * Sets references to elements inside the component. This applies {@link #renderSelectors}
+     * as well as {@link #childEls}.
+     * @private
      */
-    removeAt : function(index){
+    applyRenderSelectors: function() {
         var me = this,
-            o,
-            key;
+            childEls = me.childEls,
+            selectors = me.renderSelectors,
+            el = me.el,
+            dom = el.dom,
+            baseId, childName, childId, i, selector;
+
+        if (childEls) {
+            baseId = me.id + '-';
+            for (i = childEls.length; i--; ) {
+                childName = childId = childEls[i];
+                if (typeof(childName) != 'string') {
+                    childId = childName.id || (baseId + childName.itemId);
+                    childName = childName.name;
+                } else {
+                    childId = baseId + childId;
+                }
 
-        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];
+                // We don't use Ext.get because that is 3x (or more) slower on IE6-8. Since
+                // we know the el's are children of our el we use getById instead:
+                me[childName] = el.getById(childId);
+            }
+        }
+
+        // We still support renderSelectors. There are a few places in the framework that
+        // need them and they are a documented part of the API. In fact, we support mixing
+        // childEls and renderSelectors (no reason not to).
+        if (selectors) {
+            for (selector in selectors) {
+                if (selectors.hasOwnProperty(selector) && selectors[selector]) {
+                    me[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], dom));
+                }
             }
-            Ext.Array.erase(me.keys, index, 1);
-            me.fireEvent('remove', o, key);
-            return o;
         }
-        return false;
     },
 
     /**
-     * Removed an item associated with the passed key fom the collection.
-     * @param {String} key The key of the item to remove.
-     * @return {Object} The item removed or false if no item was removed.
+     * Tests whether this Component matches the selector string.
+     * @param {String} selector The selector string to test against.
+     * @return {Boolean} True if this Component matches the selector.
      */
-    removeAtKey : function(key){
-        return this.removeAt(this.indexOfKey(key));
+    is: function(selector) {
+        return Ext.ComponentQuery.is(this, selector);
     },
 
     /**
-     * Returns the number of items in the collection.
-     * @return {Number} the number of items in the collection.
+     * Walks up the `ownerCt` axis looking for an ancestor Container which matches the passed simple selector.
+     *
+     * Example:
+     *
+     *     var owningTabPanel = grid.up('tabpanel');
+     *
+     * @param {String} [selector] The simple selector to test.
+     * @return {Ext.container.Container} The matching ancestor Container (or `undefined` if no match was found).
      */
-    getCount : function(){
-        return this.length;
+    up: function(selector) {
+        var result = this.ownerCt;
+        if (selector) {
+            for (; result; result = result.ownerCt) {
+                if (Ext.ComponentQuery.is(result, selector)) {
+                    return result;
+                }
+            }
+        }
+        return result;
     },
 
     /**
-     * Returns index within the collection of the passed Object.
-     * @param {Object} o The item to find the index of.
-     * @return {Number} index of the item. Returns -1 if not found.
+     * Returns the next sibling of this Component.
+     *
+     * Optionally selects the next sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector.
+     *
+     * May also be refered to as **`next()`**
+     *
+     * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with
+     * {@link #nextNode}
+     * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following items.
+     * @return {Ext.Component} The next sibling (or the next sibling which matches the selector).
+     * Returns null if there is no matching sibling.
      */
-    indexOf : function(o){
-        return Ext.Array.indexOf(this.items, o);
+    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;
     },
 
     /**
-     * Returns index within the collection of the passed key.
-     * @param {String} key The key to find the index of.
-     * @return {Number} index of the key.
+     * Returns the previous sibling of this Component.
+     *
+     * Optionally selects the previous sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery}
+     * selector.
+     *
+     * May also be refered to as **`prev()`**
+     *
+     * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with
+     * {@link #previousNode}
+     * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding items.
+     * @return {Ext.Component} The previous sibling (or the previous sibling which matches the selector).
+     * Returns null if there is no matching sibling.
      */
-    indexOfKey : function(key){
-        return Ext.Array.indexOf(this.keys, key);
+    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;
     },
 
     /**
-     * Returns the item associated with the passed key OR index.
-     * Key has priority over index.  This is the equivalent
-     * of calling {@link #key} first, then if nothing matched calling {@link #getAt}.
-     * @param {String/Number} key The key or index of the item.
-     * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.
-     * If an item was found, but is a Class, returns <tt>null</tt>.
+     * Returns the previous node in the Component tree in tree traversal order.
+     *
+     * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the
+     * tree in reverse order to attempt to find a match. Contrast with {@link #previousSibling}.
+     * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding nodes.
+     * @return {Ext.Component} The previous node (or the previous node which matches the selector).
+     * Returns null if there is no matching node.
      */
-    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; // for prototype!
-    },
+    previousNode: function(selector, includeSelf) {
+        var node = this,
+            result,
+            it, len, i;
 
-    /**
-     * Returns the item at the specified index.
-     * @param {Number} index The index of the item.
-     * @return {Object} The item at the specified index.
-     */
-    getAt : function(index) {
-        return this.items[index];
+        // If asked to include self, test me
+        if (includeSelf && node.is(selector)) {
+            return node;
+        }
+
+        result = this.prev(selector);
+        if (result) {
+            return result;
+        }
+
+        if (node.ownerCt) {
+            for (it = node.ownerCt.items.items, i = Ext.Array.indexOf(it, node) - 1; i > -1; i--) {
+                if (it[i].query) {
+                    result = it[i].query(selector);
+                    result = result[result.length - 1];
+                    if (result) {
+                        return result;
+                    }
+                }
+            }
+            return node.ownerCt.previousNode(selector, true);
+        }
     },
 
     /**
-     * Returns the item associated with the passed key.
-     * @param {String/Number} key The key of the item.
-     * @return {Object} The item associated with the passed key.
+     * Returns the next node in the Component tree in tree traversal order.
+     *
+     * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the
+     * tree to attempt to find a match. Contrast with {@link #nextSibling}.
+     * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following nodes.
+     * @return {Ext.Component} The next node (or the next node which matches the selector).
+     * Returns null if there is no matching node.
      */
-    getByKey : function(key) {
-        return this.map[key];
+    nextNode: function(selector, includeSelf) {
+        var node = this,
+            result,
+            it, len, i;
+
+        // If asked to include self, test me
+        if (includeSelf && node.is(selector)) {
+            return node;
+        }
+
+        result = this.next(selector);
+        if (result) {
+            return result;
+        }
+
+        if (node.ownerCt) {
+            for (it = node.ownerCt.items, i = it.indexOf(node) + 1, it = it.items, len = it.length; i < len; i++) {
+                if (it[i].down) {
+                    result = it[i].down(selector);
+                    if (result) {
+                        return result;
+                    }
+                }
+            }
+            return node.ownerCt.nextNode(selector);
+        }
     },
 
     /**
-     * Returns true if the collection contains the passed Object as an item.
-     * @param {Object} o  The Object to look for in the collection.
-     * @return {Boolean} True if the collection contains the Object as an item.
+     * Retrieves the id of this component. Will autogenerate an id if one has not already been set.
+     * @return {String}
      */
-    contains : function(o){
-        return Ext.Array.contains(this.items, o);
+    getId : function() {
+        return this.id || (this.id = 'ext-comp-' + (this.getAutoId()));
     },
 
-    /**
-     * Returns true if the collection contains the passed Object as a key.
-     * @param {String} key The key to look for in the collection.
-     * @return {Boolean} True if the collection contains the Object as a key.
-     */
-    containsKey : function(key){
-        return typeof this.map[key] != 'undefined';
+    getItemId : function() {
+        return this.itemId || this.id;
     },
 
     /**
-     * Removes all items from the collection.  Fires the {@link #clear} event when complete.
+     * Retrieves the top level element representing this component.
+     * @return {Ext.core.Element}
      */
-    clear : function(){
-        var me = this;
-
-        me.length = 0;
-        me.items = [];
-        me.keys = [];
-        me.map = {};
-        me.fireEvent('clear');
+    getEl : function() {
+        return this.el;
     },
 
     /**
-     * Returns the first item in the collection.
-     * @return {Object} the first item in the collection..
+     * This is used to determine where to insert the 'html', 'contentEl' and 'items' in this component.
+     * @private
      */
-    first : function() {
-        return this.items[0];
+    getTargetEl: function() {
+        return this.frameBody || this.el;
     },
 
     /**
-     * Returns the last item in the collection.
-     * @return {Object} the last item in the collection..
+     * Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
+     * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).
+     *
+     * **If using your own subclasses, be aware that a Component must register its own xtype to participate in
+     * determination of inherited xtypes.**
+     *
+     * For a list of all available xtypes, see the {@link Ext.Component} header.
+     *
+     * Example usage:
+     *
+     *     var t = new Ext.form.field.Text();
+     *     var isText = t.isXType('textfield');        // true
+     *     var isBoxSubclass = t.isXType('field');       // true, descended from Ext.form.field.Base
+     *     var isBoxInstance = t.isXType('field', true); // false, not a direct Ext.form.field.Base instance
+     *
+     * @param {String} xtype The xtype to check for this Component
+     * @param {Boolean} [shallow=false] True to check whether this Component is directly of the specified xtype, false to
+     * check whether this Component is descended from the xtype.
+     * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
      */
-    last : function() {
-        return this.items[this.length - 1];
+    isXType: function(xtype, shallow) {
+        //assume a string by default
+        if (Ext.isFunction(xtype)) {
+            xtype = xtype.xtype;
+            //handle being passed the class, e.g. Ext.Component
+        } else if (Ext.isObject(xtype)) {
+            xtype = xtype.statics().xtype;
+            //handle being passed an instance
+        }
+
+        return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1: this.self.xtype == xtype;
     },
 
     /**
-     * Collects all of the values of the given property and returns their sum
-     * @param {String} property The property to sum by
-     * @param {String} root Optional 'root' property to extract the first argument from. This is used mainly when
-     * summing fields in records, where the fields are all stored inside the 'data' object
-     * @param {Number} start (optional) The record index to start at (defaults to <tt>0</tt>)
-     * @param {Number} end (optional) The record index to end at (defaults to <tt>-1</tt>)
-     * @return {Number} The total
+     * Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all available xtypes, see the
+     * {@link Ext.Component} header.
+     *
+     * **If using your own subclasses, be aware that a Component must register its own xtype to participate in
+     * determination of inherited xtypes.**
+     *
+     * Example usage:
+     *
+     *     var t = new Ext.form.field.Text();
+     *     alert(t.getXTypes());  // alerts 'component/field/textfield'
+     *
+     * @return {String} The xtype hierarchy string
      */
-    sum: function(property, root, start, end) {
-        var values = this.extractValues(property, root),
-            length = values.length,
-            sum    = 0,
-            i;
+    getXTypes: function() {
+        var self = this.self,
+            xtypes, parentPrototype, parentXtypes;
 
-        start = start || 0;
-        end   = (end || end === 0) ? end : length - 1;
+        if (!self.xtypes) {
+            xtypes = [];
+            parentPrototype = this;
 
-        for (i = start; i <= end; i++) {
-            sum += values[i];
+            while (parentPrototype) {
+                parentXtypes = parentPrototype.xtypes;
+
+                if (parentXtypes !== undefined) {
+                    xtypes.unshift.apply(xtypes, parentXtypes);
+                }
+
+                parentPrototype = parentPrototype.superclass;
+            }
+
+            self.xtypeChain = xtypes;
+            self.xtypes = xtypes.join('/');
         }
 
-        return sum;
+        return self.xtypes;
     },
 
     /**
-     * Collects unique values of a particular property in this MixedCollection
-     * @param {String} property The property to collect on
-     * @param {String} root Optional 'root' property to extract the first argument from. This is used mainly when
-     * summing fields in records, where the fields are all stored inside the 'data' object
-     * @param {Boolean} allowBlank (optional) Pass true to allow null, undefined or empty string values
-     * @return {Array} The unique values
+     * Update the content area of a component.
+     * @param {String/Object} htmlOrData If this component has been configured with a template via the tpl config then
+     * it will use this argument as data to populate the template. If this component was not configured with a template,
+     * the components content area will be updated via Ext.Element update
+     * @param {Boolean} [loadScripts=false] Only legitimate when using the html configuration.
+     * @param {Function} [callback] Only legitimate when using the html configuration. Callback to execute when
+     * scripts have finished loading
      */
-    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);
+    update : function(htmlOrData, loadScripts, cb) {
+        var me = this;
 
-            if ((allowNull || !Ext.isEmpty(value)) && !hits[strValue]) {
-                hits[strValue] = true;
-                unique.push(value);
+        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);
             }
         }
 
-        return unique;
+        if (me.rendered) {
+            me.doComponentLayout();
+        }
     },
 
     /**
-     * @private
-     * Extracts all of the given property values from the items in the MC. Mainly used as a supporting method for
-     * functions like sum and collect.
-     * @param {String} property The property to extract
-     * @param {String} root Optional 'root' property to extract the first argument from. This is used mainly when
-     * extracting field data from Model instances, where the fields are stored inside the 'data' object
-     * @return {Array} The extracted values
+     * Convenience function to hide or show this component by boolean.
+     * @param {Boolean} visible True to show, false to hide
+     * @return {Ext.Component} this
      */
-    extractValues: function(property, root) {
-        var values = this.items;
-
-        if (root) {
-            values = Ext.Array.pluck(values, root);
-        }
-
-        return Ext.Array.pluck(values, property);
+    setVisible : function(visible) {
+        return this[visible ? 'show': 'hide']();
     },
 
     /**
-     * Returns a range of items in this collection
-     * @param {Number} startIndex (optional) The starting index. Defaults to 0.
-     * @param {Number} endIndex (optional) The ending index. Defaults to the last item.
-     * @return {Array} An array of items
+     * Returns true if this component is visible.
+     *
+     * @param {Boolean} [deep=false] Pass `true` to interrogate the visibility status of all parent Containers to
+     * determine whether this Component is truly visible to the user.
+     *
+     * Generally, to determine whether a Component is hidden, the no argument form is needed. For example when creating
+     * dynamically laid out UIs in a hidden Container before showing them.
+     *
+     * @return {Boolean} True if this component is visible, false otherwise.
      */
-    getRange : function(start, end){
+    isVisible: function(deep) {
         var me = this,
-            items = me.items,
-            range = [],
-            i;
+            child = me,
+            visible = !me.hidden,
+            ancestor = me.ownerCt;
 
-        if (items.length < 1) {
-            return range;
+        // Clear hiddenOwnerCt property
+        me.hiddenAncestor = false;
+        if (me.destroyed) {
+            return false;
         }
 
-        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];
+        if (deep && visible && me.rendered && ancestor) {
+            while (ancestor) {
+                // If any ancestor is hidden, then this is hidden.
+                // If an ancestor Panel (only Panels have a collapse method) is collapsed,
+                // then its layoutTarget (body) is hidden, so this is hidden unless its within a
+                // docked item; they are still visible when collapsed (Unless they themseves are hidden)
+                if (ancestor.hidden || (ancestor.collapsed &&
+                        !(ancestor.getDockedItems && Ext.Array.contains(ancestor.getDockedItems(), child)))) {
+                    // Store hiddenOwnerCt property if needed
+                    me.hiddenAncestor = ancestor;
+                    visible = false;
+                    break;
+                }
+                child = ancestor;
+                ancestor = ancestor.ownerCt;
             }
         }
-        return range;
+        return visible;
     },
 
     /**
-     * <p>Filters the objects in this collection by a set of {@link Ext.util.Filter Filter}s, or by a single
-     * property/value pair with optional parameters for substring matching and case sensitivity. See
-     * {@link Ext.util.Filter Filter} for an example of using Filter objects (preferred). Alternatively,
-     * MixedCollection can be easily filtered by property like this:</p>
-<pre><code>
-//create a simple store with a few people defined
-var people = new Ext.util.MixedCollection();
-people.addAll([
-    {id: 1, age: 25, name: 'Ed'},
-    {id: 2, age: 24, name: 'Tommy'},
-    {id: 3, age: 24, name: 'Arne'},
-    {id: 4, age: 26, name: 'Aaron'}
-]);
-
-//a new MixedCollection containing only the items where age == 24
-var middleAged = people.filter('age', 24);
-</code></pre>
-     *
-     *
-     * @param {Array/String} property A property on your objects, or an array of {@link Ext.util.Filter Filter} objects
-     * @param {String/RegExp} value Either string that the property values
-     * should start with or a RegExp to test against the property
-     * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
-     * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).
-     * @return {MixedCollection} The new filtered collection
+     * Enable the component
+     * @param {Boolean} [silent=false] Passing true will supress the 'enable' event from being fired.
      */
-    filter : function(property, value, anyMatch, caseSensitive) {
-        var filters = [],
-            filterFn;
+    enable: function(silent) {
+        var me = this;
 
-        //support for the simple case of filtering by property/value
-        if (Ext.isString(property)) {
-            filters.push(Ext.create('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);
+        if (me.rendered) {
+            me.el.removeCls(me.disabledCls);
+            me.el.dom.disabled = false;
+            me.onEnable();
         }
 
-        //at this point we have an array of zero or more Ext.util.Filter objects to filter with,
-        //so here we construct a function that combines these filters by ANDing them together
-        filterFn = function(record) {
-            var isMatch = true,
-                length = filters.length,
-                i;
-
-            for (i = 0; i < length; i++) {
-                var filter = filters[i],
-                    fn     = filter.filterFn,
-                    scope  = filter.scope;
-
-                isMatch = isMatch && fn.call(scope, record);
-            }
+        me.disabled = false;
 
-            return isMatch;
-        };
+        if (silent !== true) {
+            me.fireEvent('enable', me);
+        }
 
-        return this.filterBy(filterFn);
+        return me;
     },
 
     /**
-     * Filter by a function. Returns a <i>new</i> collection that has been filtered.
-     * The passed function will be called with each object in the collection.
-     * If the function returns true, the value is included otherwise it is filtered.
-     * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
-     * @return {MixedCollection} The new filtered collection
+     * Disable the component.
+     * @param {Boolean} [silent=false] Passing true will supress the 'disable' event from being fired.
      */
-    filterBy : function(fn, scope) {
-        var me = this,
-            newMC  = new this.self(),
-            keys   = me.keys,
-            items  = me.items,
-            length = items.length,
-            i;
+    disable: function(silent) {
+        var me = this;
 
-        newMC.getKey = me.getKey;
+        if (me.rendered) {
+            me.el.addCls(me.disabledCls);
+            me.el.dom.disabled = true;
+            me.onDisable();
+        }
 
-        for (i = 0; i < length; i++) {
-            if (fn.call(scope || me, items[i], keys[i])) {
-                newMC.add(keys[i], items[i]);
-            }
+        me.disabled = true;
+
+        if (silent !== true) {
+            me.fireEvent('disable', me);
         }
 
-        return newMC;
+        return me;
     },
 
-    /**
-     * Finds the index of the first matching object in this collection by a specific property/value.
-     * @param {String} property The name of a property on your objects.
-     * @param {String/RegExp} value A string that the property values
-     * should start with or a RegExp to test against the property.
-     * @param {Number} start (optional) The index to start searching at (defaults to 0).
-     * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.
-     * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.
-     * @return {Number} The matched index or -1
-     */
-    findIndex : function(property, value, start, anyMatch, caseSensitive){
-        if(Ext.isEmpty(value, false)){
-            return -1;
+    // @private
+    onEnable: function() {
+        if (this.maskOnDisable) {
+            this.el.unmask();
         }
-        value = this.createValueMatcher(value, anyMatch, caseSensitive);
-        return this.findIndexBy(function(o){
-            return o && value.test(o[property]);
-        }, null, start);
     },
 
-    /**
-     * Find the index of the first matching object in this collection by a function.
-     * If the function returns <i>true</i> it is considered a match.
-     * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
-     * @param {Number} start (optional) The index to start searching at (defaults to 0).
-     * @return {Number} The matched index or -1
-     */
-    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;
-            }
+    // @private
+    onDisable : function() {
+        if (this.maskOnDisable) {
+            this.el.mask();
         }
-        return -1;
     },
 
     /**
-     * Returns a regular expression based on the given value and matching options. This is used internally for finding and filtering,
-     * and by Ext.data.Store#filter
-     * @private
-     * @param {String} value The value to create the regex for. This is escaped using Ext.escapeRe
-     * @param {Boolean} anyMatch True to allow any match - no regex start/end line anchors will be added. Defaults to false
-     * @param {Boolean} caseSensitive True to make the regex case sensitive (adds 'i' switch to regex). Defaults to false.
-     * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false. Ignored if anyMatch is true.
+     * Method to determine whether this Component is currently disabled.
+     * @return {Boolean} the disabled state of this Component.
      */
-    createValueMatcher : function(value, anyMatch, caseSensitive, exactMatch) {
-        if (!value.exec) { // not a regex
-            var er = Ext.String.escapeRegex;
-            value = String(value);
+    isDisabled : function() {
+        return this.disabled;
+    },
 
-            if (anyMatch === true) {
-                value = er(value);
-            } else {
-                value = '^' + er(value);
-                if (exactMatch === true) {
-                    value += '$';
-                }
-            }
-            value = new RegExp(value, caseSensitive ? '' : 'i');
-        }
-        return value;
+    /**
+     * Enable or disable the component.
+     * @param {Boolean} disabled True to disable.
+     */
+    setDisabled : function(disabled) {
+        return this[disabled ? 'disable': 'enable']();
     },
 
     /**
-     * Creates a shallow copy of this collection
-     * @return {MixedCollection}
+     * Method to determine whether this Component is currently set to hidden.
+     * @return {Boolean} the hidden state of this Component.
      */
-    clone : function() {
-        var me = this,
-            copy = new this.self(),
-            keys = me.keys,
-            items = me.items,
-            i = 0,
-            len = items.length;
+    isHidden : function() {
+        return this.hidden;
+    },
 
-        for(; i < len; i++){
-            copy.add(keys[i], items[i]);
-        }
-        copy.getKey = me.getKey;
-        return copy;
-    }
-});
-
-/**
- * @class Ext.util.Sortable
-
-A mixin which allows a data component to be sorted. This is used by e.g. {@link Ext.data.Store} and {@link Ext.data.TreeStore}.
-
-**NOTE**: This mixin is mainly for internal library use and most users should not need to use it directly. It
-is more likely you will want to use one of the component classes that import this mixin, such as
-{@link Ext.data.Store} or {@link Ext.data.TreeStore}.
- * @markdown
- * @docauthor Tommy Maintz <tommy@sencha.com>
- */
-Ext.define("Ext.util.Sortable", {
-    /**
-     * @property isSortable
-     * @type Boolean
-     * Flag denoting that this object is sortable. Always true.
-     */
-    isSortable: true,
-    
     /**
-     * The default sort direction to use if one is not specified (defaults to "ASC")
-     * @property defaultSortDirection
-     * @type String
+     * Adds a CSS class to the top level element representing this component.
+     * @param {String} cls The CSS class name to add
+     * @return {Ext.Component} Returns the Component to allow method chaining.
      */
-    defaultSortDirection: "ASC",
-    
-    requires: [
-        'Ext.util.Sorter'
-    ],
+    addCls : function(className) {
+        var me = this;
+        if (!className) {
+            return me;
+        }
+        if (!Ext.isArray(className)){
+            className = className.replace(me.trimRe, '').split(me.spacesRe);
+        }
+        if (me.rendered) {
+            me.el.addCls(className);
+        }
+        else {
+            me.additionalCls = Ext.Array.unique(me.additionalCls.concat(className));
+        }
+        return me;
+    },
 
     /**
-     * The property in each item that contains the data to sort.
-     * @type String
-     */    
-    
-    /**
-     * Performs initialization of this mixin. Component classes using this mixin should call this method
-     * during their own initialization.
+     * Adds a CSS class to the top level element representing this component.
+     * @param {String} cls The CSS class name to add
+     * @return {Ext.Component} Returns the Component to allow method chaining.
      */
-    initSortable: function() {
-        var me = this,
-            sorters = me.sorters;
-        
-        /**
-         * The collection of {@link Ext.util.Sorter Sorters} currently applied to this Store
-         * @property sorters
-         * @type Ext.util.MixedCollection
-         */
-        me.sorters = Ext.create('Ext.util.AbstractMixedCollection', false, function(item) {
-            return item.id || item.property;
-        });
-        
-        if (sorters) {
-            me.sorters.addAll(me.decodeSorters(sorters));
-        }
+    addClass : function() {
+        return this.addCls.apply(this, arguments);
     },
 
     /**
-     * <p>Sorts the data in the Store by one or more of its properties. Example usage:</p>
-<pre><code>
-//sort by a single field
-myStore.sort('myField', 'DESC');
-
-//sorting by multiple fields
-myStore.sort([
-    {
-        property : 'age',
-        direction: 'ASC'
-    },
-    {
-        property : 'name',
-        direction: 'DESC'
-    }
-]);
-</code></pre>
-     * <p>Internally, Store converts the passed arguments into an array of {@link Ext.util.Sorter} instances, and delegates the actual
-     * sorting to its internal {@link Ext.util.MixedCollection}.</p>
-     * <p>When passing a single string argument to sort, Store maintains a ASC/DESC toggler per field, so this code:</p>
-<pre><code>
-store.sort('myField');
-store.sort('myField');
-     </code></pre>
-     * <p>Is equivalent to this code, because Store handles the toggling automatically:</p>
-<pre><code>
-store.sort('myField', 'ASC');
-store.sort('myField', 'DESC');
-</code></pre>
-     * @param {String|Array} sorters Either a string name of one of the fields in this Store's configured {@link Ext.data.Model Model},
-     * or an Array of sorter configurations.
-     * @param {String} direction The overall direction to sort the data by. Defaults to "ASC".
+     * Removes a CSS class from the top level element representing this component.
+     * @param {Object} className
+     * @return {Ext.Component} Returns the Component to allow method chaining.
      */
-    sort: function(sorters, direction, where, doSort) {
-        var me = this,
-            sorter, sorterFn,
-            newSorters;
-        
-        if (Ext.isArray(sorters)) {
-            doSort = where;
-            where = direction;
-            newSorters = sorters;
+    removeCls : function(className) {
+        var me = this;
+
+        if (!className) {
+            return me;
         }
-        else if (Ext.isObject(sorters)) {
-            doSort = where;
-            where = direction;
-            newSorters = [sorters];
+        if (!Ext.isArray(className)){
+            className = className.replace(me.trimRe, '').split(me.spacesRe);
         }
-        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 (me.rendered) {
+            me.el.removeCls(className);
         }
-        
-        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);
-            }
+        else if (me.additionalCls.length) {
+            Ext.each(className, function(cls) {
+                Ext.Array.remove(me.additionalCls, cls);
+            });
         }
-        
-        if (doSort !== false) {
-            sorters = me.sorters.items;
-            if (sorters.length) {
-                //construct an amalgamated sorter function which combines all of the Sorters passed
-                sorterFn = function(r1, r2) {
-                    var result = sorters[0].sort(r1, r2),
-                        length = sorters.length,
-                        i;
-
-                        //if we have more than one sorter, OR any additional sorter functions together
-                        for (i = 1; i < length; i++) {
-                            result = result || sorters[i].sort.call(this, r1, r2);
-                        }
-
-                    return result;
-                };
+        return me;
+    },
 
-                me.doSort(sorterFn);                
-            }
+    //<debug>
+    removeClass : function() {
+        if (Ext.isDefined(Ext.global.console)) {
+            Ext.global.console.warn('Ext.Component: removeClass has been deprecated. Please use removeCls.');
         }
-        
-        return sorters;
+        return this.removeCls.apply(this, arguments);
     },
-    
-    onBeforeSort: Ext.emptyFn,
-        
-    /**
-     * @private
-     * Normalizes an array of sorter objects, ensuring that they are all Ext.util.Sorter instances
-     * @param {Array} sorters The sorters array
-     * @return {Array} Array of Ext.util.Sorter objects
-     */
-    decodeSorters: function(sorters) {
-        if (!Ext.isArray(sorters)) {
-            if (sorters === undefined) {
-                sorters = [];
-            } else {
-                sorters = [sorters];
-            }
+    //</debug>
+
+    addOverCls: function() {
+        var me = this;
+        if (!me.disabled) {
+            me.el.addCls(me.overCls);
         }
+    },
 
-        var length = sorters.length,
-            Sorter = Ext.util.Sorter,
-            fields = this.model ? this.model.prototype.fields : null,
-            field,
-            config, i;
+    removeOverCls: function() {
+        this.el.removeCls(this.overCls);
+    },
 
-        for (i = 0; i < length; i++) {
-            config = sorters[i];
+    addListener : function(element, listeners, scope, options) {
+        var me = this,
+            fn,
+            option;
 
-            if (!(config instanceof Sorter)) {
-                if (Ext.isString(config)) {
-                    config = {
-                        property: config
-                    };
+        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;
                 }
-                
-                Ext.applyIf(config, {
-                    root     : this.sortRoot,
-                    direction: "ASC"
-                });
 
-                //support for 3.x style sorters where a function can be defined as 'fn'
-                if (config.fn) {
-                    config.sorterFn = config.fn;
+                for (option in options) {
+                    if (options.hasOwnProperty(option)) {
+                        if (me.eventOptionsRe.test(option)) {
+                            listeners[option] = options[option];
+                        }
+                    }
                 }
+            }
 
-                //support a function to be passed as a sorter definition
-                if (typeof config == 'function') {
-                    config = {
-                        sorterFn: config
-                    };
+            // At this point we have a variable called element,
+            // and a listeners object that can be passed to on
+            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);
+            }
+        }
 
-                // ensure sortType gets pushed on if necessary
-                if (fields && !config.transform) {
-                    field = fields.get(config.property);
-                    config.transform = field ? field.sortType : undefined;
+        return me.mixins.observable.addListener.apply(me, arguments);
+    },
+
+    // inherit docs
+    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);
+                    }
                 }
-                sorters[i] = Ext.create('Ext.util.Sorter', config);
             }
+        } else {
+            return me.mixins.observable.removeManagedListenerItem.apply(me, arguments);
         }
+    },
 
-        return sorters;
+    /**
+     * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
+     * @return {Ext.container.Container} the Container which owns this Component.
+     */
+    getBubbleTarget : function() {
+        return this.ownerCt;
     },
-    
-    getSorters: function() {
-        return this.sorters.items;
-    }
-});
-/**
- * @class Ext.util.MixedCollection
- * <p>
- * Represents a collection of a set of key and value pairs. Each key in the MixedCollection
- * must be unique, the same key cannot exist twice. This collection is ordered, items in the
- * collection can be accessed by index  or via the key. Newly added items are added to
- * the end of the collection. This class is similar to {@link Ext.util.HashMap} however it
- * is heavier and provides more functionality. Sample usage:
- * <pre><code>
-var coll = new Ext.util.MixedCollection();
-coll.add('key1', 'val1');
-coll.add('key2', 'val2');
-coll.add('key3', 'val3');
 
-console.log(coll.get('key1')); // prints 'val1'
-console.log(coll.indexOfKey('key3')); // prints 2
- * </code></pre>
- *
- * <p>
- * The MixedCollection also has support for sorting and filtering of the values in the collection.
- * <pre><code>
-var coll = new Ext.util.MixedCollection();
-coll.add('key1', 100);
-coll.add('key2', -100);
-coll.add('key3', 17);
-coll.add('key4', 0);
-var biggerThanZero = coll.filterBy(function(value){
-    return value > 0;
-});
-console.log(biggerThanZero.getCount()); // prints 2
- * </code></pre>
- * </p>
- */
-Ext.define('Ext.util.MixedCollection', {
-    extend: 'Ext.util.AbstractMixedCollection',
-    mixins: {
-        sortable: 'Ext.util.Sortable'
+    /**
+     * Method to determine whether this Component is floating.
+     * @return {Boolean} the floating state of this component.
+     */
+    isFloating : function() {
+        return this.floating;
     },
 
     /**
-     * Creates new MixedCollection.
-     * @param {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
-     * function should add function references to the collection. Defaults to
-     * <tt>false</tt>.
-     * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
-     * and return the key value for that item.  This is used when available to look up the key on items that
-     * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
-     * equivalent to providing an implementation for the {@link #getKey} method.
+     * Method to determine whether this Component is draggable.
+     * @return {Boolean} the draggable state of this component.
      */
-    constructor: function() {
-        var me = this;
-        me.callParent(arguments);
-        me.addEvents('sort');
-        me.mixins.sortable.initSortable.call(me);
+    isDraggable : function() {
+        return !!this.draggable;
     },
 
-    doSort: function(sorterFn) {
-        this.sortBy(sorterFn);
+    /**
+     * Method to determine whether this Component is droppable.
+     * @return {Boolean} the droppable state of this component.
+     */
+    isDroppable : function() {
+        return !!this.droppable;
     },
 
     /**
      * @private
-     * Performs the actual sorting based on a direction and a sorting function. Internally,
-     * this creates a temporary array of all items in the MixedCollection, sorts it and then writes
-     * the sorted array data back into this.items and this.keys
-     * @param {String} property Property to sort by ('key', 'value', or 'index')
-     * @param {String} dir (optional) Direction to sort 'ASC' or 'DESC'. Defaults to 'ASC'.
-     * @param {Function} fn (optional) Comparison function that defines the sort order.
-     * Defaults to sorting by numeric value.
+     * Method to manage awareness of when components are added to their
+     * respective Container, firing an added event.
+     * References are established at add time rather than at render time.
+     * @param {Ext.container.Container} container Container which holds the component
+     * @param {Number} pos Position at which the component was added
      */
-    _sort : function(property, dir, fn){
-        var me = this,
-            i, len,
-            dsc   = String(dir).toUpperCase() == 'DESC' ? -1 : 1,
+    onAdded : function(container, pos) {
+        this.ownerCt = container;
+        this.fireEvent('added', this, container, pos);
+    },
 
-            //this is a temporary array used to apply the sorting function
-            c     = [],
-            keys  = me.keys,
-            items = me.items;
+    /**
+     * @private
+     * Method to manage awareness of when components are removed from their
+     * respective Container, firing an removed event. References are properly
+     * cleaned up after removing a component from its owning container.
+     */
+    onRemoved : function() {
+        var me = this;
 
-        //default to a simple sorter function if one is not provided
-        fn = fn || function(a, b) {
-            return a - b;
-        };
+        me.fireEvent('removed', me, me.ownerCt);
+        delete me.ownerCt;
+    },
 
-        //copy all the items into a temporary array, which we will sort
-        for(i = 0, len = items.length; i < len; i++){
-            c[c.length] = {
-                key  : keys[i],
-                value: items[i],
-                index: i
-            };
-        }
+    // @private
+    beforeDestroy : Ext.emptyFn,
+    // @private
+    // @private
+    onResize : Ext.emptyFn,
 
-        //sort the temporary array
-        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;
-        });
+    /**
+     * Sets the width and height of this Component. This method fires the {@link #resize} event. This method can accept
+     * either width and height as separate arguments, or you can pass a size object like `{width:10, height:20}`.
+     *
+     * @param {Number/String/Object} width The new width to set. This may be one of:
+     *
+     *   - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
+     *   - A String used to set the CSS width style.
+     *   - A size object in the format `{width: widthValue, height: heightValue}`.
+     *   - `undefined` to leave the width unchanged.
+     *
+     * @param {Number/String} height The new height to set (not required if a size object is passed as the first arg).
+     * This may be one of:
+     *
+     *   - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
+     *   - A String used to set the CSS height style. Animation may **not** be used.
+     *   - `undefined` to leave the height unchanged.
+     *
+     * @return {Ext.Component} this
+     */
+    setSize : function(width, height) {
+        var me = this,
+            layoutCollection;
 
-        //copy the temporary array back into the main this.items and this.keys objects
-        for(i = 0, len = c.length; i < len; i++){
-            items[i] = c[i].value;
-            keys[i]  = c[i].key;
+        // support for standard size objects
+        if (Ext.isObject(width)) {
+            height = width.height;
+            width  = width.width;
         }
 
-        me.fireEvent('sort', me);
-    },
-
-    /**
-     * Sorts the collection by a single sorter function
-     * @param {Function} sorterFn The function to sort by
-     */
-    sortBy: function(sorterFn) {
-        var me     = this,
-            items  = me.items,
-            keys   = me.keys,
-            length = items.length,
-            temp   = [],
-            i;
+        // Constrain within configured maxima
+        if (Ext.isNumber(width)) {
+            width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
+        }
+        if (Ext.isNumber(height)) {
+            height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
+        }
 
-        //first we create a copy of the items array so that we can sort it
-        for (i = 0; i < length; i++) {
-            temp[i] = {
-                key  : keys[i],
-                value: items[i],
-                index: i
+        if (!me.rendered || !me.isVisible()) {
+            // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
+            if (me.hiddenAncestor) {
+                layoutCollection = me.hiddenAncestor.layoutOnShow;
+                layoutCollection.remove(me);
+                layoutCollection.add(me);
+            }
+            me.needsLayout = {
+                width: width,
+                height: height,
+                isSetSize: true
             };
+            if (!me.rendered) {
+                me.width  = (width !== undefined) ? width : me.width;
+                me.height = (height !== undefined) ? height : me.height;
+            }
+            return me;
         }
+        me.doComponentLayout(width, height, true);
 
-        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 me;
+    },
 
-            return v;
-        });
+    isFixedWidth: function() {
+        var me = this,
+            layoutManagedWidth = me.layoutManagedWidth;
 
-        //copy the temporary array back into the main this.items and this.keys objects
-        for (i = 0; i < length; i++) {
-            items[i] = temp[i].value;
-            keys[i]  = temp[i].key;
+        if (Ext.isDefined(me.width) || layoutManagedWidth == 1) {
+            return true;
         }
-        
-        me.fireEvent('sort', me, items, keys);
+        if (layoutManagedWidth == 2) {
+            return false;
+        }
+        return (me.ownerCt && me.ownerCt.isFixedWidth());
     },
 
-    /**
-     * Reorders each of the items based on a mapping from old index to new index. Internally this
-     * just translates into a sort. The 'sort' event is fired whenever reordering has occured.
-     * @param {Object} mapping Mapping from old item index to new item index
-     */
-    reorder: function(mapping) {
+    isFixedHeight: function() {
         var me = this,
-            items = me.items,
-            index = 0,
-            length = items.length,
-            order = [],
-            remaining = [],
-            oldIndex;
+            layoutManagedHeight = me.layoutManagedHeight;
 
-        me.suspendEvents();
+        if (Ext.isDefined(me.height) || layoutManagedHeight == 1) {
+            return true;
+        }
+        if (layoutManagedHeight == 2) {
+            return false;
+        }
+        return (me.ownerCt && me.ownerCt.isFixedHeight());
+    },
 
-        //object of {oldPosition: newPosition} reversed to {newPosition: oldPosition}
-        for (oldIndex in mapping) {
-            order[mapping[oldIndex]] = items[oldIndex];
+    setCalculatedSize : function(width, height, callingContainer) {
+        var me = this,
+            layoutCollection;
+
+        // support for standard size objects
+        if (Ext.isObject(width)) {
+            callingContainer = width.ownerCt;
+            height = width.height;
+            width  = width.width;
         }
 
-        for (index = 0; index < length; index++) {
-            if (mapping[index] == undefined) {
-                remaining.push(items[index]);
-            }
+        // Constrain within configured maxima
+        if (Ext.isNumber(width)) {
+            width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
+        }
+        if (Ext.isNumber(height)) {
+            height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
         }
 
-        for (index = 0; index < length; index++) {
-            if (order[index] == undefined) {
-                order[index] = remaining.shift();
+        if (!me.rendered || !me.isVisible()) {
+            // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
+            if (me.hiddenAncestor) {
+                layoutCollection = me.hiddenAncestor.layoutOnShow;
+                layoutCollection.remove(me);
+                layoutCollection.add(me);
             }
+            me.needsLayout = {
+                width: width,
+                height: height,
+                isSetSize: false,
+                ownerCt: callingContainer
+            };
+            return me;
         }
+        me.doComponentLayout(width, height, false, callingContainer);
 
-        me.clear();
-        me.addAll(order);
-
-        me.resumeEvents();
-        me.fireEvent('sort', me);
+        return me;
     },
 
     /**
-     * Sorts this collection by <b>key</b>s.
-     * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.
-     * @param {Function} fn (optional) Comparison function that defines the sort order.
-     * Defaults to sorting by case insensitive string.
+     * This method needs to be called whenever you change something on this component that requires the Component's
+     * layout to be recalculated.
+     * @param {Object} width
+     * @param {Object} height
+     * @param {Object} isSetSize
+     * @param {Object} callingContainer
+     * @return {Ext.container.Container} this
      */
-    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);
-        });
-    }
-});
+    doComponentLayout : function(width, height, isSetSize, callingContainer) {
+        var me = this,
+            componentLayout = me.getComponentLayout(),
+            lastComponentSize = componentLayout.lastComponentSize || {
+                width: undefined,
+                height: undefined
+            };
 
-/**
- * @class Ext.data.StoreManager
- * @extends Ext.util.MixedCollection
- * <p>Contains a collection of all stores that are created that have an identifier.
- * An identifier can be assigned by setting the {@link Ext.data.AbstractStore#storeId storeId} 
- * property. When a store is in the StoreManager, it can be referred to via it's identifier:
- * <pre><code>
-Ext.create('Ext.data.Store', {
-    model: 'SomeModel',
-    storeId: 'myStore'
-});
+        // collapsed state is not relevant here, so no testing done.
+        // Only Panels have a collapse method, and that just sets the width/height such that only
+        // a single docked Header parallel to the collapseTo side are visible, and the Panel body is hidden.
+        if (me.rendered && componentLayout) {
+            // If no width passed, then only insert a value if the Component is NOT ALLOWED to autowidth itself.
+            if (!Ext.isDefined(width)) {
+                if (me.isFixedWidth()) {
+                    width = Ext.isDefined(me.width) ? me.width : lastComponentSize.width;
+                }
+            }
+            // If no height passed, then only insert a value if the Component is NOT ALLOWED to autoheight itself.
+            if (!Ext.isDefined(height)) {
+                if (me.isFixedHeight()) {
+                    height = Ext.isDefined(me.height) ? me.height : lastComponentSize.height;
+                }
+            }
 
-var store = Ext.data.StoreManager.lookup('myStore');
- * </code></pre>
- * Also note that the {@link #lookup} method is aliased to {@link Ext#getStore} for convenience.</p>
- * <p>
- * If a store is registered with the StoreManager, you can also refer to the store by it's identifier when
- * registering it with any Component that consumes data from a store:
- * <pre><code>
-Ext.create('Ext.data.Store', {
-    model: 'SomeModel',
-    storeId: 'myStore'
-});
+            if (isSetSize) {
+                me.width = width;
+                me.height = height;
+            }
 
-Ext.create('Ext.view.View', {
-    store: 'myStore',
-    // other configuration here
-});
- * </code></pre>
- * </p>
- * @singleton
- * @docauthor Evan Trimboli <evan@sencha.com>
- * TODO: Make this an AbstractMgr
- */
-Ext.define('Ext.data.StoreManager', {
-    extend: 'Ext.util.MixedCollection',
-    alternateClassName: ['Ext.StoreMgr', 'Ext.data.StoreMgr', 'Ext.StoreManager'],
-    singleton: true,
-    uses: ['Ext.data.ArrayStore'],
-    
-    /**
-     * @cfg {Object} listeners @hide
-     */
+            componentLayout.layout(width, height, isSetSize, callingContainer);
+        }
+
+        return me;
+    },
 
     /**
-     * Registers one or more Stores with the StoreManager. You do not normally need to register stores
-     * manually.  Any store initialized with a {@link Ext.data.Store#storeId} will be auto-registered. 
-     * @param {Ext.data.Store} store1 A Store instance
-     * @param {Ext.data.Store} store2 (optional)
-     * @param {Ext.data.Store} etc... (optional)
+     * Forces this component to redo its componentLayout.
      */
-    register : function() {
-        for (var i = 0, s; (s = arguments[i]); i++) {
-            this.add(s);
+    forceComponentLayout: function () {
+        this.doComponentLayout();
+    },
+
+    // @private
+    setComponentLayout : function(layout) {
+        var currentLayout = this.componentLayout;
+        if (currentLayout && currentLayout.isLayout && currentLayout != layout) {
+            currentLayout.setOwner(null);
         }
+        this.componentLayout = layout;
+        layout.setOwner(this);
     },
 
-    /**
-     * Unregisters one or more Stores with the StoreManager
-     * @param {String/Object} id1 The id of the Store, or a Store instance
-     * @param {String/Object} id2 (optional)
-     * @param {String/Object} etc... (optional)
-     */
-    unregister : function() {
-        for (var i = 0, s; (s = arguments[i]); i++) {
-            this.remove(this.lookup(s));
+    getComponentLayout : function() {
+        var me = this;
+
+        if (!me.componentLayout || !me.componentLayout.isLayout) {
+            me.setComponentLayout(Ext.layout.Layout.create(me.componentLayout, 'autocomponent'));
         }
+        return me.componentLayout;
     },
 
     /**
-     * Gets a registered Store by id
-     * @param {String/Object} id The id of the Store, or a Store instance, or a store configuration
-     * @return {Ext.data.Store}
+     * Occurs after componentLayout is run.
+     * @param {Number} adjWidth The box-adjusted width that was set
+     * @param {Number} adjHeight The box-adjusted height that was set
+     * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
+     * @param {Ext.Component} callingContainer Container requesting the layout. Only used when isSetSize is false.
      */
-    lookup : function(store) {
-        // handle the case when we are given an array or an array of arrays.
-        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 Ext.create('Ext.data.ArrayStore', {
-                data  : data,
-                fields: fields,
-                autoDestroy: true,
-                autoCreated: true,
-                expanded: expand
-            });
-        }
-        
-        if (Ext.isString(store)) {
-            // store id
-            return this.get(store);
-        } else {
-            // store instance or store config
-            return Ext.data.AbstractStore.create(store);
+    afterComponentLayout: function(width, height, isSetSize, callingContainer) {
+        var me = this,
+            layout = me.componentLayout,
+            oldSize = me.preLayoutSize;
+
+        ++me.componentLayoutCounter;
+        if (!oldSize || ((width !== oldSize.width) || (height !== oldSize.height))) {
+            me.fireEvent('resize', me, width, height);
         }
     },
 
-    // getKey implementation for MixedCollection
-    getKey : function(o) {
-         return o.storeId;
-    }
-}, function() {    
     /**
-     * <p>Creates a new store for the given id and config, then registers it with the {@link Ext.data.StoreManager Store Mananger}. 
-     * Sample usage:</p>
-    <pre><code>
-    Ext.regStore('AllUsers', {
-        model: 'User'
-    });
+     * Occurs before componentLayout is run. Returning false from this method will prevent the componentLayout from
+     * being executed.
+     * @param {Number} adjWidth The box-adjusted width that was set
+     * @param {Number} adjHeight The box-adjusted height that was set
+     * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
+     * @param {Ext.Component} callingContainer Container requesting sent the layout. Only used when isSetSize is false.
+     */
+    beforeComponentLayout: function(width, height, isSetSize, callingContainer) {
+        this.preLayoutSize = this.componentLayout.lastComponentSize;
+        return true;
+    },
 
-    //the store can now easily be used throughout the application
-    new Ext.List({
-        store: 'AllUsers',
-        ... other config
-    });
-    </code></pre>
-     * @param {String} id The id to set on the new store
-     * @param {Object} config The store config
-     * @param {Constructor} cls The new Component class.
-     * @member Ext
-     * @method regStore
+    /**
+     * Sets the left and top of the component. To set the page XY position instead, use
+     * {@link Ext.Component#setPagePosition setPagePosition}. This method fires the {@link #move} event.
+     * @param {Number} left The new left
+     * @param {Number} top The new top
+     * @return {Ext.Component} this
      */
-    Ext.regStore = function(name, config) {
-        var store;
+    setPosition : function(x, y) {
+        var me = this;
 
-        if (Ext.isObject(name)) {
-            config = name;
-        } else {
-            config.storeId = name;
+        if (Ext.isObject(x)) {
+            y = x.y;
+            x = x.x;
         }
 
-        if (config instanceof Ext.data.Store) {
-            store = config;
-        } else {
-            store = Ext.create('Ext.data.Store', config);
+        if (!me.rendered) {
+            return me;
         }
 
-        return Ext.data.StoreManager.register(store);
-    };
+        if (x !== undefined || y !== undefined) {
+            me.el.setBox(x, y);
+            me.onPosition(x, y);
+            me.fireEvent('move', me, x, y);
+        }
+        return me;
+    },
 
     /**
-     * Gets a registered Store by id (shortcut to {@link Ext.data.StoreManager#lookup})
-     * @param {String/Object} id The id of the Store, or a Store instance
-     * @return {Ext.data.Store}
-     * @member Ext
-     * @method getStore
+     * @private
+     * Called after the component is moved, this method is empty by default but can be implemented by any
+     * subclass that needs to perform custom logic after a move occurs.
+     * @param {Number} x The new x position
+     * @param {Number} y The new y position
      */
-    Ext.getStore = function(name) {
-        return Ext.data.StoreManager.lookup(name);
-    };
-});
-
-/**
- * @class Ext.LoadMask
- * A simple utility class for generically masking elements while loading data.  If the {@link #store}
- * config option is specified, the masking will be automatically synchronized with the store's loading
- * process and the mask element will be cached for reuse.
- * <p>Example usage:</p>
- * <pre><code>
-// Basic mask:
-var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
-myMask.show();
-</code></pre>
-
- */
-
-Ext.define('Ext.LoadMask', {
-
-    /* Begin Definitions */
-
-    mixins: {
-        observable: 'Ext.util.Observable'
-    },
-
-    requires: ['Ext.data.StoreManager'],
-
-    /* End Definitions */
+    onPosition: Ext.emptyFn,
 
     /**
-     * @cfg {Ext.data.Store} store
-     * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
-     * hidden on either load success, or load fail.
+     * Sets the width of the component. This method fires the {@link #resize} event.
+     *
+     * @param {Number} width The new width to setThis may be one of:
+     *
+     *   - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
+     *   - A String used to set the CSS width style.
+     *
+     * @return {Ext.Component} this
      */
+    setWidth : function(width) {
+        return this.setSize(width);
+    },
 
     /**
-     * @cfg {String} msg
-     * The text to display in a centered loading message box (defaults to 'Loading...')
+     * Sets the height of the component. This method fires the {@link #resize} event.
+     *
+     * @param {Number} height The new height to set. This may be one of:
+     *
+     *   - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
+     *   - A String used to set the CSS height style.
+     *   - _undefined_ to leave the height unchanged.
+     *
+     * @return {Ext.Component} this
      */
-    msg : 'Loading...',
+    setHeight : function(height) {
+        return this.setSize(undefined, height);
+    },
+
     /**
-     * @cfg {String} msgCls
-     * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
+     * Gets the current size of the component's underlying element.
+     * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
      */
-    msgCls : Ext.baseCSSPrefix + 'mask-loading',
-    
+    getSize : function() {
+        return this.el.getSize();
+    },
+
     /**
-     * @cfg {Boolean} useMsg
-     * Whether or not to use a loading message class or simply mask the bound element.
+     * Gets the current width of the component's underlying element.
+     * @return {Number}
      */
-    useMsg: true,
+    getWidth : function() {
+        return this.el.getWidth();
+    },
 
     /**
-     * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
-     * @type Boolean
+     * Gets the current height of the component's underlying element.
+     * @return {Number}
      */
-    disabled: false,
+    getHeight : function() {
+        return this.el.getHeight();
+    },
 
     /**
-     * Creates new LoadMask.
-     * @param {Mixed} el The element, element ID, or DOM node you wish to mask.
-     * Also, may be a Component who's element you wish to mask.
-     * @param {Object} config (optional) The config object
+     * Gets the {@link Ext.ComponentLoader} for this Component.
+     * @return {Ext.ComponentLoader} The loader instance, null if it doesn't exist.
      */
-    constructor : function(el, config) {
-        var me = this;
+    getLoader: function(){
+        var me = this,
+            autoLoad = me.autoLoad ? (Ext.isObject(me.autoLoad) ? me.autoLoad : {url: me.autoLoad}) : null,
+            loader = me.loader || autoLoad;
 
-        if (el.isComponent) {
-            me.bindComponent(el);
-        } else {
-            me.el = Ext.get(el);
-        }
-        Ext.apply(me, config);
+        if (loader) {
+            if (!loader.isLoader) {
+                me.loader = Ext.create('Ext.ComponentLoader', Ext.apply({
+                    target: me,
+                    autoLoad: autoLoad
+                }, loader));
+            } else {
+                loader.setTarget(me);
+            }
+            return me.loader;
 
-        me.addEvents('beforeshow', 'show', 'hide');
-        if (me.store) {
-            me.bindStore(me.store, true);
         }
-        me.mixins.observable.constructor.call(me, config);
+        return null;
     },
 
-    bindComponent: function(comp) {
+    /**
+     * This method allows you to show or hide a LoadMask on top of this component.
+     *
+     * @param {Boolean/Object/String} load True to show the default LoadMask, a config object that will be passed to the
+     * LoadMask constructor, or a message String to show. False to hide the current LoadMask.
+     * @param {Boolean} [targetEl=false] True to mask the targetEl of this Component instead of the `this.el`. For example,
+     * setting this to true on a Panel will cause only the body to be masked.
+     * @return {Ext.LoadMask} The LoadMask instance that has just been shown.
+     */
+    setLoading : function(load, targetEl) {
         var me = this,
-            listeners = {
-                resize: me.onComponentResize,
-                scope: me
-            };
+            config;
 
-        if (comp.el) {
-            me.onComponentRender(comp);
-        } else {
-            listeners.render = {
-                fn: me.onComponentRender,
-                scope: me,
-                single: true
-            };
+        if (me.rendered) {
+            if (load !== false && !me.collapsed) {
+                if (Ext.isObject(load)) {
+                    config = load;
+                }
+                else if (Ext.isString(load)) {
+                    config = {msg: load};
+                }
+                else {
+                    config = {};
+                }
+                me.loadMask = me.loadMask || Ext.create('Ext.LoadMask', targetEl ? me.getTargetEl() : me.el, config);
+                me.loadMask.show();
+            } else if (me.loadMask) {
+                Ext.destroy(me.loadMask);
+                me.loadMask = null;
+            }
         }
-        me.mon(comp, listeners);
+
+        return me.loadMask;
     },
 
     /**
-     * @private
-     * Called if we were configured with a Component, and that Component was not yet rendered. Collects the element to mask.
+     * Sets the dock position of this component in its parent panel. Note that this only has effect if this item is part
+     * of the dockedItems collection of a parent that has a DockLayout (note that any Panel has a DockLayout by default)
+     * @param {Object} dock The dock position.
+     * @param {Boolean} [layoutParent=false] True to re-layout parent.
+     * @return {Ext.Component} this
      */
-    onComponentRender: function(comp) {
-        this.el = comp.getContentTarget();
+    setDocked : function(dock, layoutParent) {
+        var me = this;
+
+        me.dock = dock;
+        if (layoutParent && me.ownerCt && me.rendered) {
+            me.ownerCt.doComponentLayout();
+        }
+        return me;
     },
 
-    /**
-     * @private
-     * Called when this LoadMask's Component is resized. The isMasked method also re-centers any displayed message.
-     */
-    onComponentResize: function(comp, w, h) {
-        this.el.isMasked();
+    onDestroy : function() {
+        var me = this;
+
+        if (me.monitorResize && Ext.EventManager.resizeEvent) {
+            Ext.EventManager.resizeEvent.removeListener(me.setSize, me);
+        }
+        // Destroying the floatingItems ZIndexManager will also destroy descendant floating Components
+        Ext.destroy(
+            me.componentLayout,
+            me.loadMask,
+            me.floatingItems
+        );
     },
 
     /**
-     * Changes the data store bound to this LoadMask.
-     * @param {Store} store The store to bind to this LoadMask
+     * Remove any references to elements added via renderSelectors/childEls
+     * @private
      */
-    bindStore : function(store, initial) {
-        var me = this;
+    cleanElementRefs: function(){
+        var me = this,
+            i = 0,
+            childEls = me.childEls,
+            selectors = me.renderSelectors,
+            selector,
+            name,
+            len;
 
-        if (!initial && me.store) {
-            me.mun(me.store, {
-                scope: me,
-                beforeload: me.onBeforeLoad,
-                load: me.onLoad,
-                exception: me.onLoad
-            });
-            if(!store) {
-                me.store = null;
+        if (me.rendered) {
+            if (childEls) {
+                for (len = childEls.length; i < len; ++i) {
+                    name = childEls[i];
+                    if (typeof(name) != 'string') {
+                        name = name.name;
+                    }
+                    delete me[name];
+                }
             }
-        }
-        if (store) {
-            store = Ext.data.StoreManager.lookup(store);
-            me.mon(store, {
-                scope: me,
-                beforeload: me.onBeforeLoad,
-                load: me.onLoad,
-                exception: me.onLoad
-            });
 
+            if (selectors) {
+                for (selector in selectors) {
+                    if (selectors.hasOwnProperty(selector)) {
+                        delete me[selector];
+                    }
+                }
+            }
         }
-        me.store = store;
-        if (store && store.isLoading()) {
-            me.onBeforeLoad();
-        }
+        delete me.rendered;
+        delete me.el;
+        delete me.frameBody;
     },
 
     /**
-     * Disables the mask to prevent it from being displayed
+     * Destroys the Component.
      */
-    disable : function() {
+    destroy : function() {
         var me = this;
 
-       me.disabled = true;
-       if (me.loading) {
-           me.onLoad();
-       }
-    },
+        if (!me.isDestroyed) {
+            if (me.fireEvent('beforedestroy', me) !== false) {
+                me.destroying = true;
+                me.beforeDestroy();
 
-    /**
-     * Enables the mask so that it can be displayed
-     */
-    enable : function() {
-        this.disabled = false;
-    },
+                if (me.floating) {
+                    delete me.floatParent;
+                    // A zIndexManager is stamped into a *floating* Component when it is added to a Container.
+                    // If it has no zIndexManager at render time, it is assigned to the global Ext.WindowManager instance.
+                    if (me.zIndexManager) {
+                        me.zIndexManager.unregister(me);
+                    }
+                } else if (me.ownerCt && me.ownerCt.remove) {
+                    me.ownerCt.remove(me, false);
+                }
 
-    /**
-     * Method to determine whether this LoadMask is currently disabled.
-     * @return {Boolean} the disabled state of this LoadMask.
-     */
-    isDisabled : function() {
-        return this.disabled;
-    },
+                me.onDestroy();
 
-    // private
-    onLoad : function() {
-        var me = this;
+                // Attempt to destroy all plugins
+                Ext.destroy(me.plugins);
 
-        me.loading = false;
-        me.el.unmask();
-        me.fireEvent('hide', me, me.el, me.store);
-    },
+                if (me.rendered) {
+                    me.el.remove();
+                }
 
-    // private
-    onBeforeLoad : function() {
-        var me = this;
+                me.fireEvent('destroy', me);
+                Ext.ComponentManager.unregister(me);
 
-        if (!me.disabled && !me.loading && me.fireEvent('beforeshow', me, me.el, me.store) !== false) {
-            if (me.useMsg) {
-                me.el.mask(me.msg, me.msgCls, false);
-            } else {
-                me.el.mask();
+                me.mixins.state.destroy.call(me);
+
+                me.clearListeners();
+                // make sure we clean up the element references after removing all events
+                me.cleanElementRefs();
+                me.destroying = false;
+                me.isDestroyed = true;
             }
-            
-            me.fireEvent('show', me, me.el, me.store);
-            me.loading = true;
         }
     },
 
     /**
-     * Show this LoadMask over the configured Element.
+     * Retrieves a plugin by its pluginId which has been bound to this component.
+     * @param {Object} pluginId
+     * @return {Ext.AbstractPlugin} plugin instance.
      */
-    show: function() {
-        this.onBeforeLoad();
+    getPlugin: function(pluginId) {
+        var i = 0,
+            plugins = this.plugins,
+            ln = plugins.length;
+        for (; i < ln; i++) {
+            if (plugins[i].pluginId === pluginId) {
+                return plugins[i];
+            }
+        }
     },
 
     /**
-     * Hide this LoadMask.
-     */
-    hide: function() {
-        this.onLoad();
-    },
-
-    // private
-    destroy : function() {
-        this.hide();
-        this.clearListeners();
+     * Determines whether this component is the descendant of a particular container.
+     * @param {Ext.Container} container
+     * @return {Boolean} True if it is.
+     */
+    isDescendantOf: function(container) {
+        return !!this.findParentBy(function(p){
+            return p === container;
+        });
     }
+}, function() {
+    this.createAlias({
+        on: 'addListener',
+        prev: 'previousSibling',
+        next: 'nextSibling'
+    });
 });
 
 /**
- * @class Ext.ComponentLoader
- * @extends Ext.ElementLoader
- * 
- * This class is used to load content via Ajax into a {@link Ext.Component}. In general 
- * this class will not be instanced directly, rather a loader configuration will be passed to the
- * constructor of the {@link Ext.Component}.
- * 
- * ## HTML Renderer
- * By default, the content loaded will be processed as raw html. The response text
- * from the request is taken and added to the component. This can be used in
- * conjunction with the {@link #scripts} option to execute any inline scripts in
- * the resulting content. Using this renderer has the same effect as passing the
- * {@link Ext.Component#html} configuration option.
- * 
- * ## Data Renderer
- * This renderer allows content to be added by using JSON data and a {@link Ext.XTemplate}.
- * The content received from the response is passed to the {@link Ext.Component#update} method.
- * This content is run through the attached {@link Ext.Component#tpl} and the data is added to
- * the Component. Using this renderer has the same effect as using the {@link Ext.Component#data}
- * configuration in conjunction with a {@link Ext.Component#tpl}.
- * 
- * ## Component Renderer
- * This renderer can only be used with a {@link Ext.container.Container} and subclasses. It allows for
- * Components to be loaded remotely into a Container. The response is expected to be a single/series of
- * {@link Ext.Component} configuration objects. When the response is received, the data is decoded
- * and then passed to {@link Ext.container.Container#add}. Using this renderer has the same effect as specifying
- * the {@link Ext.container.Container#items} configuration on a Container. 
- * 
- * ## Custom Renderer
- * A custom function can be passed to handle any other special case, see the {@link #renderer} option.
- * 
- * ## Example Usage
- *     new Ext.Component({
- *         tpl: '{firstName} - {lastName}',
- *         loader: {
- *             url: 'myPage.php',
- *             renderer: 'data',
- *             params: {
- *                 userId: 1
- *             }
- *         }
- *     });
+ * The AbstractPlugin class is the base class from which user-implemented plugins should inherit.
+ *
+ * This class defines the essential API of plugins as used by Components by defining the following methods:
+ *
+ *   - `init` : The plugin initialization method which the owning Component calls at Component initialization time.
+ *
+ *     The Component passes itself as the sole parameter.
+ *
+ *     Subclasses should set up bidirectional links between the plugin and its client Component here.
+ *
+ *   - `destroy` : The plugin cleanup method which the owning Component calls at Component destruction time.
+ *
+ *     Use this method to break links between the plugin and the Component and to free any allocated resources.
+ *
+ *   - `enable` : The base implementation just sets the plugin's `disabled` flag to `false`
+ *
+ *   - `disable` : The base implementation just sets the plugin's `disabled` flag to `true`
  */
-Ext.define('Ext.ComponentLoader', {
-
-    /* Begin Definitions */
-    
-    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 = [];
-
-                //<debug>
-                if (!target.isContainer) {
-                    Ext.Error.raise({
-                        target: target,
-                        msg: 'Components can only be loaded into a container'
-                    });
-                }
-                //</debug>
-
-                try {
-                    items = Ext.decode(response.responseText);
-                } catch (e) {
-                    success = false;
-                }
+Ext.define('Ext.AbstractPlugin', {
+    disabled: false,
 
-                if (success) {
-                    if (active.removeAll) {
-                        target.removeAll();
-                    }
-                    target.add(items);
-                }
-                return success;
-            }
+    constructor: function(config) {
+        //<debug>
+        if (!config.cmp && Ext.global.console) {
+            Ext.global.console.warn("Attempted to attach a plugin ");
         }
+        //</debug>
+        Ext.apply(this, config);
     },
 
-    /* End Definitions */
-
-    /**
-     * @cfg {Ext.Component/String} target The target {@link Ext.Component} for the loader. Defaults to <tt>null</tt>.
-     * If a string is passed it will be looked up via the id.
-     */
-    target: null,
-
-    /**
-     * @cfg {Mixed} loadMask True or a {@link Ext.LoadMask} configuration to enable masking during loading. Defaults to <tt>false</tt>.
-     */
-    loadMask: false,
-    
-    /**
-     * @cfg {Boolean} scripts True to parse any inline script tags in the response. This only used when using the html
-     * {@link #renderer}.
-     */
-
-    /**
-     * @cfg {String/Function} renderer
-
-The type of content that is to be loaded into, which can be one of 3 types:
-
-+ **html** : Loads raw html content, see {@link Ext.Component#html}
-+ **data** : Loads raw html content, see {@link Ext.Component#data}
-+ **component** : Loads child {Ext.Component} instances. This option is only valid when used with a Container.
-
-Defaults to `html`.
-
-Alternatively, you can pass a function which is called with the following parameters.
-
-+ loader - Loader instance
-+ response - The server response
-+ active - The active request
-
-The function must return false is loading is not successful. Below is a sample of using a custom renderer:
-
-    new Ext.Component({
-        loader: {
-            url: 'myPage.php',
-            renderer: function(loader, response, active) {
-                var text = response.responseText;
-                loader.getTarget().update('The response is ' + text);
-                return true;
-            }
-        }
-    });
-     * @markdown
-     */
-    renderer: 'html',
+    getCmp: function() {
+        return this.cmp;
+    },
 
     /**
-     * Set a {Ext.Component} as the target of this loader. Note that if the target is changed,
-     * any active requests will be aborted.
-     * @param {String/Ext.Component} target The component to be the target of this loader. If a string is passed
-     * it will be looked up via its id.
+     * @method
+     * The init method is invoked after initComponent method has been run for the client Component.
+     *
+     * The supplied implementation is empty. Subclasses should perform plugin initialization, and set up bidirectional
+     * links between the plugin and its client Component in their own implementation of this method.
+     * @param {Ext.Component} client The client Component which owns this plugin.
      */
-    setTarget: function(target){
-        var me = this;
-        
-        if (Ext.isString(target)) {
-            target = Ext.getCmp(target);
-        }
+    init: Ext.emptyFn,
 
-        if (me.target && me.target != target) {
-            me.abort();
-        }
-        me.target = target;
-    },
-    
-    // inherit docs
-    removeMask: function(){
-        this.target.setLoading(false);
-    },
-    
     /**
-     * Add the mask on the target
-     * @private
-     * @param {Mixed} mask The mask configuration
+     * @method
+     * The destroy method is invoked by the owning Component at the time the Component is being destroyed.
+     *
+     * The supplied implementation is empty. Subclasses should perform plugin cleanup in their own implementation of
+     * this method.
      */
-    addMask: function(mask){
-        this.target.setLoading(mask);
-    },
+    destroy: Ext.emptyFn,
 
     /**
-     * Get the target of this loader.
-     * @return {Ext.Component} target The target, null if none exists.
+     * The base implementation just sets the plugin's `disabled` flag to `false`
+     *
+     * Plugin subclasses which need more complex processing may implement an overriding implementation.
      */
-    
-    setOptions: function(active, options){
-        active.removeAll = Ext.isDefined(options.removeAll) ? options.removeAll : this.removeAll;
+    enable: function() {
+        this.disabled = false;
     },
 
     /**
-     * Gets the renderer to use
-     * @private
-     * @param {String/Function} renderer The renderer to use
-     * @return {Function} A rendering function to use.
+     * The base implementation just sets the plugin's `disabled` flag to `true`
+     *
+     * Plugin subclasses which need more complex processing may implement an overriding implementation.
      */
-    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;
-        }
+    disable: function() {
+        this.disabled = true;
     }
 });
-
 /**
- * @class Ext.layout.component.Auto
- * @extends Ext.layout.component.Component
- * @private
+ * The Connection class encapsulates a connection to the page's originating domain, allowing requests to be made either
+ * to a configured URL, or to a URL specified at request time.
  *
- * <p>The AutoLayout is the default layout manager delegated by {@link Ext.Component} to
- * render any child Elements when no <tt>{@link Ext.Component#layout layout}</tt> is configured.</p>
- */
-
-Ext.define('Ext.layout.component.Auto', {
-
-    /* Begin Definitions */
-
-    alias: 'layout.autocomponent',
-
-    extend: 'Ext.layout.component.Component',
-
-    /* End Definitions */
-
-    type: 'autocomponent',
-
-    onLayout : function(width, height) {
-        this.setTargetSize(width, height);
-    }
-});
-/**
- * @class Ext.AbstractComponent
- * <p>An abstract base class which provides shared methods for Components across the Sencha product line.</p>
- * <p>Please refer to sub class's documentation</p>
+ * Requests made by this class are asynchronous, and will return immediately. No data from the server will be available
+ * to the statement immediately following the {@link #request} call. To process returned data, use a success callback
+ * in the request options object, or an {@link #requestcomplete event listener}.
+ *
+ * # File Uploads
+ *
+ * File uploads are not performed using normal "Ajax" techniques, that is they are not performed using XMLHttpRequests.
+ * Instead the form is submitted in the standard manner with the DOM &lt;form&gt; element temporarily modified to have its
+ * target set to refer to a dynamically generated, hidden &lt;iframe&gt; which is inserted into the document but removed
+ * after the return data has been gathered.
+ *
+ * The server response is parsed by the browser to create the document for the IFRAME. If the server is using JSON to
+ * send the return object, then the Content-Type header must be set to "text/html" in order to tell the browser to
+ * insert the text unchanged into the document body.
+ *
+ * Characters which are significant to an HTML parser must be sent as HTML entities, so encode `<` as `&lt;`, `&` as
+ * `&amp;` etc.
+ *
+ * The response text is retrieved from the document, and a fake XMLHttpRequest object is created containing a
+ * responseText property in order to conform to the requirements of event handlers and callbacks.
+ *
+ * Be aware that file upload packets are sent with the content type multipart/form and some server technologies
+ * (notably JEE) may require some custom processing in order to retrieve parameter names and parameter values from the
+ * packet content.
+ *
+ * Also note that it's not possible to check the response code of the hidden iframe, so the success handler will ALWAYS fire.
  */
-
-Ext.define('Ext.AbstractComponent', {
-
-    /* Begin Definitions */
-
+Ext.define('Ext.data.Connection', {
     mixins: {
-        observable: 'Ext.util.Observable',
-        animate: 'Ext.util.Animate',
-        state: 'Ext.state.Stateful'
+        observable: 'Ext.util.Observable'
     },
 
-    requires: [
-        'Ext.PluginManager',
-        'Ext.ComponentManager',
-        'Ext.core.Element',
-        'Ext.core.DomHelper',
-        'Ext.XTemplate',
-        'Ext.ComponentQuery',
-        'Ext.LoadMask',
-        'Ext.ComponentLoader',
-        'Ext.EventManager',
-        'Ext.layout.Layout',
-        'Ext.layout.component.Auto'
-    ],
-
-    // Please remember to add dependencies whenever you use it
-    // I had to fix these many times already
-    uses: [
-        'Ext.ZIndexManager'
-    ],
-
     statics: {
-        AUTO_ID: 1000
-    },
-
-    /* End Definitions */
-
-    isComponent: true,
-
-    getAutoId: function() {
-        return ++Ext.AbstractComponent.AUTO_ID;
+        requestId: 0
     },
 
+    url: null,
+    async: true,
+    method: null,
+    username: '',
+    password: '',
 
     /**
-     * @cfg {String} id
-     * <p>The <b><u>unique id of this component instance</u></b> (defaults to an {@link #getId auto-assigned id}).</p>
-     * <p>It should not be necessary to use this configuration except for singleton objects in your application.
-     * Components created with an id may be accessed globally using {@link Ext#getCmp Ext.getCmp}.</p>
-     * <p>Instead of using assigned ids, use the {@link #itemId} config, and {@link Ext.ComponentQuery ComponentQuery} which
-     * provides selector-based searching for Sencha Components analogous to DOM querying. The {@link Ext.container.Container Container}
-     * class contains {@link Ext.container.Container#down shortcut methods} to query its descendant Components by selector.</p>
-     * <p>Note that this id will also be used as the element id for the containing HTML element
-     * that is rendered to the page for this component. This allows you to write id-based CSS
-     * rules to style the specific instance of this component uniquely, and also to select
-     * sub-elements using this component's id as the parent.</p>
-     * <p><b>Note</b>: to avoid complications imposed by a unique <tt>id</tt> also see <code>{@link #itemId}</code>.</p>
-     * <p><b>Note</b>: to access the container of a Component see <code>{@link #ownerCt}</code>.</p>
+     * @cfg {Boolean} disableCaching
+     * True to add a unique cache-buster param to GET requests.
      */
+    disableCaching: true,
 
     /**
-     * @cfg {String} itemId
-     * <p>An <tt>itemId</tt> can be used as an alternative way to get a reference to a component
-     * when no object reference is available.  Instead of using an <code>{@link #id}</code> with
-     * {@link Ext}.{@link Ext#getCmp getCmp}, use <code>itemId</code> with
-     * {@link Ext.container.Container}.{@link Ext.container.Container#getComponent getComponent} which will retrieve
-     * <code>itemId</code>'s or <tt>{@link #id}</tt>'s. Since <code>itemId</code>'s are an index to the
-     * container's internal MixedCollection, the <code>itemId</code> is scoped locally to the container --
-     * avoiding potential conflicts with {@link Ext.ComponentManager} which requires a <b>unique</b>
-     * <code>{@link #id}</code>.</p>
-     * <pre><code>
-var c = new Ext.panel.Panel({ //
-    {@link Ext.Component#height height}: 300,
-    {@link #renderTo}: document.body,
-    {@link Ext.container.Container#layout layout}: 'auto',
-    {@link Ext.container.Container#items items}: [
-        {
-            itemId: 'p1',
-            {@link Ext.panel.Panel#title title}: 'Panel 1',
-            {@link Ext.Component#height height}: 150
-        },
-        {
-            itemId: 'p2',
-            {@link Ext.panel.Panel#title title}: 'Panel 2',
-            {@link Ext.Component#height height}: 150
-        }
-    ]
-})
-p1 = c.{@link Ext.container.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
-p2 = p1.{@link #ownerCt}.{@link Ext.container.Container#getComponent getComponent}('p2'); // reference via a sibling
-     * </code></pre>
-     * <p>Also see <tt>{@link #id}</tt>, <code>{@link Ext.container.Container#query}</code>,
-     * <code>{@link Ext.container.Container#down}</code> and <code>{@link Ext.container.Container#child}</code>.</p>
-     * <p><b>Note</b>: to access the container of an item see <tt>{@link #ownerCt}</tt>.</p>
+     * @cfg {Boolean} withCredentials
+     * True to set `withCredentials = true` on the XHR object
      */
+    withCredentials: false,
 
     /**
-     * This Component's owner {@link Ext.container.Container Container} (defaults to undefined, and is set automatically when
-     * this Component is added to a Container).  Read-only.
-     * <p><b>Note</b>: to access items within the Container see <tt>{@link #itemId}</tt>.</p>
-     * @type Ext.Container
-     * @property ownerCt
+     * @cfg {Boolean} cors
+     * True to enable CORS support on the XHR object. Currently the only effect of this option
+     * is to use the XDomainRequest object instead of XMLHttpRequest if the browser is IE8 or above.
      */
-
-     /**
-      * @private
-      * Flag set by the container layout to which this Component is added.
-      * If the layout manages this Component's width, it sets the value to 1.
-      * If it does NOT manage the width, it sets it to 2.
-      * If the layout MAY affect the width, but only if the owning Container has a fixed width, this is set to 0.
-      * @type boolean
-      * @property layoutManagedWidth
-      */
-
-     /**
-      * @private
-      * Flag set by the container layout to which this Component is added.
-      * If the layout manages this Component's height, it sets the value to 1.
-      * If it does NOT manage the height, it sets it to 2.
-      * If the layout MAY affect the height, but only if the owning Container has a fixed height, this is set to 0.
-      * @type boolean
-      * @property layoutManagedHeight
-      */
+    cors: false,
 
     /**
-     * @cfg {Mixed} autoEl
-     * <p>A tag name or {@link Ext.core.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
-     * encapsulate this Component.</p>
-     * <p>You do not normally need to specify this. For the base classes {@link Ext.Component} and {@link Ext.container.Container},
-     * this defaults to <b><tt>'div'</tt></b>. The more complex Sencha classes use a more complex
-     * DOM structure specified by their own {@link #renderTpl}s.</p>
-     * <p>This is intended to allow the developer to create application-specific utility Components encapsulated by
-     * different DOM elements. Example usage:</p><pre><code>
-{
-    xtype: 'component',
-    autoEl: {
-        tag: 'img',
-        src: 'http://www.example.com/example.jpg'
-    }
-}, {
-    xtype: 'component',
-    autoEl: {
-        tag: 'blockquote',
-        html: 'autoEl is cool!'
-    }
-}, {
-    xtype: 'container',
-    autoEl: 'ul',
-    cls: 'ux-unordered-list',
-    items: {
-        xtype: 'component',
-        autoEl: 'li',
-        html: 'First list item'
-    }
-}
-</code></pre>
+     * @cfg {String} disableCachingParam
+     * Change the parameter which is sent went disabling caching through a cache buster.
      */
+    disableCachingParam: '_dc',
 
     /**
-     * @cfg {Mixed} renderTpl
-     * <p>An {@link Ext.XTemplate XTemplate} used to create the internal structure inside this Component's
-     * encapsulating {@link #getEl Element}.</p>
-     * <p>You do not normally need to specify this. For the base classes {@link Ext.Component}
-     * and {@link Ext.container.Container}, this defaults to <b><code>null</code></b> which means that they will be initially rendered
-     * with no internal structure; they render their {@link #getEl Element} empty. The more specialized ExtJS and Touch classes
-     * which use a more complex DOM structure, provide their own template definitions.</p>
-     * <p>This is intended to allow the developer to create application-specific utility Components with customized
-     * internal structure.</p>
-     * <p>Upon rendering, any created child elements may be automatically imported into object properties using the
-     * {@link #renderSelectors} option.</p>
+     * @cfg {Number} timeout
+     * The timeout in milliseconds to be used for requests.
      */
-    renderTpl: null,
+    timeout : 30000,
 
     /**
-     * @cfg {Object} renderSelectors
+     * @cfg {Object} extraParams
+     * Any parameters to be appended to the request.
+     */
 
-An object containing properties specifying {@link Ext.DomQuery DomQuery} selectors which identify child elements
-created by the render process.
+    useDefaultHeader : true,
+    defaultPostHeader : 'application/x-www-form-urlencoded; charset=UTF-8',
+    useDefaultXhrHeader : true,
+    defaultXhrHeader : 'XMLHttpRequest',
 
-After the Component's internal structure is rendered according to the {@link #renderTpl}, this object is iterated through,
-and the found Elements are added as properties to the Component using the `renderSelector` property name.
+    constructor : function(config) {
+        config = config || {};
+        Ext.apply(this, config);
 
-For example, a Component which rendered an image, and description into its element might use the following properties
-coded into its prototype:
+        this.addEvents(
+            /**
+             * @event beforerequest
+             * Fires before a network request is made to retrieve a data object.
+             * @param {Ext.data.Connection} conn This Connection object.
+             * @param {Object} options The options config object passed to the {@link #request} method.
+             */
+            'beforerequest',
+            /**
+             * @event requestcomplete
+             * Fires if the request was successfully completed.
+             * @param {Ext.data.Connection} conn This Connection object.
+             * @param {Object} response The XHR object containing the response data.
+             * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
+             * @param {Object} options The options config object passed to the {@link #request} method.
+             */
+            'requestcomplete',
+            /**
+             * @event requestexception
+             * Fires if an error HTTP status was returned from the server.
+             * See [HTTP Status Code Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
+             * for details of HTTP status codes.
+             * @param {Ext.data.Connection} conn This Connection object.
+             * @param {Object} response The XHR object containing the response data.
+             * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
+             * @param {Object} options The options config object passed to the {@link #request} method.
+             */
+            'requestexception'
+        );
+        this.requests = {};
+        this.mixins.observable.constructor.call(this);
+    },
 
-    renderTpl: '&lt;img src="{imageUrl}" class="x-image-component-img">&lt;div class="x-image-component-desc">{description}&gt;/div&lt;',
+    /**
+     * Sends an HTTP request to a remote server.
+     *
+     * **Important:** Ajax server requests are asynchronous, and this call will
+     * return before the response has been received. Process any returned data
+     * in a callback function.
+     *
+     *     Ext.Ajax.request({
+     *         url: 'ajax_demo/sample.json',
+     *         success: function(response, opts) {
+     *             var obj = Ext.decode(response.responseText);
+     *             console.dir(obj);
+     *         },
+     *         failure: function(response, opts) {
+     *             console.log('server-side failure with status code ' + response.status);
+     *         }
+     *     });
+     *
+     * To execute a callback function in the correct scope, use the `scope` option.
+     *
+     * @param {Object} options An object which may contain the following properties:
+     *
+     * (The options object may also contain any other property which might be needed to perform
+     * postprocessing in a callback because it is passed to callback functions.)
+     *
+     * @param {String/Function} options.url The URL to which to send the request, or a function
+     * to call which returns a URL string. The scope of the function is specified by the `scope` option.
+     * Defaults to the configured `url`.
+     *
+     * @param {Object/String/Function} options.params An object containing properties which are
+     * used as parameters to the request, a url encoded string or a function to call to get either. The scope
+     * of the function is specified by the `scope` option.
+     *
+     * @param {String} options.method The HTTP method to use
+     * for the request. Defaults to the configured method, or if no method was configured,
+     * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
+     * the method name is case-sensitive and should be all caps.
+     *
+     * @param {Function} options.callback The function to be called upon receipt of the HTTP response.
+     * The callback is called regardless of success or failure and is passed the following parameters:
+     * @param {Object} options.callback.options The parameter to the request call.
+     * @param {Boolean} options.callback.success True if the request succeeded.
+     * @param {Object} options.callback.response The XMLHttpRequest object containing the response data.
+     * See [www.w3.org/TR/XMLHttpRequest/](http://www.w3.org/TR/XMLHttpRequest/) for details about
+     * accessing elements of the response.
+     *
+     * @param {Function} options.success The function to be called upon success of the request.
+     * The callback is passed the following parameters:
+     * @param {Object} options.success.response The XMLHttpRequest object containing the response data.
+     * @param {Object} options.success.options The parameter to the request call.
+     *
+     * @param {Function} options.failure The function to be called upon success of the request.
+     * The callback is passed the following parameters:
+     * @param {Object} options.failure.response The XMLHttpRequest object containing the response data.
+     * @param {Object} options.failure.options The parameter to the request call.
+     *
+     * @param {Object} options.scope The scope in which to execute the callbacks: The "this" object for
+     * the callback function. If the `url`, or `params` options were specified as functions from which to
+     * draw values, then this also serves as the scope for those function calls. Defaults to the browser
+     * window.
+     *
+     * @param {Number} options.timeout The timeout in milliseconds to be used for this request.
+     * Defaults to 30 seconds.
+     *
+     * @param {Ext.Element/HTMLElement/String} options.form The `<form>` Element or the id of the `<form>`
+     * to pull parameters from.
+     *
+     * @param {Boolean} options.isUpload **Only meaningful when used with the `form` option.**
+     *
+     * True if the form object is a file upload (will be set automatically if the form was configured
+     * with **`enctype`** `"multipart/form-data"`).
+     *
+     * File uploads are not performed using normal "Ajax" techniques, that is they are **not**
+     * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
+     * DOM `<form>` element temporarily modified to have its [target][] set to refer to a dynamically
+     * generated, hidden `<iframe>` which is inserted into the document but removed after the return data
+     * has been gathered.
+     *
+     * The server response is parsed by the browser to create the document for the IFRAME. If the
+     * server is using JSON to send the return object, then the [Content-Type][] header must be set to
+     * "text/html" in order to tell the browser to insert the text unchanged into the document body.
+     *
+     * The response text is retrieved from the document, and a fake XMLHttpRequest object is created
+     * containing a `responseText` property in order to conform to the requirements of event handlers
+     * and callbacks.
+     *
+     * Be aware that file upload packets are sent with the content type [multipart/form][] and some server
+     * technologies (notably JEE) may require some custom processing in order to retrieve parameter names
+     * and parameter values from the packet content.
+     *
+     * [target]: http://www.w3.org/TR/REC-html40/present/frames.html#adef-target
+     * [Content-Type]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
+     * [multipart/form]: http://www.faqs.org/rfcs/rfc2388.html
+     *
+     * @param {Object} options.headers Request headers to set for the request.
+     *
+     * @param {Object} options.xmlData XML document to use for the post. Note: This will be used instead
+     * of params for the post data. Any params will be appended to the URL.
+     *
+     * @param {Object/String} options.jsonData JSON data to use as the post. Note: This will be used
+     * instead of params for the post data. Any params will be appended to the URL.
+     *
+     * @param {Boolean} options.disableCaching True to add a unique cache-buster param to GET requests.
+     *
+     * @param {Boolean} options.withCredentials True to add the withCredentials property to the XHR object
+     *
+     * @return {Object} The request object. This may be used to cancel the request.
+     */
+    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;
 
-    renderSelectors: {
-        image: 'img.x-image-component-img',
-        descEl: 'div.x-image-component-desc'
-    }
+        if (me.fireEvent('beforerequest', me, options) !== false) {
 
-After rendering, the Component would have a property <code>image</code> referencing its child `img` Element,
-and a property `descEl` referencing the `div` Element which contains the description.
+            requestOptions = me.setOptions(options, scope);
 
-     * @markdown
-     */
+            if (this.isFormUpload(options) === true) {
+                this.upload(options.form, requestOptions.url, requestOptions.data, options);
+                return null;
+            }
 
-    /**
-     * @cfg {Mixed} renderTo
-     * <p>Specify the id of the element, a DOM element or an existing Element that this component
-     * will be rendered into.</p><div><ul>
-     * <li><b>Notes</b> : <ul>
-     * <div class="sub-desc">Do <u>not</u> use this option if the Component is to be a child item of
-     * a {@link Ext.container.Container Container}. It is the responsibility of the
-     * {@link Ext.container.Container Container}'s {@link Ext.container.Container#layout layout manager}
-     * to render and manage its child items.</div>
-     * <div class="sub-desc">When using this config, a call to render() is not required.</div>
-     * </ul></li>
-     * </ul></div>
-     * <p>See <code>{@link #render}</code> also.</p>
-     */
+            // if autoabort is set, cancel the current transactions
+            if (options.autoAbort === true || me.autoAbort) {
+                me.abort();
+            }
 
-    /**
-     * @cfg {Boolean} frame
-     * <p>Specify as <code>true</code> to have the Component inject framing elements within the Component at render time to
-     * provide a graphical rounded frame around the Component content.</p>
-     * <p>This is only necessary when running on outdated, or non standard-compliant browsers such as Microsoft's Internet Explorer
-     * prior to version 9 which do not support rounded corners natively.</p>
-     * <p>The extra space taken up by this framing is available from the read only property {@link #frameSize}.</p>
-     */
-
-    /**
-     * <p>Read-only property indicating the width of any framing elements which were added within the encapsulating element
-     * to provide graphical, rounded borders. See the {@link #frame} config.</p>
-     * <p> This is an object containing the frame width in pixels for all four sides of the Component containing
-     * the following properties:</p><div class="mdetail-params"><ul>
-     * <li><code>top</code> The width of the top framing element in pixels.</li>
-     * <li><code>right</code> The width of the right framing element in pixels.</li>
-     * <li><code>bottom</code> The width of the bottom framing element in pixels.</li>
-     * <li><code>left</code> The width of the left framing element in pixels.</li>
-     * </ul></div>
-     * @property frameSize
-     * @type {Object}
-     */
+            // create a connection object
 
-    /**
-     * @cfg {String/Object} componentLayout
-     * <p>The sizing and positioning of a Component's internal Elements is the responsibility of
-     * the Component's layout manager which sizes a Component's internal structure in response to the Component being sized.</p>
-     * <p>Generally, developers will not use this configuration as all provided Components which need their internal
-     * elements sizing (Such as {@link Ext.form.field.Base input fields}) come with their own componentLayout managers.</p>
-     * <p>The {@link Ext.layout.container.Auto default layout manager} will be used on instances of the base Ext.Component class
-     * which simply sizes the Component's encapsulating element to the height and width specified in the {@link #setSize} method.</p>
-     */
+            if ((options.cors === true || me.cors === true) && Ext.isIe && Ext.ieVersion >= 8) {
+                xhr = new XDomainRequest();
+            } else {
+                xhr = this.getXhrInstance();
+            }
 
-    /**
-     * @cfg {Mixed} tpl
-     * An <bold>{@link Ext.Template}</bold>, <bold>{@link Ext.XTemplate}</bold>
-     * or an array of strings to form an Ext.XTemplate.
-     * Used in conjunction with the <code>{@link #data}</code> and
-     * <code>{@link #tplWriteMode}</code> configurations.
-     */
+            async = options.async !== false ? (options.async || me.async) : false;
 
-    /**
-     * @cfg {Mixed} data
-     * The initial set of data to apply to the <code>{@link #tpl}</code> to
-     * update the content area of the Component.
-     */
+            // open the request
+            if (username) {
+                xhr.open(requestOptions.method, requestOptions.url, async, username, password);
+            } else {
+                xhr.open(requestOptions.method, requestOptions.url, async);
+            }
 
-    /**
-     * @cfg {String} tplWriteMode The Ext.(X)Template method to use when
-     * updating the content area of the Component. Defaults to <code>'overwrite'</code>
-     * (see <code>{@link Ext.XTemplate#overwrite}</code>).
-     */
-    tplWriteMode: 'overwrite',
+            if (options.withCredentials === true || me.withCredentials === true) {
+                xhr.withCredentials = true;
+            }
 
-    /**
-     * @cfg {String} baseCls
-     * The base CSS class to apply to this components's element. This will also be prepended to
-     * elements within this component like Panel's body will get a class x-panel-body. This means
-     * that if you create a subclass of Panel, and you want it to get all the Panels styling for the
-     * element and the body, you leave the baseCls x-panel and use componentCls to add specific styling for this
-     * component.
-     */
-    baseCls: Ext.baseCSSPrefix + 'component',
+            headers = me.setupHeaders(xhr, options, requestOptions.data, requestOptions.params);
 
-    /**
-     * @cfg {String} componentCls
-     * CSS Class to be added to a components root level element to give distinction to it
-     * via styling.
-     */
+            // create the transaction object
+            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;
+            // bind our statechange listener
+            if (async) {
+                xhr.onreadystatechange = Ext.Function.bind(me.onStateChange, me, [request]);
+            }
 
-    /**
-     * @cfg {String} cls
-     * An optional extra CSS class that will be added to this component's Element (defaults to '').  This can be
-     * useful for adding customized styles to the component or any of its children using standard CSS rules.
-     */
+            // start the request!
+            xhr.send(requestOptions.data);
+            if (!async) {
+                return this.onComplete(request);
+            }
+            return request;
+        } else {
+            Ext.callback(options.callback, options.scope, [options, undefined, undefined]);
+            return null;
+        }
+    },
 
     /**
-     * @cfg {String} overCls
-     * An optional extra CSS class that will be added to this component's Element when the mouse moves
-     * over the Element, and removed when the mouse moves out. (defaults to '').  This can be
-     * useful for adding customized 'active' or 'hover' styles to the component or any of its children using standard CSS rules.
+     * Uploads a form using a hidden iframe.
+     * @param {String/HTMLElement/Ext.Element} form The form to upload
+     * @param {String} url The url to post to
+     * @param {String} params Any extra parameters to pass
+     * @param {Object} options The initial options
      */
+    upload: function(form, url, params, options) {
+        form = Ext.getDom(form);
+        options = options || {};
 
-    /**
-     * @cfg {String} disabledCls
-     * CSS class to add when the Component is disabled. Defaults to 'x-item-disabled'.
-     */
-    disabledCls: Ext.baseCSSPrefix + 'item-disabled',
+        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
+                }, hiddenItem;
 
-    /**
-     * @cfg {String/Array} ui
-     * A set style for a component. Can be a string or an Array of multiple strings (UIs)
-     */
-    ui: 'default',
+        /*
+         * Originally this behaviour was modified for Opera 10 to apply the secure URL after
+         * the frame had been added to the document. It seems this has since been corrected in
+         * Opera so the behaviour has been reverted, the URL will be set before being added.
+         */
+        Ext.fly(frame).set({
+            id: id,
+            name: id,
+            cls: Ext.baseCSSPrefix + 'hide-display',
+            src: Ext.SSL_SECURE_URL
+        });
+
+        document.body.appendChild(frame);
+
+        // This is required so that IE doesn't pop the response up in a new window.
+        if (document.frames) {
+           document.frames[id].name = id;
+        }
+
+        Ext.fly(form).set({
+            target: id,
+            method: 'POST',
+            enctype: encoding,
+            encoding: encoding,
+            action: url || buf.action
+        });
+
+        // add dynamic params
+        if (params) {
+            Ext.iterate(Ext.Object.fromQueryString(params), function(name, value){
+                hiddenItem = document.createElement('input');
+                Ext.fly(hiddenItem).set({
+                    type: 'hidden',
+                    value: value,
+                    name: name
+                });
+                form.appendChild(hiddenItem);
+                hiddens.push(hiddenItem);
+            });
+        }
+
+        Ext.fly(frame).on('load', Ext.Function.bind(this.onUploadComplete, this, [frame, options]), null, {single: true});
+        form.submit();
+
+        Ext.fly(form).set(buf);
+        Ext.each(hiddens, function(h) {
+            Ext.removeNode(h);
+        });
+    },
 
     /**
-     * @cfg {Array} uiCls
-     * An array of of classNames which are currently applied to this component
      * @private
+     * Callback handler for the upload function. After we've submitted the form via the iframe this creates a bogus
+     * response object to simulate an XHR and populates its responseText from the now-loaded iframe's document body
+     * (or a textarea inside the body). We then clean up by removing the iframe
      */
-    uiCls: [],
+    onUploadComplete: function(frame, options) {
+        var me = this,
+            // bogus response object
+            response = {
+                responseText: '',
+                responseXML: null
+            }, doc, firstChild;
 
-    /**
-     * @cfg {String} style
-     * A custom style specification to be applied to this component's Element.  Should be a valid argument to
-     * {@link Ext.core.Element#applyStyles}.
-     * <pre><code>
-        new Ext.panel.Panel({
-            title: 'Some Title',
-            renderTo: Ext.getBody(),
-            width: 400, height: 300,
-            layout: 'form',
-            items: [{
-                xtype: 'textarea',
-                style: {
-                    width: '95%',
-                    marginBottom: '10px'
-                }
-            },
-            new Ext.button.Button({
-                text: 'Send',
-                minWidth: '100',
-                style: {
-                    marginBottom: '10px'
+        try {
+            doc = frame.contentWindow.document || frame.contentDocument || window.frames[frame.id].document;
+            if (doc) {
+                if (doc.body) {
+                    if (/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)) { // json response wrapped in textarea
+                        response.responseText = firstChild.value;
+                    } else {
+                        response.responseText = doc.body.innerHTML;
+                    }
                 }
-            })
-            ]
-        });
-     </code></pre>
-     */
+                //in IE the document may still have a body even if returns XML.
+                response.responseXML = doc.XMLDocument || doc;
+            }
+        } catch (e) {
+        }
 
-    /**
-     * @cfg {Number} width
-     * The width of this component in pixels.
-     */
+        me.fireEvent('requestcomplete', me, response, options);
 
-    /**
-     * @cfg {Number} height
-     * The height of this component in pixels.
-     */
+        Ext.callback(options.success, options.scope, [response, options]);
+        Ext.callback(options.callback, options.scope, [options, true, response]);
 
-    /**
-     * @cfg {Number/String} border
-     * Specifies the border for this component. The border can be a single numeric value to apply to all sides or
-     * it can be a CSS style specification for each style, for example: '10 5 3 10'.
-     */
+        setTimeout(function(){
+            Ext.removeNode(frame);
+        }, 100);
+    },
 
     /**
-     * @cfg {Number/String} padding
-     * Specifies the padding for this component. The padding can be a single numeric value to apply to all sides or
-     * it can be a CSS style specification for each style, for example: '10 5 3 10'.
+     * Detects whether the form is intended to be used for an upload.
+     * @private
      */
+    isFormUpload: function(options){
+        var form = this.getForm(options);
+        if (form) {
+            return (options.isUpload || (/multipart\/form-data/i).test(form.getAttribute('enctype')));
+        }
+        return false;
+    },
 
     /**
-     * @cfg {Number/String} margin
-     * Specifies the margin for this component. The margin can be a single numeric value to apply to all sides or
-     * it can be a CSS style specification for each style, for example: '10 5 3 10'.
+     * Gets the form object from options.
+     * @private
+     * @param {Object} options The request options
+     * @return {HTMLElement} The form, null if not passed
      */
+    getForm: function(options){
+        return Ext.getDom(options.form) || null;
+    },
 
     /**
-     * @cfg {Boolean} hidden
-     * Defaults to false.
+     * Sets various options such as the url, params for the request
+     * @param {Object} options The initial options
+     * @param {Object} scope The scope to execute in
+     * @return {Object} The params for the request
      */
-    hidden: false,
+    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;
 
-    /**
-     * @cfg {Boolean} disabled
-     * Defaults to false.
-     */
-    disabled: false,
 
-    /**
-     * @cfg {Boolean} draggable
-     * Allows the component to be dragged.
-     */
+        // allow params to be a method that returns the params object
+        if (Ext.isFunction(params)) {
+            params = params.call(scope, options);
+        }
+
+        // allow url to be a method that returns the actual url
+        if (Ext.isFunction(url)) {
+            url = url.call(scope, options);
+        }
+
+        url = this.setupUrl(options, url);
+
+        //<debug>
+        if (!url) {
+            Ext.Error.raise({
+                options: options,
+                msg: 'No URL specified'
+            });
+        }
+        //</debug>
+
+        // check for xml or json data, and make sure json data is encoded
+        data = options.rawData || options.xmlData || jsonData || null;
+        if (jsonData && !Ext.isPrimitive(jsonData)) {
+            data = Ext.encode(data);
+        }
+
+        // make sure params are a url encoded string and include any extraParams if specified
+        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);
+
+        // decide the proper method for this request
+        method = (options.method || me.method || ((params || data) ? 'POST' : 'GET')).toUpperCase();
+        this.setupMethod(options, method);
+
+
+        disableCache = options.disableCaching !== false ? (options.disableCaching || me.disableCaching) : false;
+        // if the method is get append date to prevent caching
+        if (method === 'GET' && disableCache) {
+            url = Ext.urlAppend(url, (options.disableCachingParam || me.disableCachingParam) + '=' + (new Date().getTime()));
+        }
+
+        // if the method is get or there is json/xml data append the params to the url
+        if ((method == 'GET' || data) && params) {
+            url = Ext.urlAppend(url, params);
+            params = null;
+        }
+
+        // allow params to be forced into the url
+        if (urlParams) {
+            url = Ext.urlAppend(url, urlParams);
+        }
+
+        return {
+            url: url,
+            method: method,
+            data: data || params || null
+        };
+    },
 
     /**
-     * Read-only property indicating whether or not the component can be dragged
-     * @property draggable
-     * @type {Boolean}
+     * Template method for overriding url
+     * @template
+     * @private
+     * @param {Object} options
+     * @param {String} url
+     * @return {String} The modified url
      */
-    draggable: false,
+    setupUrl: function(options, url){
+        var form = this.getForm(options);
+        if (form) {
+            url = url || form.action;
+        }
+        return url;
+    },
+
 
     /**
-     * @cfg {Boolean} floating
-     * Create the Component as a floating and use absolute positioning.
-     * Defaults to false.
+     * Template method for overriding params
+     * @template
+     * @private
+     * @param {Object} options
+     * @param {String} params
+     * @return {String} The modified params
      */
-    floating: false,
+    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;
+    },
 
     /**
-     * @cfg {String} hideMode
-     * A String which specifies how this Component's encapsulating DOM element will be hidden.
-     * Values may be<div class="mdetail-params"><ul>
-     * <li><code>'display'</code> : The Component will be hidden using the <code>display: none</code> style.</li>
-     * <li><code>'visibility'</code> : The Component will be hidden using the <code>visibility: hidden</code> style.</li>
-     * <li><code>'offsets'</code> : The Component will be hidden by absolutely positioning it out of the visible area of the document. This
-     * is useful when a hidden Component must maintain measurable dimensions. Hiding using <code>display</code> results
-     * in a Component having zero dimensions.</li></ul></div>
-     * Defaults to <code>'display'</code>.
+     * Template method for overriding method
+     * @template
+     * @private
+     * @param {Object} options
+     * @param {String} method
+     * @return {String} The modified method
      */
-    hideMode: 'display',
+    setupMethod: function(options, method){
+        if (this.isFormUpload(options)) {
+            return 'POST';
+        }
+        return method;
+    },
 
     /**
-     * @cfg {String} contentEl
-     * <p>Optional. Specify an existing HTML element, or the <code>id</code> of an existing HTML element to use as the content
-     * for this component.</p>
-     * <ul>
-     * <li><b>Description</b> :
-     * <div class="sub-desc">This config option is used to take an existing HTML element and place it in the layout element
-     * of a new component (it simply moves the specified DOM element <i>after the Component is rendered</i> to use as the content.</div></li>
-     * <li><b>Notes</b> :
-     * <div class="sub-desc">The specified HTML element is appended to the layout element of the component <i>after any configured
-     * {@link #html HTML} has been inserted</i>, and so the document will not contain this element at the time the {@link #render} event is fired.</div>
-     * <div class="sub-desc">The specified HTML element used will not participate in any <code><b>{@link Ext.container.Container#layout layout}</b></code>
-     * scheme that the Component may use. It is just HTML. Layouts operate on child <code><b>{@link Ext.container.Container#items items}</b></code>.</div>
-     * <div class="sub-desc">Add either the <code>x-hidden</code> or the <code>x-hide-display</code> CSS class to
-     * prevent a brief flicker of the content before it is rendered to the panel.</div></li>
-     * </ul>
+     * Setup all the headers for the request
+     * @private
+     * @param {Object} xhr The xhr object
+     * @param {Object} options The options for the request
+     * @param {Object} data The data for the request
+     * @param {Object} params The params for the request
      */
+    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;
+        }
+        // set up all the request headers on the xhr object
+        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;
+    },
 
     /**
-     * @cfg {String/Object} html
-     * An HTML fragment, or a {@link Ext.core.DomHelper DomHelper} specification to use as the layout element
-     * content (defaults to ''). The HTML content is added after the component is rendered,
-     * so the document will not contain this HTML at the time the {@link #render} event is fired.
-     * This content is inserted into the body <i>before</i> any configured {@link #contentEl} is appended.
+     * Creates the appropriate XHR transport for the browser.
+     * @private
      */
+    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;
+    })(),
 
     /**
-     * @cfg {Boolean} styleHtmlContent
-     * True to automatically style the html inside the content target of this component (body for panels).
-     * Defaults to false.
+     * Determines whether this object has a request outstanding.
+     * @param {Object} [request] Defaults to the last transaction
+     * @return {Boolean} True if there is an outstanding request.
      */
-    styleHtmlContent: false,
+    isLoading : function(request) {
+        if (!request) {
+            request = this.getLatest();
+        }
+        if (!(request && request.xhr)) {
+            return false;
+        }
+        // if there is a connection and readyState is not 0 or 4
+        var state = request.xhr.readyState;
+        return !(state === 0 || state == 4);
+    },
 
     /**
-     * @cfg {String} styleHtmlCls
-     * The class that is added to the content target when you set styleHtmlContent to true.
-     * Defaults to 'x-html'
+     * Aborts an active request.
+     * @param {Object} [request] Defaults to the last request
      */
-    styleHtmlCls: Ext.baseCSSPrefix + 'html',
+    abort : function(request) {
+        var me = this;
+        
+        if (!request) {
+            request = me.getLatest();
+        }
 
+        if (request && me.isLoading(request)) {
+            /*
+             * Clear out the onreadystatechange here, this allows us
+             * greater control, the browser may/may not fire the function
+             * depending on a series of conditions.
+             */
+            request.xhr.onreadystatechange = null;
+            request.xhr.abort();
+            me.clearTimeout(request);
+            if (!request.timedout) {
+                request.aborted = true;
+            }
+            me.onComplete(request);
+            me.cleanup(request);
+        }
+    },
+    
     /**
-     * @cfg {Number} minHeight
-     * <p>The minimum value in pixels which this Component will set its height to.</p>
-     * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
+     * Aborts all active requests
      */
+    abortAll: function(){
+        var requests = this.requests,
+            id;
+        
+        for (id in requests) {
+            if (requests.hasOwnProperty(id)) {
+                this.abort(requests[id]);
+            }
+        }
+    },
+    
     /**
-     * @cfg {Number} minWidth
-     * <p>The minimum value in pixels which this Component will set its width to.</p>
-     * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
+     * Gets the most recent request
+     * @private
+     * @return {Object} The request. Null if there is no recent request
      */
+    getLatest: function(){
+        var id = this.latestId,
+            request;
+            
+        if (id) {
+            request = this.requests[id];
+        }
+        return request || null;
+    },
+
     /**
-     * @cfg {Number} maxHeight
-     * <p>The maximum value in pixels which this Component will set its height to.</p>
-     * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
+     * Fires when the state of the xhr changes
+     * @private
+     * @param {Object} request The request
      */
+    onStateChange : function(request) {
+        if (request.xhr.readyState == 4) {
+            this.clearTimeout(request);
+            this.onComplete(request);
+            this.cleanup(request);
+        }
+    },
+
     /**
-     * @cfg {Number} maxWidth
-     * <p>The maximum value in pixels which this Component will set its width to.</p>
-     * <p><b>Warning:</b> This will override any size management applied by layout managers.</p>
+     * Clears the timeout on the request
+     * @private
+     * @param {Object} The request
      */
+    clearTimeout: function(request){
+        clearTimeout(request.timeout);
+        delete request.timeout;
+    },
 
     /**
-     * @cfg {Ext.ComponentLoader/Object} loader
-     * A configuration object or an instance of a {@link Ext.ComponentLoader} to load remote
-     * content for this Component.
+     * Cleans up any left over information from the request
+     * @private
+     * @param {Object} The request
      */
-
-     // @private
-     allowDomMove: true,
-
-     /**
-      * @cfg {Boolean} autoShow True to automatically show the component upon creation.
-      * This config option may only be used for {@link #floating} components or components
-      * that use {@link #autoRender}. Defaults to <tt>false</tt>.
-      */
-     autoShow: false,
+    cleanup: function(request){
+        request.xhr = null;
+        delete request.xhr;
+    },
 
     /**
-     * @cfg {Mixed} autoRender
-     * <p>This config is intended mainly for {@link #floating} Components which may or may not be shown. Instead
-     * of using {@link #renderTo} in the configuration, and rendering upon construction, this allows a Component
-     * to render itself upon first <i>{@link #show}</i>.</p>
-     * <p>Specify as <code>true</code> to have this Component render to the document body upon first show.</p>
-     * <p>Specify as an element, or the ID of an element to have this Component render to a specific element upon first show.</p>
-     * <p><b>This defaults to <code>true</code> for the {@link Ext.window.Window Window} class.</b></p>
+     * To be called when the request has come back from the server
+     * @private
+     * @param {Object} request
+     * @return {Object} The response
      */
-     autoRender: false,
+    onComplete : function(request) {
+        var me = this,
+            options = request.options,
+            result,
+            success,
+            response;
 
-     needsLayout: false,
+        try {
+            result = me.parseStatus(request.xhr.status);
+        } catch (e) {
+            // in some browsers we can't access the status if the readyState is not 4, so the request has failed
+            result = {
+                success : false,
+                isException : false
+            };
+        }
+        success = result.success;
 
-    /**
-     * @cfg {Object/Array} plugins
-     * An object or array of objects that will provide custom functionality for this component.  The only
-     * requirement for a valid plugin is that it contain an init method that accepts a reference of type Ext.Component.
-     * When a component is created, if any plugins are available, the component will call the init method on each
-     * plugin, passing a reference to itself.  Each plugin can then call methods or respond to events on the
-     * component as needed to provide its functionality.
-     */
+        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;
+    },
 
     /**
-     * Read-only property indicating whether or not the component has been rendered.
-     * @property rendered
-     * @type {Boolean}
+     * Checks if the response status was successful
+     * @param {Number} status The status code
+     * @return {Object} An object containing success/status state
      */
-    rendered: false,
-
-    weight: 0,
+    parseStatus: function(status) {
+        // see: https://prototype.lighthouseapp.com/projects/8886/tickets/129-ie-mangles-http-response-status-code-204-to-1223
+        status = status == 1223 ? 204 : status;
 
-    trimRe: /^\s+|\s+$/g,
-    spacesRe: /\s+/,
+        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
+        };
+    },
 
     /**
-     * This is an internal flag that you use when creating custom components.
-     * By default this is set to true which means that every component gets a mask when its disabled.
-     * Components like FieldContainer, FieldSet, Field, Button, Tab override this property to false
-     * since they want to implement custom disable logic.
-     * @property maskOnDisable
-     * @type {Boolean}
+     * Creates the response object
+     * @private
+     * @param {Object} request
      */
-    maskOnDisable: true,
-
-    /**
-     * Creates new Component.
-     * @param {Object} config  (optional) Config object.
-     */
-    constructor : function(config) {
-        var me = this,
-            i, len;
-
-        config = config || {};
-        me.initialConfig = config;
-        Ext.apply(me, config);
-
-        me.addEvents(
-            /**
-             * @event beforeactivate
-             * Fires before a Component has been visually activated.
-             * Returning false from an event listener can prevent the activate
-             * from occurring.
-             * @param {Ext.Component} this
-             */
-             'beforeactivate',
-            /**
-             * @event activate
-             * Fires after a Component has been visually activated.
-             * @param {Ext.Component} this
-             */
-             'activate',
-            /**
-             * @event beforedeactivate
-             * Fires before a Component has been visually deactivated.
-             * Returning false from an event listener can prevent the deactivate
-             * from occurring.
-             * @param {Ext.Component} this
-             */
-             'beforedeactivate',
-            /**
-             * @event deactivate
-             * Fires after a Component has been visually deactivated.
-             * @param {Ext.Component} this
-             */
-             'deactivate',
-            /**
-             * @event added
-             * Fires after a Component had been added to a Container.
-             * @param {Ext.Component} this
-             * @param {Ext.container.Container} container Parent Container
-             * @param {Number} pos position of Component
-             */
-             'added',
-            /**
-             * @event disable
-             * Fires after the component is disabled.
-             * @param {Ext.Component} this
-             */
-             'disable',
-            /**
-             * @event enable
-             * Fires after the component is enabled.
-             * @param {Ext.Component} this
-             */
-             'enable',
-            /**
-             * @event beforeshow
-             * Fires before the component is shown when calling the {@link #show} method.
-             * Return false from an event handler to stop the show.
-             * @param {Ext.Component} this
-             */
-             'beforeshow',
-            /**
-             * @event show
-             * Fires after the component is shown when calling the {@link #show} method.
-             * @param {Ext.Component} this
-             */
-             'show',
-            /**
-             * @event beforehide
-             * Fires before the component is hidden when calling the {@link #hide} method.
-             * Return false from an event handler to stop the hide.
-             * @param {Ext.Component} this
-             */
-             'beforehide',
-            /**
-             * @event hide
-             * Fires after the component is hidden.
-             * Fires after the component is hidden when calling the {@link #hide} method.
-             * @param {Ext.Component} this
-             */
-             'hide',
-            /**
-             * @event removed
-             * Fires when a component is removed from an Ext.container.Container
-             * @param {Ext.Component} this
-             * @param {Ext.container.Container} ownerCt Container which holds the component
-             */
-             'removed',
-            /**
-             * @event beforerender
-             * Fires before the component is {@link #rendered}. Return false from an
-             * event handler to stop the {@link #render}.
-             * @param {Ext.Component} this
-             */
-             'beforerender',
-            /**
-             * @event render
-             * Fires after the component markup is {@link #rendered}.
-             * @param {Ext.Component} this
-             */
-             'render',
-            /**
-             * @event afterrender
-             * <p>Fires after the component rendering is finished.</p>
-             * <p>The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed
-             * by any afterRender method defined for the Component.</p>
-             * @param {Ext.Component} this
-             */
-             'afterrender',
-            /**
-             * @event beforedestroy
-             * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the {@link #destroy}.
-             * @param {Ext.Component} this
-             */
-             'beforedestroy',
-            /**
-             * @event destroy
-             * Fires after the component is {@link #destroy}ed.
-             * @param {Ext.Component} this
-             */
-             'destroy',
-            /**
-             * @event resize
-             * Fires after the component is resized.
-             * @param {Ext.Component} this
-             * @param {Number} adjWidth The box-adjusted width that was set
-             * @param {Number} adjHeight The box-adjusted height that was set
-             */
-             'resize',
-            /**
-             * @event move
-             * Fires after the component is moved.
-             * @param {Ext.Component} this
-             * @param {Number} x The new x position
-             * @param {Number} y The new y position
-             */
-             'move'
-        );
-
-        me.getId();
-
-        me.mons = [];
-        me.additionalCls = [];
-        me.renderData = me.renderData || {};
-        me.renderSelectors = me.renderSelectors || {};
+    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;
 
-        if (me.plugins) {
-            me.plugins = [].concat(me.plugins);
-            for (i = 0, len = me.plugins.length; i < len; i++) {
-                me.plugins[i] = me.constructPlugin(me.plugins[i]);
+        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);
             }
         }
 
-        me.initComponent();
-
-        // ititComponent gets a chance to change the id property before registering
-        Ext.ComponentManager.register(me);
+        request.xhr = null;
+        delete request.xhr;
 
-        // Dont pass the config so that it is not applied to 'this' again
-        me.mixins.observable.constructor.call(me);
-        me.mixins.state.constructor.call(me, config);
+        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
+        };
 
-        // Save state on resize.
-        this.addStateEvents('resize');
+        // If we don't explicitly tear down the xhr reference, IE6/IE7 will hold this in the closure of the
+        // functions created with getResponseHeader/getAllResponseHeaders
+        xhr = null;
+        return response;
+    },
 
-        // Move this into Observable?
-        if (me.plugins) {
-            me.plugins = [].concat(me.plugins);
-            for (i = 0, len = me.plugins.length; i < len; i++) {
-                me.plugins[i] = me.initPlugin(me.plugins[i]);
-            }
-        }
+    /**
+     * Creates the exception object
+     * @private
+     * @param {Object} request
+     */
+    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
+        };
+    }
+});
 
-        me.loader = me.getLoader();
+/**
+ * @class Ext.Ajax
+ * @singleton
+ * @markdown
+ * @extends Ext.data.Connection
 
-        if (me.renderTo) {
-            me.render(me.renderTo);
-            // EXTJSIV-1935 - should be a way to do afterShow or something, but that
-            // won't work. Likewise, rendering hidden and then showing (w/autoShow) has
-            // implications to afterRender so we cannot do that.
-        }
+A singleton instance of an {@link Ext.data.Connection}. This class
+is used to communicate with your server side code. It can be used as follows:
 
-        if (me.autoShow) {
-            me.show();
+    Ext.Ajax.request({
+        url: 'page.php',
+        params: {
+            id: 1
+        },
+        success: function(response){
+            var text = response.responseText;
+            // process server response here
         }
+    });
 
-        //<debug>
-        if (Ext.isDefined(me.disabledClass)) {
-            if (Ext.isDefined(Ext.global.console)) {
-                Ext.global.console.warn('Ext.Component: disabledClass has been deprecated. Please use disabledCls.');
-            }
-            me.disabledCls = me.disabledClass;
-            delete me.disabledClass;
-        }
-        //</debug>
-    },
+Default options for all requests can be set by changing a property on the Ext.Ajax class:
 
-    initComponent: Ext.emptyFn,
+    Ext.Ajax.timeout = 60000; // 60 seconds
 
-    /**
-     * </p>The supplied default state gathering method for the AbstractComponent class.</p>
-     * This method returns dimension setings such as <code>flex</code>, <code>anchor</code>, <code>width</code>
-     * and <code>height</code> along with <code>collapsed</code> state.</p>
-     * <p>Subclasses which implement more complex state should call the superclass's implementation, and apply their state
-     * to the result if this basic state is to be saved.</p>
-     * <p>Note that Component state will only be saved if the Component has a {@link #stateId} and there as a StateProvider
-     * configured for the document.</p>
-     */
-    getState: function() {
-        var me = this,
-            layout = me.ownerCt ? (me.shadowOwnerCt || me.ownerCt).getLayout() : null,
-            state = {
-                collapsed: me.collapsed
-            },
-            width = me.width,
-            height = me.height,
-            cm = me.collapseMemento,
-            anchors;
+Any options specified in the request method for the Ajax request will override any
+defaults set on the Ext.Ajax class. In the code sample below, the timeout for the
+request will be 60 seconds.
 
-        // If a Panel-local collapse has taken place, use remembered values as the dimensions.
-        // TODO: remove this coupling with Panel's privates! All collapse/expand logic should be refactored into one place.
-        if (me.collapsed && cm) {
-            if (Ext.isDefined(cm.data.width)) {
-                width = cm.width;
-            }
-            if (Ext.isDefined(cm.data.height)) {
-                height = cm.height;
-            }
-        }
+    Ext.Ajax.timeout = 120000; // 120 seconds
+    Ext.Ajax.request({
+        url: 'page.aspx',
+        timeout: 60000
+    });
 
-        // If we have flex, only store the perpendicular dimension.
-        if (layout && me.flex) {
-            state.flex = me.flex;
-            state[layout.perpendicularPrefix] = me['get' + layout.perpendicularPrefixCap]();
-        }
-        // If we have anchor, only store dimensions which are *not* being anchored
-        else if (layout && me.anchor) {
-            state.anchor = me.anchor;
-            anchors = me.anchor.split(' ').concat(null);
-            if (!anchors[0]) {
-                if (me.width) {
-                    state.width = width;
-                }
-            }
-            if (!anchors[1]) {
-                if (me.height) {
-                    state.height = height;
-                }
-            }
-        }
-        // Store dimensions.
-        else {
-            if (me.width) {
-                state.width = width;
-            }
-            if (me.height) {
-                state.height = height;
-            }
-        }
+In general, this class will be used for all Ajax requests in your application.
+The main reason for creating a separate {@link Ext.data.Connection} is for a
+series of requests that share common settings that are different to all other
+requests in the application.
 
-        // Don't save dimensions if they are unchanged from the original configuration.
-        if (state.width == me.initialConfig.width) {
-            delete state.width;
-        }
-        if (state.height == me.initialConfig.height) {
-            delete state.height;
-        }
+ */
+Ext.define('Ext.Ajax', {
+    extend: 'Ext.data.Connection',
+    singleton: true,
 
-        // If a Box layout was managing the perpendicular dimension, don't save that dimension
-        if (layout && layout.align && (layout.align.indexOf('stretch') !== -1)) {
-            delete state[layout.perpendicularPrefix];
-        }
-        return state;
-    },
+    /**
+     * @cfg {String} url @hide
+     */
+    /**
+     * @cfg {Object} extraParams @hide
+     */
+    /**
+     * @cfg {Object} defaultHeaders @hide
+     */
+    /**
+     * @cfg {String} method (Optional) @hide
+     */
+    /**
+     * @cfg {Number} timeout (Optional) @hide
+     */
+    /**
+     * @cfg {Boolean} autoAbort (Optional) @hide
+     */
 
-    show: Ext.emptyFn,
+    /**
+     * @cfg {Boolean} disableCaching (Optional) @hide
+     */
 
-    animate: function(animObj) {
-        var me = this,
-            to;
+    /**
+     * @property {Boolean} disableCaching
+     * True to add a unique cache-buster param to GET requests. Defaults to true.
+     */
+    /**
+     * @property {String} url
+     * The default URL to be used for requests to the server.
+     * If the server receives all requests through one URL, setting this once is easier than
+     * entering it on every request.
+     */
+    /**
+     * @property {Object} extraParams
+     * An object containing properties which are used as extra parameters to each request made
+     * by this object. Session information and other data that you need
+     * to pass with each request are commonly put here.
+     */
+    /**
+     * @property {Object} defaultHeaders
+     * An object containing request headers which are added to each request made by this object.
+     */
+    /**
+     * @property {String} method
+     * The default HTTP method to be used for requests. Note that this is case-sensitive and
+     * should be all caps (if not set but params are present will use
+     * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
+     */
+    /**
+     * @property {Number} timeout
+     * The timeout in milliseconds to be used for requests. Defaults to 30000.
+     */
 
-        animObj = animObj || {};
-        to = animObj.to || {};
+    /**
+     * @property {Boolean} autoAbort
+     * Whether a new request should abort any pending requests.
+     */
+    autoAbort : false
+});
+/**
+ * A class used to load remote content to an Element. Sample usage:
+ *
+ *     Ext.get('el').load({
+ *         url: 'myPage.php',
+ *         scripts: true,
+ *         params: {
+ *             id: 1
+ *         }
+ *     });
+ *
+ * In general this class will not be instanced directly, rather the {@link Ext.Element#load} method
+ * will be used.
+ */
+Ext.define('Ext.ElementLoader', {
 
-        if (Ext.fx.Manager.hasFxBlock(me.id)) {
-            return me;
-        }
-        // Special processing for animating Component dimensions.
-        if (!animObj.dynamic && (to.height || to.width)) {
-            var curWidth = me.getWidth(),
-                w = curWidth,
-                curHeight = me.getHeight(),
-                h = curHeight,
-                needsResize = false;
+    /* Begin Definitions */
 
-            if (to.height && to.height > curHeight) {
-                h = to.height;
-                needsResize = true;
-            }
-            if (to.width && to.width > curWidth) {
-                w = to.width;
-                needsResize = true;
-            }
+    mixins: {
+        observable: 'Ext.util.Observable'
+    },
 
-            // If any dimensions are being increased, we must resize the internal structure
-            // of the Component, but then clip it by sizing its encapsulating element back to original dimensions.
-            // The animation will then progressively reveal the larger content.
-            if (needsResize) {
-                var clearWidth = !Ext.isNumber(me.width),
-                    clearHeight = !Ext.isNumber(me.height);
+    uses: [
+        'Ext.data.Connection',
+        'Ext.Ajax'
+    ],
 
-                me.componentLayout.childrenChanged = true;
-                me.setSize(w, h, me.ownerCt);
-                me.el.setSize(curWidth, curHeight);
-                if (clearWidth) {
-                    delete me.width;
-                }
-                if (clearHeight) {
-                    delete me.height;
-                }
+    statics: {
+        Renderer: {
+            Html: function(loader, response, active){
+                loader.getTarget().update(response.responseText, active.scripts === true);
+                return true;
             }
         }
-        return me.mixins.animate.animate.apply(me, arguments);
     },
 
+    /* End Definitions */
+
     /**
-     * <p>This method finds the topmost active layout who's processing will eventually determine the size and position of this
-     * Component.<p>
-     * <p>This method is useful when dynamically adding Components into Containers, and some processing must take place after the
-     * final sizing and positioning of the Component has been performed.</p>
-     * @returns
+     * @cfg {String} url
+     * The url to retrieve the content from.
      */
-    findLayoutController: function() {
-        return this.findParentBy(function(c) {
-            // Return true if we are at the root of the Container tree
-            // or this Container's layout is busy but the next one up is not.
-            return !c.ownerCt || (c.layout.layoutBusy && !c.ownerCt.layout.layoutBusy);
-        });
-    },
+    url: null,
 
-    onShow : function() {
-        // Layout if needed
-        var needsLayout = this.needsLayout;
-        if (Ext.isObject(needsLayout)) {
-            this.doComponentLayout(needsLayout.width, needsLayout.height, needsLayout.isSetSize, needsLayout.ownerCt);
-        }
-    },
+    /**
+     * @cfg {Object} params
+     * Any params to be attached to the Ajax request. These parameters will
+     * be overridden by any params in the load options.
+     */
+    params: null,
 
-    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;
-    },
+    /**
+     * @cfg {Object} baseParams Params that will be attached to every request. These parameters
+     * will not be overridden by any params in the load options.
+     */
+    baseParams: null,
 
-    // @private
-    initPlugin : function(plugin) {
-        plugin.init(this);
+    /**
+     * @cfg {Boolean/Object} autoLoad
+     * True to have the loader make a request as soon as it is created.
+     * This argument can also be a set of options that will be passed to {@link #load} is called.
+     */
+    autoLoad: false,
 
-        return plugin;
-    },
+    /**
+     * @cfg {HTMLElement/Ext.Element/String} target
+     * The target element for the loader. It can be the DOM element, the id or an {@link Ext.Element}.
+     */
+    target: null,
 
     /**
-     * Handles autoRender.
-     * Floating Components may have an ownerCt. If they are asking to be constrained, constrain them within that
-     * ownerCt, and have their z-index managed locally. Floating Components are always rendered to document.body
+     * @cfg {Boolean/String} loadMask
+     * True or a string to show when the element is loading.
      */
-    doAutoRender: function() {
-        var me = this;
-        if (me.floating) {
-            me.render(document.body);
-        } else {
-            me.render(Ext.isBoolean(me.autoRender) ? Ext.getBody() : me.autoRender);
-        }
-    },
+    loadMask: false,
 
-    // @private
-    render : function(container, position) {
-        var me = this;
+    /**
+     * @cfg {Object} ajaxOptions
+     * Any additional options to be passed to the request, for example timeout or headers.
+     */
+    ajaxOptions: null,
 
-        if (!me.rendered && me.fireEvent('beforerender', me) !== false) {
-            // If this.el is defined, we want to make sure we are dealing with
-            // an Ext Element.
-            if (me.el) {
-                me.el = Ext.get(me.el);
-            }
+    /**
+     * @cfg {Boolean} scripts
+     * True to parse any inline script tags in the response.
+     */
+    scripts: false,
 
-            // Perform render-time processing for floating Components
-            if (me.floating) {
-                me.onFloatRender();
-            }
+    /**
+     * @cfg {Function} success
+     * A function to be called when a load request is successful.
+     * Will be called with the following config parameters:
+     *
+     * - this - The ElementLoader instance.
+     * - response - The response object.
+     * - options - Ajax options.
+     */
 
-            container = me.initContainer(container);
+    /**
+     * @cfg {Function} failure A function to be called when a load request fails.
+     * Will be called with the following config parameters:
+     *
+     * - this - The ElementLoader instance.
+     * - response - The response object.
+     * - options - Ajax options.
+     */
 
-            me.onRender(container, position);
+    /**
+     * @cfg {Function} callback A function to be called when a load request finishes.
+     * Will be called with the following config parameters:
+     *
+     * - this - The ElementLoader instance.
+     * - success - True if successful request.
+     * - response - The response object.
+     * - options - Ajax options.
+     */
 
-            // Tell the encapsulating element to hide itself in the way the Component is configured to hide
-            // This means DISPLAY, VISIBILITY or OFFSETS.
-            me.el.setVisibilityMode(Ext.core.Element[me.hideMode.toUpperCase()]);
+    /**
+     * @cfg {Object} scope
+     * The scope to execute the {@link #success} and {@link #failure} functions in.
+     */
 
-            if (me.overCls) {
-                me.el.hover(me.addOverCls, me.removeOverCls, me);
-            }
+    /**
+     * @cfg {Function} renderer
+     * A custom function to render the content to the element. The passed parameters are:
+     *
+     * - The loader
+     * - The response
+     * - The active request
+     */
 
-            me.fireEvent('render', me);
+    isLoader: true,
 
-            me.initContent();
+    constructor: function(config) {
+        var me = this,
+            autoLoad;
 
-            me.afterRender(container);
-            me.fireEvent('afterrender', me);
+        config = config || {};
+        Ext.apply(me, config);
+        me.setTarget(me.target);
+        me.addEvents(
+            /**
+             * @event beforeload
+             * Fires before a load request is made to the server.
+             * Returning false from an event listener can prevent the load
+             * from occurring.
+             * @param {Ext.ElementLoader} this
+             * @param {Object} options The options passed to the request
+             */
+            'beforeload',
 
-            me.initEvents();
+            /**
+             * @event exception
+             * Fires after an unsuccessful load.
+             * @param {Ext.ElementLoader} this
+             * @param {Object} response The response from the server
+             * @param {Object} options The options passed to the request
+             */
+            'exception',
 
-            if (me.hidden) {
-                // Hiding during the render process should not perform any ancillary
-                // actions that the full hide process does; It is not hiding, it begins in a hidden state.'
-                // So just make the element hidden according to the configured hideMode
-                me.el.hide();
-            }
+            /**
+             * @event load
+             * Fires after a successful load.
+             * @param {Ext.ElementLoader} this
+             * @param {Object} response The response from the server
+             * @param {Object} options The options passed to the request
+             */
+            'load'
+        );
 
-            if (me.disabled) {
-                // pass silent so the event doesn't fire the first time.
-                me.disable(true);
+        // don't pass config because we have already applied it.
+        me.mixins.observable.constructor.call(me);
+
+        if (me.autoLoad) {
+            autoLoad = me.autoLoad;
+            if (autoLoad === true) {
+                autoLoad = {};
             }
+            me.load(autoLoad);
         }
-        return me;
     },
 
-    // @private
-    onRender : function(container, position) {
-        var me = this,
-            el = me.el,
-            styles = me.initStyles(),
-            renderTpl, renderData, i;
+    /**
+     * Sets an {@link Ext.Element} as the target of this loader.
+     * Note that if the target is changed, any active requests will be aborted.
+     * @param {String/HTMLElement/Ext.Element} target The element or its ID.
+     */
+    setTarget: function(target){
+        var me = this;
+        target = Ext.get(target);
+        if (me.target && me.target != target) {
+            me.abort();
+        }
+        me.target = target;
+    },
 
-        position = me.getInsertPosition(position);
+    /**
+     * Returns the target of this loader.
+     * @return {Ext.Component} The target or null if none exists.
+     */
+    getTarget: function(){
+        return this.target || null;
+    },
 
-        if (!el) {
-            if (position) {
-                el = Ext.core.DomHelper.insertBefore(position, me.getElConfig(), true);
-            }
-            else {
-                el = Ext.core.DomHelper.append(container, me.getElConfig(), true);
-            }
-        }
-        else if (me.allowDomMove !== false) {
-            if (position) {
-                container.dom.insertBefore(el.dom, position);
-            } else {
-                container.dom.appendChild(el.dom);
+    /**
+     * Aborts the active load request
+     */
+    abort: function(){
+        var active = this.active;
+        if (active !== undefined) {
+            Ext.Ajax.abort(active.request);
+            if (active.mask) {
+                this.removeMask();
             }
+            delete this.active;
         }
+    },
 
-        if (Ext.scopeResetCSS && !me.ownerCt) {
-            // If this component's el is the body element, we add the reset class to the html tag
-            if (el.dom == Ext.getBody().dom) {
-                el.parent().addCls(Ext.baseCSSPrefix + 'reset');
-            }
-            else {
-                // Else we wrap this element in an element that adds the reset class.
-                me.resetEl = el.wrap({
-                    cls: Ext.baseCSSPrefix + 'reset'
-                });
-            }
+    /**
+     * Removes the mask on the target
+     * @private
+     */
+    removeMask: function(){
+        this.target.unmask();
+    },
+
+    /**
+     * Adds the mask on the target
+     * @private
+     * @param {Boolean/Object} mask The mask configuration
+     */
+    addMask: function(mask){
+        this.target.mask(mask === true ? null : mask);
+    },
+
+    /**
+     * Loads new data from the server.
+     * @param {Object} options The options for the request. They can be any configuration option that can be specified for
+     * the class, with the exception of the target option. Note that any options passed to the method will override any
+     * class defaults.
+     */
+    load: function(options) {
+        //<debug>
+        if (!this.target) {
+            Ext.Error.raise('A valid target is required when loading content');
         }
+        //</debug>
 
-        me.setUI(me.ui);
+        options = Ext.apply({}, options);
 
-        el.addCls(me.initCls());
-        el.setStyle(styles);
+        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;
 
-        // Here we check if the component has a height set through style or css.
-        // If it does then we set the this.height to that value and it won't be
-        // considered an auto height component
-        // if (this.height === undefined) {
-        //     var height = el.getHeight();
-        //     // This hopefully means that the panel has an explicit height set in style or css
-        //     if (height - el.getPadding('tb') - el.getBorderWidth('tb') > 0) {
-        //         this.height = height;
-        //     }
-        // }
+        Ext.applyIf(ajaxOptions, me.ajaxOptions);
+        Ext.applyIf(options, ajaxOptions);
 
-        me.el = el;
+        Ext.applyIf(params, me.params);
+        Ext.apply(params, me.baseParams);
 
-        me.initFrame();
+        Ext.applyIf(options, {
+            url: me.url
+        });
 
-        renderTpl = me.initRenderTpl();
-        if (renderTpl) {
-            renderData = me.initRenderData();
-            renderTpl.append(me.getTargetEl(), renderData);
+        //<debug>
+        if (!options.url) {
+            Ext.Error.raise('You must specify the URL from which content should be loaded');
         }
+        //</debug>
 
-        me.applyRenderSelectors();
+        Ext.apply(options, {
+            scope: me,
+            params: params,
+            callback: me.onComplete
+        });
 
-        me.rendered = true;
+        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);
     },
 
-    // @private
-    afterRender : function() {
-        var me = this,
-            pos,
-            xy;
+    /**
+     * Sets any additional options on the active request
+     * @private
+     * @param {Object} active The active request
+     * @param {Object} options The initial options
+     */
+    setOptions: Ext.emptyFn,
 
-        me.getComponentLayout();
+    /**
+     * Parses the response after the request completes
+     * @private
+     * @param {Object} options Ajax options
+     * @param {Boolean} success Success status of the request
+     * @param {Object} response The response object
+     */
+    onComplete: function(options, success, response) {
+        var me = this,
+            active = me.active,
+            scope = active.scope,
+            renderer = me.getRenderer(active.renderer);
 
-        // Set the size if a size is configured, or if this is the outermost Container
-        if (!me.ownerCt || (me.height || me.width)) {
-            me.setSize(me.width, me.height);
-        }
 
-        // For floaters, calculate x and y if they aren't defined by aligning
-        // the sized element to the center of either the container or the ownerCt
-        if (me.floating && (me.x === undefined || me.y === undefined)) {
-            if (me.floatParent) {
-                xy = me.el.getAlignToXY(me.floatParent.getTargetEl(), 'c-c');
-                pos = me.floatParent.getTargetEl().translatePoints(xy[0], xy[1]);
-            } else {
-                xy = me.el.getAlignToXY(me.container, 'c-c');
-                pos = me.container.translatePoints(xy[0], xy[1]);
-            }
-            me.x = me.x === undefined ? pos.left: me.x;
-            me.y = me.y === undefined ? pos.top: me.y;
+        if (success) {
+            success = renderer.call(me, me, response, active);
         }
 
-        if (Ext.isDefined(me.x) || Ext.isDefined(me.y)) {
-            me.setPosition(me.x, me.y);
+        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 (me.styleHtmlContent) {
-            me.getTargetEl().addCls(me.styleHtmlCls);
+        if (active.mask) {
+            me.removeMask();
         }
-    },
-
-    frameCls: Ext.baseCSSPrefix + 'frame',
 
-    frameElementCls: {
-        tl: [],
-        tc: [],
-        tr: [],
-        ml: [],
-        mc: [],
-        mr: [],
-        bl: [],
-        bc: [],
-        br: []
+        delete me.active;
     },
 
-    frameTpl: [
-        '<tpl if="top">',
-            '<tpl if="left"><div class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></tpl>" style="background-position: {tl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
-                '<tpl if="right"><div class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></tpl>" style="background-position: {tr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
-                    '<div class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></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 class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></tpl>',
-            '<tpl if="right"><div class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></tpl>" style="background-position: {mr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
-                '<div class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" role="presentation"></div>',
-            '<tpl if="right"></div></tpl>',
-        '<tpl if="left"></div></tpl>',
-        '<tpl if="bottom">',
-            '<tpl if="left"><div class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
-                '<tpl if="right"><div class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></tpl>" style="background-position: {br}; padding-right: {frameWidth}px" role="presentation"></tpl>',
-                    '<div class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></div>',
-                '<tpl if="right"></div></tpl>',
-            '<tpl if="left"></div></tpl>',
-        '</tpl>'
-    ],
-
-    frameTableTpl: [
-        '<table><tbody>',
-            '<tpl if="top">',
-                '<tr>',
-                    '<tpl if="left"><td class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></tpl>" style="background-position: {tl}; padding-left:{frameWidth}px" role="presentation"></td></tpl>',
-                    '<td class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></tpl>" style="background-position: {tc}; height: {frameWidth}px" role="presentation"></td>',
-                    '<tpl if="right"><td class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></tpl>" style="background-position: {tr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
-                '</tr>',
-            '</tpl>',
-            '<tr>',
-                '<tpl if="left"><td class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
-                '<td class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" style="background-position: 0 0;" role="presentation"></td>',
-                '<tpl if="right"><td class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></tpl>" style="background-position: {mr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
-            '</tr>',
-            '<tpl if="bottom">',
-                '<tr>',
-                    '<tpl if="left"><td class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
-                    '<td class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></td>',
-                    '<tpl if="right"><td class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></tpl>" style="background-position: {br}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
-                '</tr>',
-            '</tpl>',
-        '</tbody></table>'
-    ],
-
     /**
+     * Gets the renderer to use
      * @private
+     * @param {String/Function} renderer The renderer to use
+     * @return {Function} A rendering function to use.
      */
-    initFrame : function() {
-        if (Ext.supports.CSS3BorderRadius) {
-            return false;
+    getRenderer: function(renderer){
+        if (Ext.isFunction(renderer)) {
+            return renderer;
         }
+        return this.statics().Renderer.Html;
+    },
 
-        var me = this,
-            frameInfo = me.getFrameInfo(),
-            frameWidth = frameInfo.width,
-            frameTpl = me.getFrameTpl(frameInfo.table);
-
-        if (me.frame) {
-            // Here we render the frameTpl to this component. This inserts the 9point div or the table framing.
-            frameTpl.insertFirst(me.el, Ext.apply({}, {
-                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)));
-
-            // The frameBody is returned in getTargetEl, so that layouts render items to the correct target.=
-            me.frameBody = me.el.down('.' + me.frameCls + '-mc');
+    /**
+     * Automatically refreshes the content over a specified period.
+     * @param {Number} interval The interval to refresh in ms.
+     * @param {Object} options (optional) The options to pass to the load method. See {@link #load}
+     */
+    startAutoRefresh: function(interval, options){
+        var me = this;
+        me.stopAutoRefresh();
+        me.autoRefresh = setInterval(function(){
+            me.load(options);
+        }, interval);
+    },
 
-            // Add the render selectors for each of the frame elements
-            Ext.apply(me.renderSelectors, {
-                frameTL: '.' + me.baseCls + '-tl',
-                frameTC: '.' + me.baseCls + '-tc',
-                frameTR: '.' + me.baseCls + '-tr',
-                frameML: '.' + me.baseCls + '-ml',
-                frameMC: '.' + me.baseCls + '-mc',
-                frameMR: '.' + me.baseCls + '-mr',
-                frameBL: '.' + me.baseCls + '-bl',
-                frameBC: '.' + me.baseCls + '-bc',
-                frameBR: '.' + me.baseCls + '-br'
-            });
-        }
+    /**
+     * Clears any auto refresh. See {@link #startAutoRefresh}.
+     */
+    stopAutoRefresh: function(){
+        clearInterval(this.autoRefresh);
+        delete this.autoRefresh;
     },
 
-    updateFrame: function() {
-        if (Ext.supports.CSS3BorderRadius) {
-            return false;
-        }
+    /**
+     * Checks whether the loader is automatically refreshing. See {@link #startAutoRefresh}.
+     * @return {Boolean} True if the loader is automatically refreshing
+     */
+    isAutoRefreshing: function(){
+        return Ext.isDefined(this.autoRefresh);
+    },
 
-        var me = this,
-            wasTable = this.frameSize && this.frameSize.table,
-            oldFrameTL = this.frameTL,
-            oldFrameBL = this.frameBL,
-            oldFrameML = this.frameML,
-            oldFrameMC = this.frameMC,
-            newMCClassName;
+    /**
+     * Destroys the loader. Any active requests will be aborted.
+     */
+    destroy: function(){
+        var me = this;
+        me.stopAutoRefresh();
+        delete me.target;
+        me.abort();
+        me.clearListeners();
+    }
+});
 
-        this.initFrame();
+/**
+ * @class Ext.ComponentLoader
+ * @extends Ext.ElementLoader
+ *
+ * This class is used to load content via Ajax into a {@link Ext.Component}. In general
+ * this class will not be instanced directly, rather a loader configuration will be passed to the
+ * constructor of the {@link Ext.Component}.
+ *
+ * ## HTML Renderer
+ * By default, the content loaded will be processed as raw html. The response text
+ * from the request is taken and added to the component. This can be used in
+ * conjunction with the {@link #scripts} option to execute any inline scripts in
+ * the resulting content. Using this renderer has the same effect as passing the
+ * {@link Ext.Component#html} configuration option.
+ *
+ * ## Data Renderer
+ * This renderer allows content to be added by using JSON data and a {@link Ext.XTemplate}.
+ * The content received from the response is passed to the {@link Ext.Component#update} method.
+ * This content is run through the attached {@link Ext.Component#tpl} and the data is added to
+ * the Component. Using this renderer has the same effect as using the {@link Ext.Component#data}
+ * configuration in conjunction with a {@link Ext.Component#tpl}.
+ *
+ * ## Component Renderer
+ * This renderer can only be used with a {@link Ext.container.Container} and subclasses. It allows for
+ * Components to be loaded remotely into a Container. The response is expected to be a single/series of
+ * {@link Ext.Component} configuration objects. When the response is received, the data is decoded
+ * and then passed to {@link Ext.container.Container#add}. Using this renderer has the same effect as specifying
+ * the {@link Ext.container.Container#items} configuration on a Container.
+ *
+ * ## Custom Renderer
+ * A custom function can be passed to handle any other special case, see the {@link #renderer} option.
+ *
+ * ## Example Usage
+ *     new Ext.Component({
+ *         tpl: '{firstName} - {lastName}',
+ *         loader: {
+ *             url: 'myPage.php',
+ *             renderer: 'data',
+ *             params: {
+ *                 userId: 1
+ *             }
+ *         }
+ *     });
+ */
+Ext.define('Ext.ComponentLoader', {
 
-        if (oldFrameMC) {
-            if (me.frame) {
-                // Reapply render selectors
-                delete me.frameTL;
-                delete me.frameTC;
-                delete me.frameTR;
-                delete me.frameML;
-                delete me.frameMC;
-                delete me.frameMR;
-                delete me.frameBL;
-                delete me.frameBC;
-                delete me.frameBR;
-                this.applyRenderSelectors();
+    /* Begin Definitions */
 
-                // Store the class names set on the new mc
-                newMCClassName = this.frameMC.dom.className;
+    extend: 'Ext.ElementLoader',
 
-                // Replace the new mc with the old mc
-                oldFrameMC.insertAfter(this.frameMC);
-                this.frameMC.remove();
+    statics: {
+        Renderer: {
+            Data: function(loader, response, active){
+                var success = true;
+                try {
+                    loader.getTarget().update(Ext.decode(response.responseText));
+                } catch (e) {
+                    success = false;
+                }
+                return success;
+            },
 
-                // Restore the reference to the old frame mc as the framebody
-                this.frameBody = this.frameMC = oldFrameMC;
+            Component: function(loader, response, active){
+                var success = true,
+                    target = loader.getTarget(),
+                    items = [];
 
-                // Apply the new mc classes to the old mc element
-                oldFrameMC.dom.className = newMCClassName;
+                //<debug>
+                if (!target.isContainer) {
+                    Ext.Error.raise({
+                        target: target,
+                        msg: 'Components can only be loaded into a container'
+                    });
+                }
+                //</debug>
 
-                // Remove the old framing
-                if (wasTable) {
-                    me.el.query('> table')[1].remove();
+                try {
+                    items = Ext.decode(response.responseText);
+                } catch (e) {
+                    success = false;
                 }
-                else {
-                    if (oldFrameTL) {
-                        oldFrameTL.remove();
-                    }
-                    if (oldFrameBL) {
-                        oldFrameBL.remove();
+
+                if (success) {
+                    if (active.removeAll) {
+                        target.removeAll();
                     }
-                    oldFrameML.remove();
+                    target.add(items);
                 }
+                return success;
             }
-            else {
-                // We were framed but not anymore. Move all content from the old frame to the body
-
-            }
-        }
-        else if (me.frame) {
-            this.applyRenderSelectors();
         }
     },
 
-    getFrameInfo: function() {
-        if (Ext.supports.CSS3BorderRadius) {
-            return false;
-        }
+    /* End Definitions */
 
-        var me = this,
-            left = me.el.getStyle('background-position-x'),
-            top = me.el.getStyle('background-position-y'),
-            info, frameInfo = false, max;
+    /**
+     * @cfg {Ext.Component/String} target The target {@link Ext.Component} for the loader.
+     * If a string is passed it will be looked up via the id.
+     */
+    target: null,
 
-        // Some browsers dont support background-position-x and y, so for those
-        // browsers let's split background-position into two parts.
-        if (!left && !top) {
-            info = me.el.getStyle('background-position').split(' ');
-            left = info[0];
-            top = info[1];
-        }
+    /**
+     * @cfg {Boolean/Object} loadMask True or a {@link Ext.LoadMask} configuration to enable masking during loading.
+     */
+    loadMask: false,
 
-        // We actually pass a string in the form of '[type][tl][tr]px [type][br][bl]px' as
-        // the background position of this.el from the css to indicate to IE that this component needs
-        // framing. We parse it here and change the markup accordingly.
-        if (parseInt(left, 10) >= 1000000 && parseInt(top, 10) >= 1000000) {
-            max = Math.max;
-
-            frameInfo = {
-                // Table markup starts with 110, div markup with 100.
-                table: left.substr(0, 3) == '110',
-
-                // Determine if we are dealing with a horizontal or vertical component
-                vertical: top.substr(0, 3) == '110',
-
-                // Get and parse the different border radius sizes
-                top:    max(left.substr(3, 2), left.substr(5, 2)),
-                right:  max(left.substr(5, 2), top.substr(3, 2)),
-                bottom: max(top.substr(3, 2), top.substr(5, 2)),
-                left:   max(top.substr(5, 2), left.substr(3, 2))
-            };
-
-            frameInfo.width = max(frameInfo.top, frameInfo.right, frameInfo.bottom, frameInfo.left);
-
-            // Just to be sure we set the background image of the el to none.
-            me.el.setStyle('background-image', 'none');
-        }
-
-        // This happens when you set frame: true explicitly without using the x-frame mixin in sass.
-        // This way IE can't figure out what sizes to use and thus framing can't work.
-        if (me.frame === true && !frameInfo) {
-            //<debug error>
-            Ext.Error.raise("You have set frame: true explicity on this component while it doesn't have any " +
-                            "framing defined in the CSS template. In this case IE can't figure out what sizes " +
-                            "to use and thus framing on this component will be disabled.");
-            //</debug>
-        }
-
-        me.frame = me.frame || !!frameInfo;
-        me.frameSize = frameInfo || false;
-
-        return frameInfo;
-    },
+    /**
+     * @cfg {Boolean} scripts True to parse any inline script tags in the response. This only used when using the html
+     * {@link #renderer}.
+     */
 
-    getFramePositions: function(frameInfo) {
-        var me = this,
-            frameWidth = frameInfo.width,
-            dock = me.dock,
-            positions, tc, bc, ml, mr;
+    /**
+     * @cfg {String/Function} renderer
 
-        if (frameInfo.vertical) {
-            tc = '0 -' + (frameWidth * 0) + 'px';
-            bc = '0 -' + (frameWidth * 1) + 'px';
+The type of content that is to be loaded into, which can be one of 3 types:
 
-            if (dock && dock == "right") {
-                tc = 'right -' + (frameWidth * 0) + 'px';
-                bc = 'right -' + (frameWidth * 1) + 'px';
-            }
++ **html** : Loads raw html content, see {@link Ext.Component#html}
++ **data** : Loads raw html content, see {@link Ext.Component#data}
++ **component** : Loads child {Ext.Component} instances. This option is only valid when used with a Container.
 
-            positions = {
-                tl: '0 -' + (frameWidth * 0) + 'px',
-                tr: '0 -' + (frameWidth * 1) + 'px',
-                bl: '0 -' + (frameWidth * 2) + 'px',
-                br: '0 -' + (frameWidth * 3) + 'px',
+Alternatively, you can pass a function which is called with the following parameters.
 
-                ml: '-' + (frameWidth * 1) + 'px 0',
-                mr: 'right 0',
++ loader - Loader instance
++ response - The server response
++ active - The active request
 
-                tc: tc,
-                bc: bc
-            };
-        } else {
-            ml = '-' + (frameWidth * 0) + 'px 0';
-            mr = 'right 0';
+The function must return false is loading is not successful. Below is a sample of using a custom renderer:
 
-            if (dock && dock == "bottom") {
-                ml = 'left bottom';
-                mr = 'right bottom';
+    new Ext.Component({
+        loader: {
+            url: 'myPage.php',
+            renderer: function(loader, response, active) {
+                var text = response.responseText;
+                loader.getTarget().update('The response is ' + text);
+                return true;
             }
+        }
+    });
+     */
+    renderer: 'html',
 
-            positions = {
-                tl: '0 -' + (frameWidth * 2) + 'px',
-                tr: 'right -' + (frameWidth * 3) + 'px',
-                bl: '0 -' + (frameWidth * 4) + 'px',
-                br: 'right -' + (frameWidth * 5) + 'px',
+    /**
+     * Set a {Ext.Component} as the target of this loader. Note that if the target is changed,
+     * any active requests will be aborted.
+     * @param {String/Ext.Component} target The component to be the target of this loader. If a string is passed
+     * it will be looked up via its id.
+     */
+    setTarget: function(target){
+        var me = this;
 
-                ml: ml,
-                mr: mr,
+        if (Ext.isString(target)) {
+            target = Ext.getCmp(target);
+        }
 
-                tc: '0 -' + (frameWidth * 0) + 'px',
-                bc: '0 -' + (frameWidth * 1) + 'px'
-            };
+        if (me.target && me.target != target) {
+            me.abort();
         }
+        me.target = target;
+    },
 
-        return positions;
+    // inherit docs
+    removeMask: function(){
+        this.target.setLoading(false);
     },
 
     /**
+     * Add the mask on the target
      * @private
+     * @param {Boolean/Object} mask The mask configuration
      */
-    getFrameTpl : function(table) {
-        return table ? this.getTpl('frameTableTpl') : this.getTpl('frameTpl');
+    addMask: function(mask){
+        this.target.setLoading(mask);
     },
 
     /**
-     * <p>Creates an array of class names from the configurations to add to this Component's <code>el</code> on render.</p>
-     * <p>Private, but (possibly) used by ComponentQuery for selection by class name if Component is not rendered.</p>
-     * @return {Array} An array of class names with which the Component's element will be rendered.
-     * @private
+     * Get the target of this loader.
+     * @return {Ext.Component} target The target, null if none exists.
      */
-    initCls: function() {
-        var me = this,
-            cls = [];
 
-        cls.push(me.baseCls);
+    setOptions: function(active, options){
+        active.removeAll = Ext.isDefined(options.removeAll) ? options.removeAll : this.removeAll;
+    },
 
-        //<deprecated since=0.99>
-        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;
+    /**
+     * Gets the renderer to use
+     * @private
+     * @param {String/Function} renderer The renderer to use
+     * @return {Function} A rendering function to use.
+     */
+    getRenderer: function(renderer){
+        if (Ext.isFunction(renderer)) {
+            return renderer;
         }
-        //</deprecated>
 
-        if (me.componentCls) {
-            cls.push(me.componentCls);
-        } else {
-            me.componentCls = me.baseCls;
-        }
-        if (me.cls) {
-            cls.push(me.cls);
-            delete me.cls;
+        var renderers = this.statics().Renderer;
+        switch (renderer) {
+            case 'component':
+                return renderers.Component;
+            case 'data':
+                return renderers.Data;
+            default:
+                return Ext.ElementLoader.Renderer.Html;
         }
+    }
+});
 
-        return cls.concat(me.additionalCls);
-    },
-
+/**
+ * @author Ed Spencer
+ *
+ * Associations enable you to express relationships between different {@link Ext.data.Model Models}. Let's say we're
+ * writing an ecommerce system where Users can make Orders - there's a relationship between these Models that we can
+ * express like this:
+ *
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'name', 'email'],
+ *
+ *         hasMany: {model: 'Order', name: 'orders'}
+ *     });
+ *
+ *     Ext.define('Order', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'user_id', 'status', 'price'],
+ *
+ *         belongsTo: 'User'
+ *     });
+ *
+ * We've set up two models - User and Order - and told them about each other. You can set up as many associations on
+ * each Model as you need using the two default types - {@link Ext.data.HasManyAssociation hasMany} and {@link
+ * Ext.data.BelongsToAssociation belongsTo}. There's much more detail on the usage of each of those inside their
+ * documentation pages. If you're not familiar with Models already, {@link Ext.data.Model there is plenty on those too}.
+ *
+ * **Further Reading**
+ *
+ *   - {@link Ext.data.HasManyAssociation hasMany associations}
+ *   - {@link Ext.data.BelongsToAssociation belongsTo associations}
+ *   - {@link Ext.data.Model using Models}
+ *
+ * # Self association models
+ *
+ * We can also have models that create parent/child associations between the same type. Below is an example, where
+ * groups can be nested inside other groups:
+ *
+ *     // Server Data
+ *     {
+ *         "groups": {
+ *             "id": 10,
+ *             "parent_id": 100,
+ *             "name": "Main Group",
+ *             "parent_group": {
+ *                 "id": 100,
+ *                 "parent_id": null,
+ *                 "name": "Parent Group"
+ *             },
+ *             "child_groups": [{
+ *                 "id": 2,
+ *                 "parent_id": 10,
+ *                 "name": "Child Group 1"
+ *             },{
+ *                 "id": 3,
+ *                 "parent_id": 10,
+ *                 "name": "Child Group 2"
+ *             },{
+ *                 "id": 4,
+ *                 "parent_id": 10,
+ *                 "name": "Child Group 3"
+ *             }]
+ *         }
+ *     }
+ *
+ *     // Client code
+ *     Ext.define('Group', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'parent_id', 'name'],
+ *         proxy: {
+ *             type: 'ajax',
+ *             url: 'data.json',
+ *             reader: {
+ *                 type: 'json',
+ *                 root: 'groups'
+ *             }
+ *         },
+ *         associations: [{
+ *             type: 'hasMany',
+ *             model: 'Group',
+ *             primaryKey: 'id',
+ *             foreignKey: 'parent_id',
+ *             autoLoad: true,
+ *             associationKey: 'child_groups' // read child data from child_groups
+ *         }, {
+ *             type: 'belongsTo',
+ *             model: 'Group',
+ *             primaryKey: 'id',
+ *             foreignKey: 'parent_id',
+ *             associationKey: 'parent_group' // read parent data from parent_group
+ *         }]
+ *     });
+ *
+ *     Ext.onReady(function(){
+ *
+ *         Group.load(10, {
+ *             success: function(group){
+ *                 console.log(group.getGroup().get('name'));
+ *
+ *                 group.groups().each(function(rec){
+ *                     console.log(rec.get('name'));
+ *                 });
+ *             }
+ *         });
+ *
+ *     });
+ *
+ */
+Ext.define('Ext.data.Association', {
     /**
-     * Sets the UI for the component. This will remove any existing UIs on the component. It will also
-     * loop through any uiCls set on the component and rename them so they include the new UI
-     * @param {String} ui The new UI for the component
+     * @cfg {String} ownerModel (required)
+     * The string name of the model that owns the association.
      */
-    setUI: function(ui) {
-        var me = this,
-            oldUICls = Ext.Array.clone(me.uiCls),
-            newUICls = [],
-            classes = [],
-            cls,
-            i;
-
-        //loop through all exisiting uiCls and update the ui in them
-        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);
-        }
+    /**
+     * @cfg {String} associatedModel (required)
+     * The string name of the model that is being associated with.
+     */
 
-        //remove the UI from the element
-        me.removeUIFromElement();
+    /**
+     * @cfg {String} primaryKey
+     * The name of the primary key on the associated model. In general this will be the
+     * {@link Ext.data.Model#idProperty} of the Model.
+     */
+    primaryKey: 'id',
 
-        //set the UI
-        me.ui = ui;
+    /**
+     * @cfg {Ext.data.reader.Reader} reader
+     * A special reader to read associated data
+     */
+    
+    /**
+     * @cfg {String} associationKey
+     * The name of the property in the data to read the association from. Defaults to the name of the associated model.
+     */
 
-        //add the new UI to the elemend
-        me.addUIToElement();
+    defaultReaderType: 'json',
 
-        //loop through all exisiting uiCls and update the ui in them
-        classes = [];
-        for (i = 0; i < newUICls.length; i++) {
-            cls = newUICls[i];
-            classes = classes.concat(me.addClsWithUI(cls, true));
-        }
+    statics: {
+        create: function(association){
+            if (!association.isAssociation) {
+                if (Ext.isString(association)) {
+                    association = {
+                        type: association
+                    };
+                }
 
-        if (classes.length) {
-            me.addCls(classes);
+                switch (association.type) {
+                    case 'belongsTo':
+                        return Ext.create('Ext.data.BelongsToAssociation', association);
+                    case 'hasMany':
+                        return Ext.create('Ext.data.HasManyAssociation', association);
+                    //TODO Add this back when it's fixed
+//                    case 'polymorphic':
+//                        return Ext.create('Ext.data.PolymorphicAssociation', association);
+                    default:
+                        //<debug>
+                        Ext.Error.raise('Unknown Association type: "' + association.type + '"');
+                        //</debug>
+                }
+            }
+            return association;
         }
     },
 
     /**
-     * Adds a cls to the uiCls array, which will also call {@link #addUIClsToElement} and adds
-     * to all elements of this component.
-     * @param {String/Array} cls A string or an array of strings to add to the uiCls
-     * @param (Boolean) skip True to skip adding it to the class and do it later (via the return)
+     * Creates the Association object.
+     * @param {Object} [config] Config object.
      */
-    addClsWithUI: function(cls, skip) {
-        var me = this,
-            classes = [],
-            i;
+    constructor: function(config) {
+        Ext.apply(this, config);
 
-        if (!Ext.isArray(cls)) {
-            cls = [cls];
+        var types           = Ext.ModelManager.types,
+            ownerName       = config.ownerModel,
+            associatedName  = config.associatedModel,
+            ownerModel      = types[ownerName],
+            associatedModel = types[associatedName],
+            ownerProto;
+
+        //<debug>
+        if (ownerModel === undefined) {
+            Ext.Error.raise("The configured ownerModel was not valid (you tried " + ownerName + ")");
+        }
+        if (associatedModel === undefined) {
+            Ext.Error.raise("The configured associatedModel was not valid (you tried " + associatedName + ")");
         }
+        //</debug>
 
-        for (i = 0; i < cls.length; i++) {
-            if (cls[i] && !me.hasUICls(cls[i])) {
-                me.uiCls = Ext.Array.clone(me.uiCls);
-                me.uiCls.push(cls[i]);
+        this.ownerModel = ownerModel;
+        this.associatedModel = associatedModel;
 
-                classes = classes.concat(me.addUIClsToElement(cls[i]));
-            }
-        }
+        /**
+         * @property {String} ownerName
+         * The name of the model that 'owns' the association
+         */
 
-        if (skip !== true) {
-            me.addCls(classes);
-        }
+        /**
+         * @property {String} associatedName
+         * The name of the model is on the other end of the association (e.g. if a User model hasMany Orders, this is
+         * 'Order')
+         */
 
-        return classes;
+        Ext.applyIf(this, {
+            ownerName : ownerName,
+            associatedName: associatedName
+        });
     },
 
     /**
-     * Removes a cls to the uiCls array, which will also call {@link #removeUIClsFromElement} and removes
-     * it from all elements of this component.
-     * @param {String/Array} cls A string or an array of strings to remove to the uiCls
+     * Get a specialized reader for reading associated data
+     * @return {Ext.data.reader.Reader} The reader, null if not supplied
      */
-    removeClsWithUI: function(cls, skip) {
+    getReader: function(){
         var me = this,
-            classes = [],
-            i;
+            reader = me.reader,
+            model = me.associatedModel;
 
-        if (!Ext.isArray(cls)) {
-            cls = [cls];
+        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;
+    }
+});
 
-        for (i = 0; i < cls.length; i++) {
-            if (cls[i] && me.hasUICls(cls[i])) {
-                me.uiCls = Ext.Array.remove(me.uiCls, cls[i]);
+/**
+ * @author Ed Spencer
+ * @class Ext.ModelManager
+ * @extends Ext.AbstractManager
 
-                classes = classes.concat(me.removeUIClsFromElement(cls[i]));
-            }
-        }
+The ModelManager keeps track of all {@link Ext.data.Model} types defined in your application.
 
-        if (skip !== true) {
-            me.removeCls(classes);
-        }
+__Creating Model Instances__
 
-        return classes;
-    },
+Model instances can be created by using the {@link Ext#create Ext.create} method. Ext.create replaces
+the deprecated {@link #create Ext.ModelManager.create} method. It is also possible to create a model instance
+this by using the Model type directly. The following 3 snippets are equivalent:
+
+    Ext.define('User', {
+        extend: 'Ext.data.Model',
+        fields: ['first', 'last']
+    });
+
+    // method 1, create using Ext.create (recommended)
+    Ext.create('User', {
+        first: 'Ed',
+        last: 'Spencer'
+    });
+
+    // method 2, create through the manager (deprecated)
+    Ext.ModelManager.create({
+        first: 'Ed',
+        last: 'Spencer'
+    }, 'User');
+
+    // method 3, create on the type directly
+    new User({
+        first: 'Ed',
+        last: 'Spencer'
+    });
+
+__Accessing Model Types__
+
+A reference to a Model type can be obtained by using the {@link #getModel} function. Since models types
+are normal classes, you can access the type directly. The following snippets are equivalent:
+
+    Ext.define('User', {
+        extend: 'Ext.data.Model',
+        fields: ['first', 'last']
+    });
+
+    // method 1, access model type through the manager
+    var UserType = Ext.ModelManager.getModel('User');
+
+    // method 2, reference the type directly
+    var UserType = User;
+
+ * @markdown
+ * @singleton
+ */
+Ext.define('Ext.ModelManager', {
+    extend: 'Ext.AbstractManager',
+    alternateClassName: 'Ext.ModelMgr',
+    requires: ['Ext.data.Association'],
+
+    singleton: true,
+
+    typeName: 'mtype',
 
     /**
-     * Checks if there is currently a specified uiCls
-     * @param {String} cls The cls to check
+     * Private stack of associations that must be created once their associated model has been defined
+     * @property {Ext.data.Association[]} associationStack
      */
-    hasUICls: function(cls) {
-        var me = this,
-            uiCls = me.uiCls || [];
+    associationStack: [],
 
-        return Ext.Array.contains(uiCls, cls);
+    /**
+     * Registers a model definition. All model plugins marked with isDefault: true are bootstrapped
+     * immediately, as are any addition plugins defined in the model config.
+     * @private
+     */
+    registerType: function(name, config) {
+        var proto = config.prototype,
+            model;
+        if (proto && proto.isModel) {
+            // registering an already defined model
+            model = config;
+        } else {
+            // passing in a configuration
+            if (!config.extend) {
+                config.extend = 'Ext.data.Model';
+            }
+            model = Ext.define(name, config);
+        }
+        this.types[name] = model;
+        return model;
     },
 
     /**
-     * Method which adds a specified UI + uiCls to the components element.
-     * Can be overridden to remove the UI from more than just the components element.
-     * @param {String} ui The UI to remove from the element
+     * @private
+     * Private callback called whenever a model has just been defined. This sets up any associations
+     * that were waiting for the given model to be defined
+     * @param {Function} model The model that was just created
      */
-    addUIClsToElement: function(cls, force) {
-        var me = this,
-            result = [],
-            frameElementCls = me.frameElementCls;
-        
-        result.push(Ext.baseCSSPrefix + cls);
-        result.push(me.baseCls + '-' + cls);
-        result.push(me.baseCls + '-' + me.ui + '-' + cls);
-        
-        if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
-            // define each element of the frame
-            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
-                classes, i, j, el;
+    onModelDefined: function(model) {
+        var stack  = this.associationStack,
+            length = stack.length,
+            create = [],
+            association, i, created;
 
-            // loop through each of them, and if they are defined add the ui
-            for (i = 0; i < els.length; i++) {
-                el = me['frame' + els[i].toUpperCase()];
-                classes = [me.baseCls + '-' + me.ui + '-' + els[i], me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i]];
-                if (el && el.dom) {
-                    el.addCls(classes);
-                } else {
-                    for (j = 0; j < classes.length; j++) {
-                        if (Ext.Array.indexOf(frameElementCls[els[i]], classes[j]) == -1) {
-                            frameElementCls[els[i]].push(classes[j]);
-                        }
-                    }
-                }
+        for (i = 0; i < length; i++) {
+            association = stack[i];
+
+            if (association.associatedModel == model.modelName) {
+                create.push(association);
             }
         }
 
-        me.frameElementCls = frameElementCls;
-
-        return result;
+        for (i = 0, length = create.length; i < length; i++) {
+            created = create[i];
+            this.types[created.ownerModel].prototype.associations.add(Ext.data.Association.create(created));
+            Ext.Array.remove(stack, created);
+        }
     },
 
     /**
-     * Method which removes a specified UI + uiCls from the components element.
-     * The cls which is added to the element will be: `this.baseCls + '-' + ui`
-     * @param {String} ui The UI to add to the element
+     * Registers an association where one of the models defined doesn't exist yet.
+     * The ModelManager will check when new models are registered if it can link them
+     * together
+     * @private
+     * @param {Ext.data.Association} association The association
      */
-    removeUIClsFromElement: function(cls, force) {
-        var me = this,
-            result = [],
-            frameElementCls = me.frameElementCls;
-        
-        result.push(Ext.baseCSSPrefix + cls);
-        result.push(me.baseCls + '-' + cls);
-        result.push(me.baseCls + '-' + me.ui + '-' + cls);
-        
-        if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
-            // define each element of the frame
-            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
-                i, el;
-            cls = me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i];
-            // loop through each of them, and if they are defined add the ui
-            for (i = 0; i < els.length; i++) {
-                el = me['frame' + els[i].toUpperCase()];
-                if (el && el.dom) {
-                    el.removeCls(cls);
-                } else {
-                    Ext.Array.remove(frameElementCls[els[i]], cls);
-                }
-            }
-        }
-
-        me.frameElementCls = frameElementCls;
-
-        return result;
+    registerDeferredAssociation: function(association){
+        this.associationStack.push(association);
     },
 
     /**
-     * Method which adds a specified UI to the components element.
-     * @private
+     * Returns the {@link Ext.data.Model} for a given model name
+     * @param {String/Object} id The id of the model or the model instance.
+     * @return {Ext.data.Model} a model class.
      */
-    addUIToElement: function(force) {
-        var me = this,
-            frameElementCls = me.frameElementCls;
-        
-        me.addCls(me.baseCls + '-' + me.ui);
-        
-        if (me.frame && !Ext.supports.CSS3BorderRadius) {
-            // define each element of the frame
-            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
-                i, el, cls;
-            
-            // loop through each of them, and if they are defined add the ui
-            for (i = 0; i < els.length; i++) {
-                el = me['frame' + els[i].toUpperCase()];
-                cls = me.baseCls + '-' + me.ui + '-' + els[i];
-                if (el) {
-                    el.addCls(cls);
-                } else {
-                    if (!Ext.Array.contains(frameElementCls[els[i]], cls)) {
-                        frameElementCls[els[i]].push(cls);
-                    }
-                }
-            }
+    getModel: function(id) {
+        var model = id;
+        if (typeof model == 'string') {
+            model = this.types[model];
         }
+        return model;
     },
 
     /**
-     * Method which removes a specified UI from the components element.
-     * @private
+     * Creates a new instance of a Model using the given data.
+     *
+     * This method is deprecated.  Use {@link Ext#create Ext.create} instead.  For example:
+     *
+     *     Ext.create('User', {
+     *         first: 'Ed',
+     *         last: 'Spencer'
+     *     });
+     *
+     * @param {Object} data Data to initialize the Model's fields with
+     * @param {String} name The name of the model to create
+     * @param {Number} id (Optional) unique id of the Model instance (see {@link Ext.data.Model})
      */
-    removeUIFromElement: function() {
-        var me = this,
-            frameElementCls = me.frameElementCls;
-        
-        me.removeCls(me.baseCls + '-' + me.ui);
-        
-        if (me.frame && !Ext.supports.CSS3BorderRadius) {
-            // define each element of the frame
-            var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
-                i, j, el, cls;
-                
-            // loop through each of them, and if they are defined add the ui
-            for (i = 0; i < els.length; i++) {
-                el = me['frame' + els[i].toUpperCase()];
-                cls = me.baseCls + '-' + me.ui + '-' + els[i];
+    create: function(config, name, id) {
+        var con = typeof name == 'function' ? name : this.types[name || config.name];
 
-                if (el) {
-                    el.removeCls(cls);
-                } else {
-                    Ext.Array.remove(frameElementCls[els[i]], cls);
-                }
-            }
+        return new con(config, id);
+    }
+}, function() {
+
+    /**
+     * Old way for creating Model classes.  Instead use:
+     *
+     *     Ext.define("MyModel", {
+     *         extend: "Ext.data.Model",
+     *         fields: []
+     *     });
+     *
+     * @param {String} name Name of the Model class.
+     * @param {Object} config A configuration object for the Model you wish to create.
+     * @return {Ext.data.Model} The newly registered Model
+     * @member Ext
+     * @deprecated 4.0.0 Use {@link Ext#define} instead.
+     */
+    Ext.regModel = function() {
+        //<debug>
+        if (Ext.isDefined(Ext.global.console)) {
+            Ext.global.console.warn('Ext.regModel has been deprecated. Models can now be created by extending Ext.data.Model: Ext.define("MyModel", {extend: "Ext.data.Model", fields: []});.');
         }
-    },
+        //</debug>
+        return this.ModelManager.registerType.apply(this.ModelManager, arguments);
+    };
+});
 
-    getElConfig : function() {
-        var result = this.autoEl || {tag: 'div'};
-        result.id = this.id;
-        return result;
-    },
+/**
+ * @singleton
+ *
+ * Provides a registry of available Plugin classes indexed by a mnemonic code known as the Plugin's ptype.
+ *
+ * A plugin may be specified simply as a *config object* as long as the correct `ptype` is specified:
+ *
+ *     {
+ *         ptype: 'gridviewdragdrop',
+ *         dragText: 'Drag and drop to reorganize'
+ *     }
+ *
+ * Or just use the ptype on its own:
+ *
+ *     'gridviewdragdrop'
+ *
+ * Alternatively you can instantiate the plugin with Ext.create:
+ *
+ *     Ext.create('Ext.view.plugin.AutoComplete', {
+ *         ptype: 'gridviewdragdrop',
+ *         dragText: 'Drag and drop to reorganize'
+ *     })
+ */
+Ext.define('Ext.PluginManager', {
+    extend: 'Ext.AbstractManager',
+    alternateClassName: 'Ext.PluginMgr',
+    singleton: true,
+    typeName: 'ptype',
 
     /**
-     * This function takes the position argument passed to onRender and returns a
-     * DOM element that you can use in the insertBefore.
-     * @param {String/Number/Element/HTMLElement} position Index, element id or element you want
-     * to put this component before.
-     * @return {HTMLElement} DOM element that you can use in the insertBefore
+     * Creates a new Plugin from the specified config object using the config object's ptype to determine the class to
+     * instantiate.
+     * @param {Object} config A configuration object for the Plugin you wish to create.
+     * @param {Function} defaultType (optional) The constructor to provide the default Plugin type if the config object does not
+     * contain a `ptype`. (Optional if the config contains a `ptype`).
+     * @return {Ext.Component} The newly instantiated Plugin.
      */
-    getInsertPosition: function(position) {
-        // Convert the position to an element to insert before
-        if (position !== undefined) {
-            if (Ext.isNumber(position)) {
-                position = this.container.dom.childNodes[position];
-            }
-            else {
-                position = Ext.getDom(position);
-            }
+    //create: function(plugin, defaultType) {
+    //    if (plugin instanceof this) {
+    //        return plugin;
+    //    } else {
+    //        var type, config = {};
+    //
+    //        if (Ext.isString(plugin)) {
+    //            type = plugin;
+    //        }
+    //        else {
+    //            type = plugin[this.typeName] || defaultType;
+    //            config = plugin;
+    //        }
+    //
+    //        return Ext.createByAlias('plugin.' + type, config);
+    //    }
+    //},
+
+    create : function(config, defaultType){
+        if (config.init) {
+            return config;
+        } else {
+            return Ext.createByAlias('plugin.' + (config.ptype || defaultType), config);
         }
 
-        return position;
+        // Prior system supported Singleton plugins.
+        //var PluginCls = this.types[config.ptype || defaultType];
+        //if (PluginCls.init) {
+        //    return PluginCls;
+        //} else {
+        //    return new PluginCls(config);
+        //}
     },
 
     /**
-     * Adds ctCls to container.
-     * @return {Ext.core.Element} The initialized container
-     * @private
+     * Returns all plugins registered with the given type. Here, 'type' refers to the type of plugin, not its ptype.
+     * @param {String} type The type to search for
+     * @param {Boolean} defaultsOnly True to only return plugins of this type where the plugin's isDefault property is
+     * truthy
+     * @return {Ext.AbstractPlugin[]} All matching plugins
      */
-    initContainer: function(container) {
-        var me = this;
-
-        // If you render a component specifying the el, we get the container
-        // of the el, and make sure we dont move the el around in the dom
-        // during the render
-        if (!container && me.el) {
-            container = me.el.dom.parentNode;
-            me.allowDomMove = false;
-        }
+    findByType: function(type, defaultsOnly) {
+        var matches = [],
+            types   = this.types;
 
-        me.container = Ext.get(container);
+        for (var name in types) {
+            if (!types.hasOwnProperty(name)) {
+                continue;
+            }
+            var item = types[name];
 
-        if (me.ctCls) {
-            me.container.addCls(me.ctCls);
+            if (item.type == type && (!defaultsOnly || (defaultsOnly === true && item.isDefault))) {
+                matches.push(item);
+            }
         }
 
-        return me.container;
-    },
-
+        return matches;
+    }
+}, function() {
     /**
-     * Initialized the renderData to be used when rendering the renderTpl.
-     * @return {Object} Object with keys and values that are going to be applied to the renderTpl
-     * @private
+     * Shorthand for {@link Ext.PluginManager#registerType}
+     * @param {String} ptype The ptype mnemonic string by which the Plugin class
+     * may be looked up.
+     * @param {Function} cls The new Plugin class.
+     * @member Ext
+     * @method preg
      */
-    initRenderData: function() {
-        var me = this;
+    Ext.preg = function() {
+        return Ext.PluginManager.registerType.apply(Ext.PluginManager, arguments);
+    };
+});
 
-        return Ext.applyIf(me.renderData, {
-            ui: me.ui,
-            uiCls: me.uiCls,
-            baseCls: me.baseCls,
-            componentCls: me.componentCls,
-            frame: me.frame
-        });
+/**
+ * Represents an HTML fragment template. Templates may be {@link #compile precompiled} for greater performance.
+ *
+ * An instance of this class may be created by passing to the constructor either a single argument, or multiple
+ * arguments:
+ *
+ * # Single argument: String/Array
+ *
+ * The single argument may be either a String or an Array:
+ *
+ * - String:
+ *
+ *       var t = new Ext.Template("<div>Hello {0}.</div>");
+ *       t.{@link #append}('some-element', ['foo']);
+ *
+ * - Array:
+ *
+ *   An Array will be combined with `join('')`.
+ *
+ *       var t = new Ext.Template([
+ *           '<div name="{id}">',
+ *               '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
+ *           '</div>',
+ *       ]);
+ *       t.{@link #compile}();
+ *       t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
+ *
+ * # Multiple arguments: String, Object, Array, ...
+ *
+ * Multiple arguments will be combined with `join('')`.
+ *
+ *     var t = new Ext.Template(
+ *         '<div name="{id}">',
+ *             '<span class="{cls}">{name} {value}</span>',
+ *         '</div>',
+ *         // a configuration object:
+ *         {
+ *             compiled: true,      // {@link #compile} immediately
+ *         }
+ *     );
+ *
+ * # Notes
+ *
+ * - For a list of available format functions, see {@link Ext.util.Format}.
+ * - `disableFormats` reduces `{@link #apply}` time when no formatting is required.
+ */
+Ext.define('Ext.Template', {
+
+    /* Begin Definitions */
+
+    requires: ['Ext.DomHelper', 'Ext.util.Format'],
+
+    inheritableStatics: {
+        /**
+         * Creates a template from the passed element's value (_display:none_ textarea, preferred) or innerHTML.
+         * @param {String/HTMLElement} el A DOM element or its id
+         * @param {Object} config (optional) Config object
+         * @return {Ext.Template} The created template
+         * @static
+         * @inheritable
+         */
+        from: function(el, config) {
+            el = Ext.getDom(el);
+            return new this(el.value || el.innerHTML, config || '');
+        }
     },
 
+    /* End Definitions */
+
     /**
-     * @private
+     * Creates new template.
+     * 
+     * @param {String...} html List of strings to be concatenated into template.
+     * Alternatively an array of strings can be given, but then no config object may be passed.
+     * @param {Object} config (optional) Config object
      */
-    getTpl: function(name) {
+    constructor: function(html) {
         var me = this,
-            prototype = me.self.prototype,
-            ownerPrototype,
-            tpl;
+            args = arguments,
+            buffer = [],
+            i = 0,
+            length = args.length,
+            value;
 
-        if (me.hasOwnProperty(name)) {
-            tpl = me[name];
-            if (tpl && !(tpl instanceof Ext.XTemplate)) {
-                me[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
-            }
+        me.initialConfig = {};
 
-            return me[name];
+        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);
+                }
+            }
+            html = buffer.join('');
+        } else {
+            if (Ext.isArray(html)) {
+                buffer.push(html.join(''));
+            } else {
+                buffer.push(html);
+            }
         }
 
-        if (!(prototype[name] instanceof Ext.XTemplate)) {
-            ownerPrototype = prototype;
-
-            do {
-                if (ownerPrototype.hasOwnProperty(name)) {
-                    tpl = ownerPrototype[name];
-                    if (tpl && !(tpl instanceof Ext.XTemplate)) {
-                        ownerPrototype[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
-                        break;
-                    }
-                }
+        // @private
+        me.html = buffer.join('');
 
-                ownerPrototype = ownerPrototype.superclass;
-            } while (ownerPrototype);
+        if (me.compiled) {
+            me.compile();
         }
-
-        return prototype[name];
     },
 
+    isTemplate: true,
+
     /**
-     * Initializes the renderTpl.
-     * @return {Ext.XTemplate} The renderTpl XTemplate instance.
-     * @private
+     * @cfg {Boolean} compiled
+     * True to immediately compile the template. Defaults to false.
      */
-    initRenderTpl: function() {
-        return this.getTpl('renderTpl');
-    },
 
     /**
-     * Function description
-     * @return {String} A CSS style string with style, padding, margin and border.
-     * @private
+     * @cfg {Boolean} disableFormats
+     * True to disable format functions in the template. If the template doesn't contain
+     * format functions, setting disableFormats to true will reduce apply time. Defaults to false.
      */
-    initStyles: function() {
-        var style = {},
-            me = this,
-            Element = Ext.core.Element;
-
-        if (Ext.isString(me.style)) {
-            style = Element.parseStyles(me.style);
-        } else {
-            style = Ext.apply({}, me.style);
-        }
-
-        // Convert the padding, margin and border properties from a space seperated string
-        // into a proper style string
-        if (me.padding !== undefined) {
-            style.padding = Element.unitizeBox((me.padding === true) ? 5 : me.padding);
-        }
-
-        if (me.margin !== undefined) {
-            style.margin = Element.unitizeBox((me.margin === true) ? 5 : me.margin);
-        }
+    disableFormats: false,
 
-        delete me.style;
-        return style;
-    },
+    re: /\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
 
     /**
-     * Initializes this components contents. It checks for the properties
-     * html, contentEl and tpl/data.
-     * @private
+     * Returns an HTML fragment of this template with the specified values applied.
+     *
+     * @param {Object/Array} values The template values. Can be an array if your params are numeric:
+     *
+     *     var tpl = new Ext.Template('Name: {0}, Age: {1}');
+     *     tpl.applyTemplate(['John', 25]);
+     *
+     * or an object:
+     *
+     *     var tpl = new Ext.Template('Name: {name}, Age: {age}');
+     *     tpl.applyTemplate({name: 'John', age: 25});
+     *
+     * @return {String} The HTML fragment
      */
-    initContent: function() {
+    applyTemplate: function(values) {
         var me = this,
-            target = me.getTargetEl(),
-            contentEl,
-            pre;
-
-        if (me.html) {
-            target.update(Ext.core.DomHelper.markup(me.html));
-            delete me.html;
-        }
+            useFormat = me.disableFormats !== true,
+            fm = Ext.util.Format,
+            tpl = me;
 
-        if (me.contentEl) {
-            contentEl = Ext.get(me.contentEl);
-            pre = Ext.baseCSSPrefix;
-            contentEl.removeCls([pre + 'hidden', pre + 'hide-display', pre + 'hide-offsets', pre + 'hide-nosize']);
-            target.appendChild(contentEl.dom);
+        if (me.compiled) {
+            return me.compiled(values);
         }
-
-        if (me.tpl) {
-            // Make sure this.tpl is an instantiated XTemplate
-            if (!me.tpl.isTemplate) {
-                me.tpl = Ext.create('Ext.XTemplate', me.tpl);
+        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);
+                }
             }
-
-            if (me.data) {
-                me.tpl[me.tplWriteMode](target, me.data);
-                delete me.data;
+            else {
+                return values[name] !== undefined ? values[name] : "";
             }
         }
+        return me.html.replace(me.re, fn);
     },
 
-    // @private
-    initEvents : function() {
+    /**
+     * Sets the HTML used as the template and optionally compiles it.
+     * @param {String} html
+     * @param {Boolean} compile (optional) True to compile the template.
+     * @return {Ext.Template} this
+     */
+    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,
-            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);
-                    }
+            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 + "'].join('');};";
+        eval(body);
+        return me;
     },
 
     /**
-     * Sets references to elements inside the component. E.g body -> x-panel-body
-     * @private
+     * 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
      */
-    applyRenderSelectors: function() {
-        var selectors = this.renderSelectors || {},
-            el = this.el.dom,
-            selector;
-
-        for (selector in selectors) {
-            if (selectors.hasOwnProperty(selector) && selectors[selector]) {
-                this[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], el));
-            }
-        }
+    insertFirst: function(el, values, returnElement) {
+        return this.doInsert('afterBegin', el, values, returnElement);
     },
 
     /**
-     * Tests whether this Component matches the selector string.
-     * @param {String} selector The selector string to test against.
-     * @return {Boolean} True if this Component matches the selector.
+     * 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
      */
-    is: function(selector) {
-        return Ext.ComponentQuery.is(this, selector);
+    insertBefore: function(el, values, returnElement) {
+        return this.doInsert('beforeBegin', el, values, returnElement);
     },
 
     /**
-     * <p>Walks up the <code>ownerCt</code> axis looking for an ancestor Container which matches
-     * the passed simple selector.</p>
-     * <p>Example:<pre><code>
-var owningTabPanel = grid.up('tabpanel');
-</code></pre>
-     * @param {String} selector Optional. The simple selector to test.
-     * @return {Container} The matching ancestor Container (or <code>undefined</code> if no match was found).
+     * 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
      */
-    up: function(selector) {
-        var result = this.ownerCt;
-        if (selector) {
-            for (; result; result = result.ownerCt) {
-                if (Ext.ComponentQuery.is(result, selector)) {
-                    return result;
-                }
-            }
-        }
-        return result;
+    insertAfter: function(el, values, returnElement) {
+        return this.doInsert('afterEnd', el, values, returnElement);
     },
 
     /**
-     * <p>Returns the next sibling of this Component.</p>
-     * <p>Optionally selects the next sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector.</p>
-     * <p>May also be refered to as <code><b>next()</b></code></p>
-     * <p>Note that this is limited to siblings, and if no siblings of the item match, <code>null</code> is returned. Contrast with {@link #nextNode}</p>
-     * @param {String} selector Optional A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following items.
-     * @returns The next sibling (or the next sibling which matches the selector). Returns null if there is no matching sibling.
+     * 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
      */
-    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;
+    append: function(el, values, returnElement) {
+        return this.doInsert('beforeEnd', el, values, returnElement);
     },
 
-    /**
-     * <p>Returns the previous sibling of this Component.</p>
-     * <p>Optionally selects the previous sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector.</p>
-     * <p>May also be refered to as <code><b>prev()</b></code></p>
-     * <p>Note that this is limited to siblings, and if no siblings of the item match, <code>null</code> is returned. Contrast with {@link #previousNode}</p>
-     * @param {String} selector Optional. A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding items.
-     * @returns The previous sibling (or the previous sibling which matches the selector). Returns null if there is no matching sibling.
-     */
-    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;
+    doInsert: function(where, el, values, returnEl) {
+        el = Ext.getDom(el);
+        var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
+        return returnEl ? Ext.get(newNode, true) : newNode;
     },
 
     /**
-     * <p>Returns the previous node in the Component tree in tree traversal order.</p>
-     * <p>Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will
-     * walk the tree in reverse order to attempt to find a match. Contrast with {@link #previousSibling}.</p>
-     * @param {String} selector Optional. A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding nodes.
-     * @returns The previous node (or the previous node which matches the selector). Returns null if there is no matching node.
+     * 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
      */
-    previousNode: function(selector, includeSelf) {
-        var node = this,
-            result,
-            it, len, i;
-
-        // If asked to include self, test me
-        if (includeSelf && node.is(selector)) {
-            return node;
-        }
-
-        result = this.prev(selector);
-        if (result) {
-            return result;
-        }
-
-        if (node.ownerCt) {
-            for (it = node.ownerCt.items.items, i = Ext.Array.indexOf(it, node) - 1; i > -1; i--) {
-                if (it[i].query) {
-                    result = it[i].query(selector);
-                    result = result[result.length - 1];
-                    if (result) {
-                        return result;
-                    }
-                }
-            }
-            return node.ownerCt.previousNode(selector, true);
-        }
-    },
+    overwrite: function(el, values, returnElement) {
+        el = Ext.getDom(el);
+        el.innerHTML = this.applyTemplate(values);
+        return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
+    }
+}, function() {
 
     /**
-     * <p>Returns the next node in the Component tree in tree traversal order.</p>
-     * <p>Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will
-     * walk the tree to attempt to find a match. Contrast with {@link #nextSibling}.</p>
-     * @param {String} selector Optional A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following nodes.
-     * @returns The next node (or the next node which matches the selector). Returns null if there is no matching node.
+     * @method apply
+     * @member Ext.Template
+     * Alias for {@link #applyTemplate}.
+     * @alias Ext.Template#applyTemplate
      */
-    nextNode: function(selector, includeSelf) {
-        var node = this,
-            result,
-            it, len, i;
-
-        // If asked to include self, test me
-        if (includeSelf && node.is(selector)) {
-            return node;
-        }
+    this.createAlias('apply', 'applyTemplate');
+});
 
-        result = this.next(selector);
-        if (result) {
-            return result;
-        }
+/**
+ * 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: 'Tommy Maintz',
+ *         title: 'Lead Developer',
+ *         company: 'Sencha Inc.',
+ *         email: 'tommy@sencha.com',
+ *         address: '5 Cups Drive',
+ *         city: 'Palo Alto',
+ *         state: 'CA',
+ *         zip: '44102',
+ *         drinks: ['Coffee', 'Soda', 'Water'],
+ *         kids: [
+ *             {
+ *                 name: 'Joshua',
+ *                 age:3
+ *             },
+ *             {
+ *                 name: 'Matthew',
+ *                 age:2
+ *             },
+ *             {
+ *                 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>       // loop through array at root node
+ *     <tpl for="foo">...</tpl>     // loop through array at foo node
+ *     <tpl for="foo.bar">...</tpl> // loop through array at foo.bar node
+ *
+ * Using the sample data above:
+ *
+ *     var tpl = new Ext.XTemplate(
+ *         '<p>Kids: ',
+ *         '<tpl for=".">',       // process the data.kids node
+ *             '<p>{#}. {name}</p>',  // use current array index to autonumber
+ *         '</tpl></p>'
+ *     );
+ *     tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
+ *
+ * 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">',     // interrogate the kids property within the data
+ *             '<p>{name}</p>',
+ *         '</tpl></p>'
+ *     );
+ *     tpl.overwrite(panel.body, data);  // pass the root node of the data object
+ *
+ * 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. Notes:
+ *
+ * - Double quotes must be encoded if used within the conditional
+ * - There is no else operator -- if needed, two opposite if statements should be used.
+ *
+ * Examples:
+ *
+ *     <tpl if="age > 1 && age < 10">Child</tpl>
+ *     <tpl if="age >= 10 && age < 18">Teenager</tpl>
+ *     <tpl if="this.isGirl(name)">...</tpl>
+ *     <tpl if="id==\'download\'">...</tpl>
+ *     <tpl if="needsIcon"><img src="{icon}" class="{iconCls}"/></tpl>
+ *     // no good:
+ *     <tpl if="name == "Tommy"">Hello</tpl>
+ *     // encode " if it is part of the condition, e.g.
+ *     <tpl if="name == &quot;Tommy&quot;">Hello</tpl>
+ *
+ * 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);
+ *
+ * # 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">',  // <-- Note that the > is encoded
+ *                 '<p>{#}: {name}</p>',  // <-- Auto-number each item
+ *                 '<p>In 5 Years: {age+5}</p>',  // <-- Basic math
+ *                 '<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. There are some special
+ * variables available in that code:
+ *
+ * - **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>'
+ *      );
+ *     tpl.overwrite(panel.body, data);
+ *
+ * # 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>',
+ *              // use opposite if statement to simulate 'else' processing:
+ *             '<tpl if="this.isGirl(name) == false">',
+ *                 '<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 == 'Sara Grace';
+ *             },
+ *             isBaby: function(age){
+ *                return age < 1;
+ *             }
+ *         }
+ *     );
+ *     tpl.overwrite(panel.body, data);
+ */
+Ext.define('Ext.XTemplate', {
 
-        if (node.ownerCt) {
-            for (it = node.ownerCt.items, i = it.indexOf(node) + 1, it = it.items, len = it.length; i < len; i++) {
-                if (it[i].down) {
-                    result = it[i].down(selector);
-                    if (result) {
-                        return result;
-                    }
-                }
-            }
-            return node.ownerCt.nextNode(selector);
-        }
-    },
+    /* Begin Definitions */
 
-    /**
-     * Retrieves the id of this component.
-     * Will autogenerate an id if one has not already been set.
-     */
-    getId : function() {
-        return this.id || (this.id = 'ext-comp-' + (this.getAutoId()));
-    },
+    extend: 'Ext.Template',
 
-    getItemId : function() {
-        return this.itemId || this.id;
-    },
+    /* End Definitions */
 
-    /**
-     * Retrieves the top level element representing this component.
-     */
-    getEl : function() {
-        return this.el;
-    },
+    argsRe: /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
+    nameRe: /^<tpl\b[^>]*?for="(.*?)"/,
+    ifRe: /^<tpl\b[^>]*?if="(.*?)"/,
+    execRe: /^<tpl\b[^>]*?exec="(.*?)"/,
+    constructor: function() {
+        this.callParent(arguments);
 
-    /**
-     * This is used to determine where to insert the 'html', 'contentEl' and 'items' in this component.
-     * @private
-     */
-    getTargetEl: function() {
-        return this.frameBody || this.el;
-    },
+        var me = this,
+            html = me.html,
+            argsRe = me.argsRe,
+            nameRe = me.nameRe,
+            ifRe = me.ifRe,
+            execRe = me.execRe,
+            id = 0,
+            tpls = [],
+            VALUES = 'values',
+            PARENT = 'parent',
+            XINDEX = 'xindex',
+            XCOUNT = 'xcount',
+            RETURN = 'return ',
+            WITHVALUES = 'with(values){ ',
+            m, matchName, matchIf, matchExec, exp, fn, exec, name, i;
 
-    /**
-     * <p>Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
-     * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).</p>
-     * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
-     * to participate in determination of inherited xtypes.</b></p>
-     * <p>For a list of all available xtypes, see the {@link Ext.Component} header.</p>
-     * <p>Example usage:</p>
-     * <pre><code>
-var t = new Ext.form.field.Text();
-var isText = t.isXType('textfield');        // true
-var isBoxSubclass = t.isXType('field');       // true, descended from Ext.form.field.Base
-var isBoxInstance = t.isXType('field', true); // false, not a direct Ext.form.field.Base instance
-</code></pre>
-     * @param {String} xtype The xtype to check for this Component
-     * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is
-     * the default), or true to check whether this Component is directly of the specified xtype.
-     * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
-     */
-    isXType: function(xtype, shallow) {
-        //assume a string by default
-        if (Ext.isFunction(xtype)) {
-            xtype = xtype.xtype;
-            //handle being passed the class, e.g. Ext.Component
-        } else if (Ext.isObject(xtype)) {
-            xtype = xtype.statics().xtype;
-            //handle being passed an instance
-        }
+        html = ['<tpl>', html, '</tpl>'].join('');
 
-        return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1: this.self.xtype == xtype;
-    },
+        while ((m = html.match(argsRe))) {
+            exp = null;
+            fn = null;
+            exec = null;
+            matchName = m[0].match(nameRe);
+            matchIf = m[0].match(ifRe);
+            matchExec = m[0].match(execRe);
 
-    /**
-     * <p>Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all
-     * available xtypes, see the {@link Ext.Component} header.</p>
-     * <p><b>If using your own subclasses, be aware that a Component must register its own xtype
-     * to participate in determination of inherited xtypes.</b></p>
-     * <p>Example usage:</p>
-     * <pre><code>
-var t = new Ext.form.field.Text();
-alert(t.getXTypes());  // alerts 'component/field/textfield'
-</code></pre>
-     * @return {String} The xtype hierarchy string
-     */
-    getXTypes: function() {
-        var self = this.self,
-            xtypes      = [],
-            parentPrototype  = this,
-            xtype;
+            exp = matchIf ? matchIf[1] : null;
+            if (exp) {
+                fn = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + 'try{' + RETURN + Ext.String.htmlDecode(exp) + ';}catch(e){return;}}');
+            }
 
-        if (!self.xtypes) {
-            while (parentPrototype && Ext.getClass(parentPrototype)) {
-                xtype = Ext.getClass(parentPrototype).xtype;
+            exp = matchExec ? matchExec[1] : null;
+            if (exp) {
+                exec = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + Ext.String.htmlDecode(exp) + ';}');
+            }
 
-                if (xtype !== undefined) {
-                    xtypes.unshift(xtype);
+            name = matchName ? matchName[1] : null;
+            if (name) {
+                if (name === '.') {
+                    name = VALUES;
+                } else if (name === '..') {
+                    name = PARENT;
                 }
-
-                parentPrototype = parentPrototype.superclass;
+                name = Ext.functionFactory(VALUES, PARENT, 'try{' + WITHVALUES + RETURN + name + ';}}catch(e){return;}');
             }
 
-            self.xtypeChain = xtypes;
-            self.xtypes = xtypes.join('/');
-        }
-
-        return self.xtypes;
-    },
-
-    /**
-     * Update the content area of a component.
-     * @param {Mixed} htmlOrData
-     * If this component has been configured with a template via the tpl config
-     * then it will use this argument as data to populate the template.
-     * If this component was not configured with a template, the components
-     * content area will be updated via Ext.core.Element update
-     * @param {Boolean} loadScripts
-     * (optional) Only legitimate when using the html configuration. Defaults to false
-     * @param {Function} callback
-     * (optional) Only legitimate when using the html configuration. Callback to execute when scripts have finished loading
-     */
-    update : function(htmlOrData, loadScripts, cb) {
-        var me = this;
+            tpls.push({
+                id: id,
+                target: name,
+                exec: exec,
+                test: fn,
+                body: m[1] || ''
+            });
 
-        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.core.DomHelper.markup(htmlOrData) : htmlOrData;
-            if (me.rendered) {
-                me.getTargetEl().update(me.html, loadScripts, cb);
-            }
+            html = html.replace(m[0], '{xtpl' + id + '}');
+            id = id + 1;
         }
 
-        if (me.rendered) {
-            me.doComponentLayout();
+        for (i = tpls.length - 1; i >= 0; --i) {
+            me.compileTpl(tpls[i]);
         }
+        me.master = tpls[tpls.length - 1];
+        me.tpls = tpls;
     },
 
-    /**
-     * Convenience function to hide or show this component by boolean.
-     * @param {Boolean} visible True to show, false to hide
-     * @return {Ext.Component} this
-     */
-    setVisible : function(visible) {
-        return this[visible ? 'show': 'hide']();
+    // @private
+    applySubTemplate: function(id, values, parent, xindex, xcount) {
+        var me = this, t = me.tpls[id];
+        return t.compiled.call(me, values, parent, xindex, xcount);
     },
 
     /**
-     * Returns true if this component is visible.
-     * @param {Boolean} deep. <p>Optional. Pass <code>true</code> to interrogate the visibility status of all
-     * parent Containers to determine whether this Component is truly visible to the user.</p>
-     * <p>Generally, to determine whether a Component is hidden, the no argument form is needed. For example
-     * when creating dynamically laid out UIs in a hidden Container before showing them.</p>
-     * @return {Boolean} True if this component is visible, false otherwise.
+     * @cfg {RegExp} codeRe
+     * The regular expression used to match code variables. Default: matches {[expression]}.
      */
-    isVisible: function(deep) {
-        var me = this,
-            child = me,
-            visible = !me.hidden,
-            ancestor = me.ownerCt;
-
-        // Clear hiddenOwnerCt property
-        me.hiddenAncestor = false;
-        if (me.destroyed) {
-            return false;
-        }
-
-        if (deep && visible && me.rendered && ancestor) {
-            while (ancestor) {
-                // If any ancestor is hidden, then this is hidden.
-                // If an ancestor Panel (only Panels have a collapse method) is collapsed,
-                // then its layoutTarget (body) is hidden, so this is hidden unless its within a
-                // docked item; they are still visible when collapsed (Unless they themseves are hidden)
-                if (ancestor.hidden || (ancestor.collapsed &&
-                        !(ancestor.getDockedItems && Ext.Array.contains(ancestor.getDockedItems(), child)))) {
-                    // Store hiddenOwnerCt property if needed
-                    me.hiddenAncestor = ancestor;
-                    visible = false;
-                    break;
-                }
-                child = ancestor;
-                ancestor = ancestor.ownerCt;
-            }
-        }
-        return visible;
-    },
+    codeRe: /\{\[((?:\\\]|.|\n)*?)\]\}/g,
 
     /**
-     * Enable the component
-     * @param {Boolean} silent
-     * Passing false will supress the 'enable' event from being fired.
+     * @cfg {Boolean} compiled
+     * Only applies to {@link Ext.Template}, XTemplates are compiled automatically.
      */
-    enable: function(silent) {
-        var me = this;
 
-        if (me.rendered) {
-            me.el.removeCls(me.disabledCls);
-            me.el.dom.disabled = false;
-            me.onEnable();
-        }
+    re: /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?\}/g,
 
-        me.disabled = false;
+    // @private
+    compileTpl: function(tpl) {
+        var fm = Ext.util.Format,
+            me = this,
+            useFormat = me.disableFormats !== true,
+            body, bodyReturn, evaluatedFn;
 
-        if (silent !== true) {
-            me.fireEvent('enable', me);
-        }
+        function fn(m, name, format, args, math) {
+            var v;
+            // name is what is inside the {}
+            // Name begins with xtpl, use a Sub Template
+            if (name.substr(0, 4) == 'xtpl') {
+                return "',this.applySubTemplate(" + name.substr(4) + ", values, parent, xindex, xcount),'";
+            }
+            // name = "." - Just use the values object.
+            if (name == '.') {
+                // filter to not include arrays/objects/nulls
+                v = 'Ext.Array.indexOf(["string", "number", "boolean"], typeof values) > -1 || Ext.isDate(values) ? values : ""';
+            }
 
-        return me;
-    },
+            // name = "#" - Use the xindex
+            else if (name == '#') {
+                v = 'xindex';
+            }
+            else if (name.substr(0, 7) == "parent.") {
+                v = name;
+            }
+            // name has a . in it - Use object literal notation, starting from values
+            else if (name.indexOf('.') != -1) {
+                v = "values." + name;
+            }
 
-    /**
-     * Disable the component.
-     * @param {Boolean} silent
-     * Passing true, will supress the 'disable' event from being fired.
-     */
-    disable: function(silent) {
-        var me = this;
+            // name is a property of values
+            else {
+                v = "values['" + name + "']";
+            }
+            if (math) {
+                v = '(' + v + math + ')';
+            }
+            if (format && useFormat) {
+                args = args ? ',' + args : "";
+                if (format.substr(0, 5) != "this.") {
+                    format = "fm." + format + '(';
+                }
+                else {
+                    format = 'this.' + format.substr(5) + '(';
+                }
+            }
+            else {
+                args = '';
+                format = "(" + v + " === undefined ? '' : ";
+            }
+            return "'," + format + v + args + "),'";
+        }
 
-        if (me.rendered) {
-            me.el.addCls(me.disabledCls);
-            me.el.dom.disabled = true;
-            me.onDisable();
+        function codeFn(m, code) {
+            // Single quotes get escaped when the template is compiled, however we want to undo this when running code.
+            return "',(" + code.replace(me.compileARe, "'") + "),'";
         }
 
-        me.disabled = true;
+        bodyReturn = tpl.body.replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn).replace(me.codeRe, codeFn);
+        body = "evaluatedFn = function(values, parent, xindex, xcount){return ['" + bodyReturn + "'].join('');};";
+        eval(body);
 
-        if (silent !== true) {
-            me.fireEvent('disable', me);
-        }
+        tpl.compiled = function(values, parent, xindex, xcount) {
+            var vs,
+                length,
+                buffer,
+                i;
 
-        return me;
-    },
+            if (tpl.test && !tpl.test.call(me, values, parent, xindex, xcount)) {
+                return '';
+            }
 
-    // @private
-    onEnable: function() {
-        if (this.maskOnDisable) {
-            this.el.unmask();
-        }
-    },
+            vs = tpl.target ? tpl.target.call(me, values, parent) : values;
+            if (!vs) {
+               return '';
+            }
 
-    // @private
-    onDisable : function() {
-        if (this.maskOnDisable) {
-            this.el.mask();
-        }
-    },
+            parent = tpl.target ? values : parent;
+            if (tpl.target && Ext.isArray(vs)) {
+                buffer = [];
+                length = vs.length;
+                if (tpl.exec) {
+                    for (i = 0; i < length; i++) {
+                        buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
+                        tpl.exec.call(me, vs[i], parent, i + 1, length);
+                    }
+                } else {
+                    for (i = 0; i < length; i++) {
+                        buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
+                    }
+                }
+                return buffer.join('');
+            }
 
-    /**
-     * Method to determine whether this Component is currently disabled.
-     * @return {Boolean} the disabled state of this Component.
-     */
-    isDisabled : function() {
-        return this.disabled;
-    },
+            if (tpl.exec) {
+                tpl.exec.call(me, vs, parent, xindex, xcount);
+            }
+            return evaluatedFn.call(me, vs, parent, xindex, xcount);
+        };
 
-    /**
-     * Enable or disable the component.
-     * @param {Boolean} disabled
-     */
-    setDisabled : function(disabled) {
-        return this[disabled ? 'disable': 'enable']();
+        return this;
     },
 
-    /**
-     * Method to determine whether this Component is currently set to hidden.
-     * @return {Boolean} the hidden state of this Component.
-     */
-    isHidden : function() {
-        return this.hidden;
+    // inherit docs from Ext.Template
+    applyTemplate: function(values) {
+        return this.master.compiled.call(this, values, {}, 1, 1);
     },
 
     /**
-     * Adds a CSS class to the top level element representing this component.
-     * @param {String} cls The CSS class name to add
-     * @return {Ext.Component} Returns the Component to allow method chaining.
+     * Does nothing. XTemplates are compiled automatically, so this function simply returns this.
+     * @return {Ext.XTemplate} this
      */
-    addCls : function(className) {
-        var me = this;
-        if (!className) {
-            return me;
-        }
-        if (!Ext.isArray(className)){
-            className = className.replace(me.trimRe, '').split(me.spacesRe);
-        }
-        if (me.rendered) {
-            me.el.addCls(className);
-        }
-        else {
-            me.additionalCls = Ext.Array.unique(me.additionalCls.concat(className));
-        }
-        return me;
-    },
-
-    /**
-     * @deprecated 4.0 Replaced by {@link #addCls}
-     * Adds a CSS class to the top level element representing this component.
-     * @param {String} cls The CSS class name to add
-     * @return {Ext.Component} Returns the Component to allow method chaining.
-     */
-    addClass : function() {
-        return this.addCls.apply(this, arguments);
+    compile: function() {
+        return this;
+    }
+}, function() {
+    // re-create the alias, inheriting it from Ext.Template doesn't work as intended.
+    this.createAlias('apply', 'applyTemplate');
+});
+
+/**
+ * @class Ext.app.Controller
+ *
+ * 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.
+ *
+ * <u>Using refs</u>
+ *
+ * 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.
+ *
+ * <u>Generated getter methods</u>
+ *
+ * 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.
+ *
+ * <u>Further Reading</u>
+ *
+ * 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'
     },
 
     /**
-     * Removes a CSS class from the top level element representing this component.
-     * @returns {Ext.Component} Returns the Component to allow method chaining.
+     * @cfg {String} id The id of this controller. You can use this id when dispatching.
+     */
+    
+    /**
+     * @cfg {String[]} models
+     * Array of models to require from AppName.model namespace. For example:
+     * 
+     *     Ext.define("MyApp.controller.Foo", {
+     *         extend: "Ext.app.Controller",
+     *         models: ['User', 'Vehicle']
+     *     });
+     * 
+     * This is equivalent of:
+     * 
+     *     Ext.define("MyApp.controller.Foo", {
+     *         extend: "Ext.app.Controller",
+     *         requires: ['MyApp.model.User', 'MyApp.model.Vehicle']
+     *     });
+     * 
      */
-    removeCls : function(className) {
-        var me = this;
 
-        if (!className) {
-            return me;
-        }
-        if (!Ext.isArray(className)){
-            className = className.replace(me.trimRe, '').split(me.spacesRe);
-        }
-        if (me.rendered) {
-            me.el.removeCls(className);
-        }
-        else if (me.additionalCls.length) {
-            Ext.each(className, function(cls) {
-                Ext.Array.remove(me.additionalCls, cls);
-            });
-        }
-        return me;
-    },
+    /**
+     * @cfg {String[]} views
+     * Array of views to require from AppName.view namespace. For example:
+     * 
+     *     Ext.define("MyApp.controller.Foo", {
+     *         extend: "Ext.app.Controller",
+     *         views: ['List', 'Detail']
+     *     });
+     * 
+     * This is equivalent of:
+     * 
+     *     Ext.define("MyApp.controller.Foo", {
+     *         extend: "Ext.app.Controller",
+     *         requires: ['MyApp.view.List', 'MyApp.view.Detail']
+     *     });
+     * 
+     */
 
-    //<debug>
-    removeClass : function() {
-        if (Ext.isDefined(Ext.global.console)) {
-            Ext.global.console.warn('Ext.Component: removeClass has been deprecated. Please use removeCls.');
+    /**
+     * @cfg {String[]} stores
+     * Array of stores to require from AppName.store namespace. For example:
+     * 
+     *     Ext.define("MyApp.controller.Foo", {
+     *         extend: "Ext.app.Controller",
+     *         stores: ['Users', 'Vehicles']
+     *     });
+     * 
+     * This is equivalent of:
+     * 
+     *     Ext.define("MyApp.controller.Foo", {
+     *         extend: "Ext.app.Controller",
+     *         requires: ['MyApp.store.Users', 'MyApp.store.Vehicles']
+     *     });
+     * 
+     */
+
+    onClassExtended: function(cls, data) {
+        var className = Ext.getClassName(cls),
+            match = className.match(/^(.*)\.controller\./);
+
+        if (match !== null) {
+            var namespace = Ext.Loader.getPrefix(className) || match[1],
+                onBeforeClassCreated = data.onBeforeClassCreated,
+                requires = [],
+                modules = ['model', 'view', 'store'],
+                prefix;
+
+            data.onBeforeClassCreated = function(cls, data) {
+                var i, ln, module,
+                    items, j, subLn, item;
+
+                for (i = 0,ln = modules.length; i < ln; i++) {
+                    module = modules[i];
+
+                    items = Ext.Array.from(data[module + 's']);
+
+                    for (j = 0,subLn = items.length; j < subLn; j++) {
+                        item = items[j];
+
+                        prefix = Ext.Loader.getPrefix(item);
+
+                        if (prefix === '' || prefix === item) {
+                            requires.push(namespace + '.' + module + '.' + item);
+                        }
+                        else {
+                            requires.push(item);
+                        }
+                    }
+                }
+
+                Ext.require(requires, Ext.Function.pass(onBeforeClassCreated, arguments, this));
+            };
         }
-        return this.removeCls.apply(this, arguments);
     },
-    //</debug>
 
-    addOverCls: function() {
-        var me = this;
-        if (!me.disabled) {
-            me.el.addCls(me.overCls);
+    /**
+     * Creates new Controller.
+     * @param {Object} config (optional) Config object.
+     */
+    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);
         }
     },
 
-    removeOverCls: function() {
-        this.el.removeCls(this.overCls);
-    },
+    /**
+     * A template 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.
+     * 
+     * @param {Ext.app.Application} application
+     * @template
+     */
+    init: function(application) {},
 
-    addListener : function(element, listeners, scope, options) {
-        var me = this,
-            fn,
-            option;
+    /**
+     * A template method like {@link #init}, but called after the viewport is created.
+     * This is called after the {@link Ext.app.Application#launch launch} method of Application is executed.
+     * 
+     * @param {Ext.app.Application} application
+     * @template
+     */
+    onLaunch: function(application) {},
 
-        if (Ext.isString(element) && (Ext.isObject(listeners) || options && options.element)) {
-            if (options.element) {
-                fn = listeners;
+    createGetters: function(type, refs) {
+        type = Ext.String.capitalize(type);
+        Ext.Array.each(refs, function(ref) {
+            var fn = 'get',
+                parts = ref.split('.');
 
-                listeners = {};
-                listeners[element] = fn;
-                element = options.element;
-                if (scope) {
-                    listeners.scope = scope;
-                }
+            // Handle namespaced class names. E.g. feed.Add becomes getFeedAddView etc.
+            Ext.Array.each(parts, function(part) {
+                fn += Ext.String.capitalize(part);
+            });
+            fn += type;
 
-                for (option in options) {
-                    if (options.hasOwnProperty(option)) {
-                        if (me.eventOptionsRe.test(option)) {
-                            listeners[option] = options[option];
-                        }
-                    }
-                }
+            if (!this[fn]) {
+                this[fn] = Ext.Function.pass(this['get' + type], [ref], this);
             }
+            // Execute it right away
+            this[fn](ref);
+        },
+        this);
+    },
 
-            // At this point we have a variable called element,
-            // and a listeners object that can be passed to on
-            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);
+    ref: function(refs) {
+        var me = this;
+        refs = Ext.Array.from(refs);
+        Ext.Array.each(refs, function(info) {
+            var ref = info.ref,
+                fn = 'get' + Ext.String.capitalize(ref);
+            if (!me[fn]) {
+                me[fn] = Ext.Function.pass(me.getRef, [ref, info], me);
             }
-        }
-
-        return me.mixins.observable.addListener.apply(me, arguments);
+        });
     },
 
-    // inherit docs
-    removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
+    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,
-            element = managedListener.options ? managedListener.options.element : null;
+            selector = info.selector,
+            cached = me.refCache[ref];
 
-        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);
-                    }
-                }
+        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;
+                });
             }
-        } else {
-            return me.mixins.observable.removeManagedListenerItem.apply(me, arguments);
         }
+
+        return cached;
     },
 
     /**
-     * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
-     * @return {Ext.container.Container} the Container which owns this Component.
+     * Adds listeners to components selected via {@link Ext.ComponentQuery}. Accepts an
+     * object containing component paths mapped to a hash of listener functions.
+     *
+     * In the following example the `updateUser` function is mapped to to the `click`
+     * event on a button component, which is a child of the `useredit` component.
+     *
+     *     Ext.define('AM.controller.Users', {
+     *         init: function() {
+     *             this.control({
+     *                 'useredit button[action=save]': {
+     *                     click: this.updateUser
+     *                 }
+     *             });
+     *         },
+     *
+     *         updateUser: function(button) {
+     *             console.log('clicked the Save button');
+     *         }
+     *     });
+     *
+     * See {@link Ext.ComponentQuery} for more information on component selectors.
+     *
+     * @param {String/Object} selectors If a String, the second argument is used as the
+     * listeners, otherwise an object of selectors -> listeners is assumed
+     * @param {Object} listeners
      */
-    getBubbleTarget : function() {
-        return this.ownerCt;
+    control: function(selectors, listeners) {
+        this.application.control(selectors, listeners, this);
     },
 
     /**
-     * Method to determine whether this Component is floating.
-     * @return {Boolean} the floating state of this component.
+     * Returns instance of a {@link Ext.app.Controller controller} with the given name.
+     * When controller doesn't exist yet, it's created.
+     * @param {String} name
+     * @return {Ext.app.Controller} a controller instance.
      */
-    isFloating : function() {
-        return this.floating;
+    getController: function(name) {
+        return this.application.getController(name);
     },
 
     /**
-     * Method to determine whether this Component is draggable.
-     * @return {Boolean} the draggable state of this component.
+     * Returns instance of a {@link Ext.data.Store Store} with the given name.
+     * When store doesn't exist yet, it's created.
+     * @param {String} name
+     * @return {Ext.data.Store} a store instance.
      */
-    isDraggable : function() {
-        return !!this.draggable;
+    getStore: function(name) {
+        return this.application.getStore(name);
     },
 
     /**
-     * Method to determine whether this Component is droppable.
-     * @return {Boolean} the droppable state of this component.
+     * Returns a {@link Ext.data.Model Model} class with the given name.
+     * A shorthand for using {@link Ext.ModelManager#getModel}.
+     * @param {String} name
+     * @return {Ext.data.Model} a model class.
      */
-    isDroppable : function() {
-        return !!this.droppable;
+    getModel: function(model) {
+        return this.application.getModel(model);
     },
 
     /**
-     * @private
-     * Method to manage awareness of when components are added to their
-     * respective Container, firing an added event.
-     * References are established at add time rather than at render time.
-     * @param {Ext.container.Container} container Container which holds the component
-     * @param {number} pos Position at which the component was added
+     * Returns a View class with the given name.  To create an instance of the view,
+     * you can use it like it's used by Application to create the Viewport:
+     * 
+     *     this.getView('Viewport').create();
+     * 
+     * @param {String} name
+     * @return {Ext.Base} a view class.
      */
-    onAdded : function(container, pos) {
-        this.ownerCt = container;
-        this.fireEvent('added', this, container, pos);
-    },
+    getView: function(view) {
+        return this.application.getView(view);
+    }
+});
+
+/**
+ * @author Don Griffin
+ *
+ * This class is a base for all id generators. It also provides lookup of id generators by
+ * their id.
+ * 
+ * Generally, id generators are used to generate a primary key for new model instances. There
+ * are different approaches to solving this problem, so this mechanism has both simple use
+ * cases and is open to custom implementations. A {@link Ext.data.Model} requests id generation
+ * using the {@link Ext.data.Model#idgen} property.
+ *
+ * # Identity, Type and Shared IdGenerators
+ *
+ * It is often desirable to share IdGenerators to ensure uniqueness or common configuration.
+ * This is done by giving IdGenerator instances an id property by which they can be looked
+ * up using the {@link #get} method. To configure two {@link Ext.data.Model Model} classes
+ * to share one {@link Ext.data.SequentialIdGenerator sequential} id generator, you simply
+ * assign them the same id:
+ *
+ *     Ext.define('MyApp.data.MyModelA', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: {
+ *             type: 'sequential',
+ *             id: 'foo'
+ *         }
+ *     });
+ *
+ *     Ext.define('MyApp.data.MyModelB', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: {
+ *             type: 'sequential',
+ *             id: 'foo'
+ *         }
+ *     });
+ *
+ * To make this as simple as possible for generator types that are shared by many (or all)
+ * Models, the IdGenerator types (such as 'sequential' or 'uuid') are also reserved as
+ * generator id's. This is used by the {@link Ext.data.UuidGenerator} which has an id equal
+ * to its type ('uuid'). In other words, the following Models share the same generator:
+ *
+ *     Ext.define('MyApp.data.MyModelX', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'uuid'
+ *     });
+ *
+ *     Ext.define('MyApp.data.MyModelY', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'uuid'
+ *     });
+ *
+ * This can be overridden (by specifying the id explicitly), but there is no particularly
+ * good reason to do so for this generator type.
+ *
+ * # Creating Custom Generators
+ * 
+ * An id generator should derive from this class and implement the {@link #generate} method.
+ * The constructor will apply config properties on new instances, so a constructor is often
+ * not necessary.
+ *
+ * To register an id generator type, a derived class should provide an `alias` like so:
+ *
+ *     Ext.define('MyApp.data.CustomIdGenerator', {
+ *         extend: 'Ext.data.IdGenerator',
+ *         alias: 'idgen.custom',
+ *
+ *         configProp: 42, // some config property w/default value
+ *
+ *         generate: function () {
+ *             return ... // a new id
+ *         }
+ *     });
+ *
+ * Using the custom id generator is then straightforward:
+ *
+ *     Ext.define('MyApp.data.MyModel', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'custom'
+ *     });
+ *     // or...
+ *
+ *     Ext.define('MyApp.data.MyModel', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: {
+ *             type: 'custom',
+ *             configProp: value
+ *         }
+ *     });
+ *
+ * It is not recommended to mix shared generators with generator configuration. This leads
+ * to unpredictable results unless all configurations match (which is also redundant). In
+ * such cases, a custom generator with a default id is the best approach.
+ *
+ *     Ext.define('MyApp.data.CustomIdGenerator', {
+ *         extend: 'Ext.data.SequentialIdGenerator',
+ *         alias: 'idgen.custom',
+ *
+ *         id: 'custom', // shared by default
+ *
+ *         prefix: 'ID_',
+ *         seed: 1000
+ *     });
+ *
+ *     Ext.define('MyApp.data.MyModelX', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'custom'
+ *     });
+ *
+ *     Ext.define('MyApp.data.MyModelY', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'custom'
+ *     });
+ *
+ *     // the above models share a generator that produces ID_1000, ID_1001, etc..
+ *
+ */
+Ext.define('Ext.data.IdGenerator', {
+
+    isGenerator: true,
 
     /**
-     * @private
-     * Method to manage awareness of when components are removed from their
-     * respective Container, firing an removed event. References are properly
-     * cleaned up after removing a component from its owning container.
+     * Initializes a new instance.
+     * @param {Object} config (optional) Configuration object to be applied to the new instance.
      */
-    onRemoved : function() {
+    constructor: function(config) {
         var me = this;
 
-        me.fireEvent('removed', me, me.ownerCt);
-        delete me.ownerCt;
+        Ext.apply(me, config);
+
+        if (me.id) {
+            Ext.data.IdGenerator.all[me.id] = me;
+        }
     },
 
-    // @private
-    beforeDestroy : Ext.emptyFn,
-    // @private
-    // @private
-    onResize : Ext.emptyFn,
+    /**
+     * @cfg {String} id
+     * The id by which to register a new instance. This instance can be found using the
+     * {@link Ext.data.IdGenerator#get} static method.
+     */
+
+    getRecId: function (rec) {
+        return rec.modelName + '-' + rec.internalId;
+    },
 
     /**
-     * Sets the width and height of this Component. This method fires the {@link #resize} event. This method can accept
-     * either width and height as separate arguments, or you can pass a size object like <code>{width:10, height:20}</code>.
-     * @param {Mixed} width The new width to set. This may be one of:<div class="mdetail-params"><ul>
-     * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li>
-     * <li>A String used to set the CSS width style.</li>
-     * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
-     * <li><code>undefined</code> to leave the width unchanged.</li>
-     * </ul></div>
-     * @param {Mixed} height The new height to set (not required if a size object is passed as the first arg).
-     * This may be one of:<div class="mdetail-params"><ul>
-     * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li>
-     * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
-     * <li><code>undefined</code> to leave the height unchanged.</li>
-     * </ul></div>
-     * @return {Ext.Component} this
+     * Generates and returns the next id. This method must be implemented by the derived
+     * class.
+     *
+     * @return {String} The next id.
+     * @method generate
+     * @abstract
      */
-    setSize : function(width, height) {
-        var me = this,
-            layoutCollection;
 
-        // support for standard size objects
-        if (Ext.isObject(width)) {
-            height = width.height;
-            width  = width.width;
-        }
+    statics: {
+        /**
+         * @property {Object} all
+         * This object is keyed by id to lookup instances.
+         * @private
+         * @static
+         */
+        all: {},
 
-        // Constrain within configured maxima
-        if (Ext.isNumber(width)) {
-            width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
+        /**
+         * Returns the IdGenerator given its config description.
+         * @param {String/Object} config If this parameter is an IdGenerator instance, it is
+         * simply returned. If this is a string, it is first used as an id for lookup and
+         * then, if there is no match, as a type to create a new instance. This parameter
+         * can also be a config object that contains a `type` property (among others) that
+         * are used to create and configure the instance.
+         * @static
+         */
+        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;
         }
-        if (Ext.isNumber(height)) {
-            height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
-        }
-
-        if (!me.rendered || !me.isVisible()) {
-            // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
-            if (me.hiddenAncestor) {
-                layoutCollection = me.hiddenAncestor.layoutOnShow;
-                layoutCollection.remove(me);
-                layoutCollection.add(me);
-            }
-            me.needsLayout = {
-                width: width,
-                height: height,
-                isSetSize: true
-            };
-            if (!me.rendered) {
-                me.width  = (width !== undefined) ? width : me.width;
-                me.height = (height !== undefined) ? height : me.height;
-            }
-            return me;
-        }
-        me.doComponentLayout(width, height, true);
-
-        return me;
-    },
-
-    isFixedWidth: function() {
-        var me = this,
-            layoutManagedWidth = me.layoutManagedWidth;
-
-        if (Ext.isDefined(me.width) || layoutManagedWidth == 1) {
-            return true;
-        }
-        if (layoutManagedWidth == 2) {
-            return false;
-        }
-        return (me.ownerCt && me.ownerCt.isFixedWidth());
-    },
-
-    isFixedHeight: function() {
-        var me = this,
-            layoutManagedHeight = me.layoutManagedHeight;
-
-        if (Ext.isDefined(me.height) || layoutManagedHeight == 1) {
-            return true;
-        }
-        if (layoutManagedHeight == 2) {
-            return false;
-        }
-        return (me.ownerCt && me.ownerCt.isFixedHeight());
-    },
-
-    setCalculatedSize : function(width, height, callingContainer) {
-        var me = this,
-            layoutCollection;
-
-        // support for standard size objects
-        if (Ext.isObject(width)) {
-            callingContainer = width.ownerCt;
-            height = width.height;
-            width  = width.width;
-        }
-
-        // Constrain within configured maxima
-        if (Ext.isNumber(width)) {
-            width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
-        }
-        if (Ext.isNumber(height)) {
-            height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
-        }
-
-        if (!me.rendered || !me.isVisible()) {
-            // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
-            if (me.hiddenAncestor) {
-                layoutCollection = me.hiddenAncestor.layoutOnShow;
-                layoutCollection.remove(me);
-                layoutCollection.add(me);
-            }
-            me.needsLayout = {
-                width: width,
-                height: height,
-                isSetSize: false,
-                ownerCt: callingContainer
-            };
-            return me;
-        }
-        me.doComponentLayout(width, height, false, callingContainer);
+    }
+});
 
-        return me;
-    },
+/**
+ * @class Ext.data.SortTypes
+ * This class defines a series of static methods that are used on a
+ * {@link Ext.data.Field} for performing sorting. The methods cast the 
+ * underlying values into a data type that is appropriate for sorting on
+ * that particular field.  If a {@link Ext.data.Field#type} is specified, 
+ * the sortType will be set to a sane default if the sortType is not 
+ * explicitly defined on the field. The sortType will make any necessary
+ * modifications to the value and return it.
+ * <ul>
+ * <li><b>asText</b> - Removes any tags and converts the value to a string</li>
+ * <li><b>asUCText</b> - Removes any tags and converts the value to an uppercase string</li>
+ * <li><b>asUCText</b> - Converts the value to an uppercase string</li>
+ * <li><b>asDate</b> - Converts the value into Unix epoch time</li>
+ * <li><b>asFloat</b> - Converts the value to a floating point number</li>
+ * <li><b>asInt</b> - Converts the value to an integer number</li>
+ * </ul>
+ * <p>
+ * It is also possible to create a custom sortType that can be used throughout
+ * an application.
+ * <pre><code>
+Ext.apply(Ext.data.SortTypes, {
+    asPerson: function(person){
+        // expects an object with a first and last name property
+        return person.lastName.toUpperCase() + person.firstName.toLowerCase();
+    }    
+});
 
+Ext.define('Employee', {
+    extend: 'Ext.data.Model',
+    fields: [{
+        name: 'person',
+        sortType: 'asPerson'
+    }, {
+        name: 'salary',
+        type: 'float' // sortType set to asFloat
+    }]
+});
+ * </code></pre>
+ * </p>
+ * @singleton
+ * @docauthor Evan Trimboli <evan@sencha.com>
+ */
+Ext.define('Ext.data.SortTypes', {
+    
+    singleton: true,
+    
     /**
-     * This method needs to be called whenever you change something on this component that requires the Component's
-     * layout to be recalculated.
-     * @return {Ext.container.Container} this
+     * Default sort that does nothing
+     * @param {Object} s The value being converted
+     * @return {Object} The comparison value
      */
-    doComponentLayout : function(width, height, isSetSize, callingContainer) {
-        var me = this,
-            componentLayout = me.getComponentLayout(),
-            lastComponentSize = componentLayout.lastComponentSize || {
-                width: undefined,
-                height: undefined
-            };
-
-        // collapsed state is not relevant here, so no testing done.
-        // Only Panels have a collapse method, and that just sets the width/height such that only
-        // a single docked Header parallel to the collapseTo side are visible, and the Panel body is hidden.
-        if (me.rendered && componentLayout) {
-
-
-            // If no width passed, then only insert a value if the Component is NOT ALLOWED to autowidth itself.
-            if (!Ext.isDefined(width)) {
-                if (me.isFixedWidth()) {
-                    width = Ext.isDefined(me.width) ? me.width : lastComponentSize.width;
-                }
-            }
-
-            // If no height passed, then only insert a value if the Component is NOT ALLOWED to autoheight itself.
-            if (!Ext.isDefined(height)) {
-                if (me.isFixedHeight()) {
-                    height = Ext.isDefined(me.height) ? me.height : lastComponentSize.height;
-                }
-            }
-
-            if (isSetSize) {
-                me.width = width;
-                me.height = height;
-            }
-
-            componentLayout.layout(width, height, isSetSize, callingContainer);
-        }
-        return me;
+    none : function(s) {
+        return s;
     },
 
     /**
-     * Forces this component to redo its componentLayout.
+     * The regular expression used to strip tags
+     * @type {RegExp}
+     * @property
      */
-    forceComponentLayout: function () {
-        this.doComponentLayout();
-    },
-
-    // @private
-    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;
+    stripTagsRE : /<\/?[^>]+>/gi,
 
-        if (!me.componentLayout || !me.componentLayout.isLayout) {
-            me.setComponentLayout(Ext.layout.Layout.create(me.componentLayout, 'autocomponent'));
-        }
-        return me.componentLayout;
+    /**
+     * Strips all HTML tags to sort on text only
+     * @param {Object} s The value being converted
+     * @return {String} The comparison value
+     */
+    asText : function(s) {
+        return String(s).replace(this.stripTagsRE, "");
     },
 
     /**
-     * @param {Number} adjWidth The box-adjusted width that was set
-     * @param {Number} adjHeight The box-adjusted height that was set
-     * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
-     * @param {Ext.Component} callingContainer Container requesting the layout. Only used when isSetSize is false.
+     * Strips all HTML tags to sort on text only - Case insensitive
+     * @param {Object} s The value being converted
+     * @return {String} The comparison value
      */
-    afterComponentLayout: function(width, height, isSetSize, callingContainer) {
-        this.fireEvent('resize', this, width, height);
+    asUCText : function(s) {
+        return String(s).toUpperCase().replace(this.stripTagsRE, "");
     },
 
     /**
-     * Occurs before componentLayout is run. Returning false from this method will prevent the componentLayout
-     * from being executed.
-     * @param {Number} adjWidth The box-adjusted width that was set
-     * @param {Number} adjHeight The box-adjusted height that was set
-     * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
-     * @param {Ext.Component} callingContainer Container requesting sent the layout. Only used when isSetSize is false.
+     * Case insensitive string
+     * @param {Object} s The value being converted
+     * @return {String} The comparison value
      */
-    beforeComponentLayout: function(width, height, isSetSize, callingContainer) {
-        return true;
+    asUCString : function(s) {
+        return String(s).toUpperCase();
     },
 
     /**
-     * Sets the left and top of the component.  To set the page XY position instead, use
-     * {@link Ext.Component#setPagePosition setPagePosition}.
-     * This method fires the {@link #move} event.
-     * @param {Number} left The new left
-     * @param {Number} top The new top
-     * @return {Ext.Component} this
+     * Date sorting
+     * @param {Object} s The value being converted
+     * @return {Number} The comparison value
      */
-    setPosition : function(x, y) {
-        var me = this;
-
-        if (Ext.isObject(x)) {
-            y = x.y;
-            x = x.x;
-        }
-
-        if (!me.rendered) {
-            return me;
+    asDate : function(s) {
+        if(!s){
+            return 0;
         }
-
-        if (x !== undefined || y !== undefined) {
-            me.el.setBox(x, y);
-            me.onPosition(x, y);
-            me.fireEvent('move', me, x, y);
+        if(Ext.isDate(s)){
+            return s.getTime();
         }
-        return me;
+        return Date.parse(String(s));
     },
 
-    /* @private
-     * Called after the component is moved, this method is empty by default but can be implemented by any
-     * subclass that needs to perform custom logic after a move occurs.
-     * @param {Number} x The new x position
-     * @param {Number} y The new y position
-     */
-    onPosition: Ext.emptyFn,
-
     /**
-     * Sets the width of the component.  This method fires the {@link #resize} event.
-     * @param {Number} width The new width to setThis may be one of:<div class="mdetail-params"><ul>
-     * <li>A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li>
-     * <li>A String used to set the CSS width style.</li>
-     * </ul></div>
-     * @return {Ext.Component} this
+     * Float sorting
+     * @param {Object} s The value being converted
+     * @return {Number} The comparison value
      */
-    setWidth : function(width) {
-        return this.setSize(width);
+    asFloat : function(s) {
+        var val = parseFloat(String(s).replace(/,/g, ""));
+        return isNaN(val) ? 0 : val;
     },
 
     /**
-     * Sets the height of the component.  This method fires the {@link #resize} event.
-     * @param {Number} height The new height to set. This may be one of:<div class="mdetail-params"><ul>
-     * <li>A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.core.Element#defaultUnit}s (by default, pixels).</li>
-     * <li>A String used to set the CSS height style.</li>
-     * <li><i>undefined</i> to leave the height unchanged.</li>
-     * </ul></div>
-     * @return {Ext.Component} this
+     * Integer sorting
+     * @param {Object} s The value being converted
+     * @return {Number} The comparison value
      */
-    setHeight : function(height) {
-        return this.setSize(undefined, height);
-    },
+    asInt : function(s) {
+        var val = parseInt(String(s).replace(/,/g, ""), 10);
+        return isNaN(val) ? 0 : val;
+    }
+});
+/**
+ * Represents a filter that can be applied to a {@link Ext.util.MixedCollection MixedCollection}. Can either simply
+ * filter on a property/value pair or pass in a filter function with custom logic. Filters are always used in the
+ * context of MixedCollections, though {@link Ext.data.Store Store}s frequently create them when filtering and searching
+ * on their records. Example usage:
+ *
+ *     //set up a fictional MixedCollection containing a few people to filter on
+ *     var allNames = new Ext.util.MixedCollection();
+ *     allNames.addAll([
+ *         {id: 1, name: 'Ed',    age: 25},
+ *         {id: 2, name: 'Jamie', age: 37},
+ *         {id: 3, name: 'Abe',   age: 32},
+ *         {id: 4, name: 'Aaron', age: 26},
+ *         {id: 5, name: 'David', age: 32}
+ *     ]);
+ *
+ *     var ageFilter = new Ext.util.Filter({
+ *         property: 'age',
+ *         value   : 32
+ *     });
+ *
+ *     var longNameFilter = new Ext.util.Filter({
+ *         filterFn: function(item) {
+ *             return item.name.length > 4;
+ *         }
+ *     });
+ *
+ *     //a new MixedCollection with the 3 names longer than 4 characters
+ *     var longNames = allNames.filter(longNameFilter);
+ *
+ *     //a new MixedCollection with the 2 people of age 24:
+ *     var youngFolk = allNames.filter(ageFilter);
+ *
+ */
+Ext.define('Ext.util.Filter', {
 
+    /* Begin Definitions */
+
+    /* End Definitions */
     /**
-     * Gets the current size of the component's underlying element.
-     * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
+     * @cfg {String} property
+     * The property to filter on. Required unless a {@link #filterFn} is passed
      */
-    getSize : function() {
-        return this.el.getSize();
-    },
-
+    
     /**
-     * Gets the current width of the component's underlying element.
-     * @return {Number}
+     * @cfg {Function} filterFn
+     * A custom filter function which is passed each item in the {@link Ext.util.MixedCollection} in turn. Should return
+     * true to accept each item or false to reject it
      */
-    getWidth : function() {
-        return this.el.getWidth();
-    },
-
+    
     /**
-     * Gets the current height of the component's underlying element.
-     * @return {Number}
+     * @cfg {Boolean} anyMatch
+     * True to allow any match - no regex start/end line anchors will be added.
      */
-    getHeight : function() {
-        return this.el.getHeight();
-    },
-
+    anyMatch: false,
+    
     /**
-     * Gets the {@link Ext.ComponentLoader} for this Component.
-     * @return {Ext.ComponentLoader} The loader instance, null if it doesn't exist.
+     * @cfg {Boolean} exactMatch
+     * True to force exact match (^ and $ characters added to the regex). Ignored if anyMatch is true.
      */
-    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 = Ext.create('Ext.ComponentLoader', Ext.apply({
-                    target: me,
-                    autoLoad: autoLoad
-                }, loader));
-            } else {
-                loader.setTarget(me);
-            }
-            return me.loader;
-
-        }
-        return null;
-    },
-
+    exactMatch: false,
+    
     /**
-     * This method allows you to show or hide a LoadMask on top of this component.
-     * @param {Boolean/Object/String} load True to show the default LoadMask, a config object
-     * that will be passed to the LoadMask constructor, or a message String to show. False to
-     * hide the current LoadMask.
-     * @param {Boolean} targetEl True to mask the targetEl of this Component instead of the this.el.
-     * For example, setting this to true on a Panel will cause only the body to be masked. (defaults to false)
-     * @return {Ext.LoadMask} The LoadMask instance that has just been shown.
+     * @cfg {Boolean} caseSensitive
+     * True to make the regex case sensitive (adds 'i' switch to regex).
      */
-    setLoading : function(load, targetEl) {
-        var me = this,
-            config;
-
-        if (me.rendered) {
-            if (load !== false && !me.collapsed) {
-                if (Ext.isObject(load)) {
-                    config = load;
-                }
-                else if (Ext.isString(load)) {
-                    config = {msg: load};
-                }
-                else {
-                    config = {};
-                }
-                me.loadMask = me.loadMask || Ext.create('Ext.LoadMask', targetEl ? me.getTargetEl() : me.el, config);
-                me.loadMask.show();
-            } else if (me.loadMask) {
-                Ext.destroy(me.loadMask);
-                me.loadMask = null;
-            }
-        }
-
-        return me.loadMask;
-    },
-
+    caseSensitive: false,
+    
     /**
-     * Sets the dock position of this component in its parent panel. Note that
-     * this only has effect if this item is part of the dockedItems collection
-     * of a parent that has a DockLayout (note that any Panel has a DockLayout
-     * by default)
-     * @return {Component} this
+     * @cfg {String} root
+     * Optional root property. This is mostly useful when filtering a Store, in which case we set the root to 'data' to
+     * make the filter pull the {@link #property} out of the data object of each item
      */
-    setDocked : function(dock, layoutParent) {
-        var me = this;
-
-        me.dock = dock;
-        if (layoutParent && me.ownerCt && me.rendered) {
-            me.ownerCt.doComponentLayout();
-        }
-        return me;
-    },
-
-    onDestroy : function() {
-        var me = this;
-
-        if (me.monitorResize && Ext.EventManager.resizeEvent) {
-            Ext.EventManager.resizeEvent.removeListener(me.setSize, me);
-        }
-        Ext.destroy(me.componentLayout, me.loadMask);
-    },
 
     /**
-     * Destroys the Component.
+     * Creates new Filter.
+     * @param {Object} [config] Config object
      */
-    destroy : function() {
+    constructor: function(config) {
         var me = this;
-
-        if (!me.isDestroyed) {
-            if (me.fireEvent('beforedestroy', me) !== false) {
-                me.destroying = true;
-                me.beforeDestroy();
-
-                if (me.floating) {
-                    delete me.floatParent;
-                    // A zIndexManager is stamped into a *floating* Component when it is added to a Container.
-                    // If it has no zIndexManager at render time, it is assigned to the global Ext.WindowManager instance.
-                    if (me.zIndexManager) {
-                        me.zIndexManager.unregister(me);
-                    }
-                } else if (me.ownerCt && me.ownerCt.remove) {
-                    me.ownerCt.remove(me, false);
-                }
-
-                me.onDestroy();
-
-                // Attempt to destroy all plugins
-                Ext.destroy(me.plugins);
-
-                if (me.rendered) {
-                    me.el.remove();
-                }
-
-                Ext.ComponentManager.unregister(me);
-                me.fireEvent('destroy', me);
-
-                me.mixins.state.destroy.call(me);
-
-                me.clearListeners();
-                me.destroying = false;
-                me.isDestroyed = true;
+        Ext.apply(me, config);
+        
+        //we're aliasing filter to filterFn mostly for API cleanliness reasons, despite the fact it dirties the code here.
+        //Ext.util.Sorter takes a sorterFn property but allows .sort to be called - we do the same here
+        me.filter = me.filter || me.filterFn;
+        
+        if (me.filter === undefined) {
+            if (me.property === undefined || me.value === undefined) {
+                // Commented this out temporarily because it stops us using string ids in models. TODO: Remove this once
+                // Model has been updated to allow string ids
+                
+                // Ext.Error.raise("A Filter requires either a property or a filterFn to be set");
+            } else {
+                me.filter = me.createFilterFn();
             }
+            
+            me.filterFn = me.filter;
         }
     },
-
+    
     /**
-     * Retrieves a plugin by its pluginId which has been bound to this
-     * component.
-     * @returns {Ext.AbstractPlugin} pluginInstance
+     * @private
+     * Creates a filter function for the configured property/value/anyMatch/caseSensitive options for this Filter
      */
-    getPlugin: function(pluginId) {
-        var i = 0,
-            plugins = this.plugins,
-            ln = plugins.length;
-        for (; i < ln; i++) {
-            if (plugins[i].pluginId === pluginId) {
-                return plugins[i];
-            }
-        }
+    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);
+        };
     },
-
+    
     /**
-     * Determines whether this component is the descendant of a particular container.
-     * @param {Ext.Container} container
-     * @returns {Boolean} isDescendant
+     * @private
+     * Returns the root property of the given item, based on the configured {@link #root} property
+     * @param {Object} item The item
+     * @return {Object} The root property of the object
      */
-    isDescendantOf: function(container) {
-        return !!this.findParentBy(function(p){
-            return p === container;
-        });
-    }
-}, function() {
-    this.createAlias({
-        on: 'addListener',
-        prev: 'previousSibling',
-        next: 'nextSibling'
-    });
-});
-
-/**
- * @class Ext.AbstractPlugin
- * @extends Object
- *
- * <p>The AbstractPlugin class is the base class from which user-implemented plugins should inherit.</p>
- * <p>This class defines the essential API of plugins as used by Components by defining the following methods:</p>
- * <ul>
- * <li><code>init</code> : The plugin initialization method which the owning Component calls at Component initialization
- * time.<div class="sub-desc"><p>The Component passes itself as the sole parameter.</p><p>Subclasses should set up bidirectional
- * links between the plugin and its client Component here.</p></div></li>
- * <li><code>destroy</code> : The plugin cleanup method which the owning Component calls at Component destruction time.<div class="sub-desc">Use
- * this method to break links between the plugin and the Component and to free any allocated resources.</div></li>
- * <li><code>enable</code> : The base implementation just sets the plugin's <code>disabled</code> flag to <code>false</code><div class="sub-desc"></div></li>
- * <li><code>disable</code> : The base implementation just sets the plugin's <code>disabled</code> flag to <code>true</code><div class="sub-desc"></div></li>
- * </ul>
- */
-Ext.define('Ext.AbstractPlugin', {
-    disabled: false,
-
-    constructor: function(config) {
-        //<debug>
-        if (!config.cmp && Ext.global.console) {
-            Ext.global.console.warn("Attempted to attach a plugin ");
-        }
-        //</debug>
-        Ext.apply(this, config);
-    },
-
-    getCmp: function() {
-        return this.cmp;
+    getRoot: function(item) {
+        var root = this.root;
+        return root === undefined ? item : item[root];
     },
-
+    
     /**
-     * <p>The init method is invoked after {@link Ext.Component#initComponent initComponent} has been run for the client Component.</p>
-     * <p>The supplied implementation is empty. Subclasses should perform plugin initialization, and set up bidirectional
-     * links between the plugin and its client Component in their own implementation of this method.</p>
-     * @param {Component} client The client Component which owns this plugin.
-     * @method
-     */
-    init: Ext.emptyFn,
-
-    /**
-     * <p>The destroy method is invoked by the owning Component at the time the Component is being destroyed.</p>
-     * <p>The supplied implementation is empty. Subclasses should perform plugin cleanup in their own implementation of this method.</p>
-     * @method
-     */
-    destroy: Ext.emptyFn,
-
-    /**
-     * <p>The base implementation just sets the plugin's <code>disabled</code> flag to <code>false</code></p>
-     * <p>Plugin subclasses which need more complex processing may implement an overriding implementation.</p>
+     * @private
+     * Returns a regular expression based on the given value and matching options
      */
-    enable: function() {
-        this.disabled = false;
-    },
+    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) { // not a regex
+            value = String(value);
 
-    /**
-     * <p>The base implementation just sets the plugin's <code>disabled</code> flag to <code>true</code></p>
-     * <p>Plugin subclasses which need more complex processing may implement an overriding implementation.</p>
-     */
-    disable: function() {
-        this.disabled = true;
+            if (anyMatch === true) {
+                value = escapeRe(value);
+            } else {
+                value = '^' + escapeRe(value);
+                if (exactMatch === true) {
+                    value += '$';
+                }
+            }
+            value = new RegExp(value, caseSensitive ? '' : 'i');
+         }
+         
+         return value;
     }
 });
 /**
- * @class Ext.data.Connection
- * The Connection class encapsulates a connection to the page's originating domain, allowing requests to be made either
- * to a configured URL, or to a URL specified at request time.
- *
- * Requests made by this class are asynchronous, and will return immediately. No data from the server will be available
- * to the statement immediately following the {@link #request} call. To process returned data, use a success callback
- * in the request options object, or an {@link #requestcomplete event listener}.
- *
- * <p><u>File Uploads</u></p>
+ * Represents a single sorter that can be applied to a Store. The sorter is used
+ * to compare two values against each other for the purpose of ordering them. Ordering
+ * is achieved by specifying either:
  *
- * File uploads are not performed using normal "Ajax" techniques, that is they are not performed using XMLHttpRequests.
- * Instead the form is submitted in the standard manner with the DOM &lt;form&gt; element temporarily modified to have its
- * target set to refer to a dynamically generated, hidden &lt;iframe&gt; which is inserted into the document but removed
- * after the return data has been gathered.
+ * - {@link #property A sorting property}
+ * - {@link #sorterFn A sorting function}
  *
- * The server response is parsed by the browser to create the document for the IFRAME. If the server is using JSON to
- * send the return object, then the Content-Type header must be set to "text/html" in order to tell the browser to
- * insert the text unchanged into the document body.
+ * As a contrived example, we can specify a custom sorter that sorts by rank:
  *
- * Characters which are significant to an HTML parser must be sent as HTML entities, so encode "&lt;" as "&amp;lt;", "&amp;" as
- * "&amp;amp;" etc.
+ *     Ext.define('Person', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['name', 'rank']
+ *     });
  *
- * The response text is retrieved from the document, and a fake XMLHttpRequest object is created containing a
- * responseText property in order to conform to the requirements of event handlers and callbacks.
+ *     Ext.create('Ext.data.Store', {
+ *         model: 'Person',
+ *         proxy: 'memory',
+ *         sorters: [{
+ *             sorterFn: function(o1, o2){
+ *                 var getRank = function(o){
+ *                     var name = o.get('rank');
+ *                     if (name === 'first') {
+ *                         return 1;
+ *                     } else if (name === 'second') {
+ *                         return 2;
+ *                     } else {
+ *                         return 3;
+ *                     }
+ *                 },
+ *                 rank1 = getRank(o1),
+ *                 rank2 = getRank(o2);
  *
- * Be aware that file upload packets are sent with the content type multipart/form and some server technologies
- * (notably JEE) may require some custom processing in order to retrieve parameter names and parameter values from the
- * packet content.
+ *                 if (rank1 === rank2) {
+ *                     return 0;
+ *                 }
  *
- * Also note that it's not possible to check the response code of the hidden iframe, so the success handler will ALWAYS fire.
+ *                 return rank1 < rank2 ? -1 : 1;
+ *             }
+ *         }],
+ *         data: [{
+ *             name: 'Person1',
+ *             rank: 'second'
+ *         }, {
+ *             name: 'Person2',
+ *             rank: 'third'
+ *         }, {
+ *             name: 'Person3',
+ *             rank: 'first'
+ *         }]
+ *     });
  */
-Ext.define('Ext.data.Connection', {
-    mixins: {
-        observable: 'Ext.util.Observable'
-    },
+Ext.define('Ext.util.Sorter', {
 
-    statics: {
-        requestId: 0
+    /**
+     * @cfg {String} property
+     * The property to sort by. Required unless {@link #sorterFn} is provided. The property is extracted from the object
+     * directly and compared for sorting using the built in comparison operators.
+     */
+    
+    /**
+     * @cfg {Function} sorterFn
+     * A specific sorter function to execute. Can be passed instead of {@link #property}. This sorter function allows
+     * for any kind of custom/complex comparisons. The sorterFn receives two arguments, the objects being compared. The
+     * function should return:
+     *
+     *   - -1 if o1 is "less than" o2
+     *   - 0 if o1 is "equal" to o2
+     *   - 1 if o1 is "greater than" o2
+     */
+    
+    /**
+     * @cfg {String} root
+     * Optional root property. This is mostly useful when sorting a Store, in which case we set the root to 'data' to
+     * make the filter pull the {@link #property} out of the data object of each item
+     */
+    
+    /**
+     * @cfg {Function} transform
+     * A function that will be run on each value before it is compared in the sorter. The function will receive a single
+     * argument, the value.
+     */
+    
+    /**
+     * @cfg {String} direction
+     * The direction to sort by.
+     */
+    direction: "ASC",
+    
+    constructor: function(config) {
+        var me = this;
+        
+        Ext.apply(me, config);
+        
+        //<debug>
+        if (me.property === undefined && me.sorterFn === undefined) {
+            Ext.Error.raise("A Sorter requires either a property or a sorter function");
+        }
+        //</debug>
+        
+        me.updateSortFunction();
     },
+    
+    /**
+     * @private
+     * Creates and returns a function which sorts an array by the given property and direction
+     * @return {Function} A function which sorts by the property/direction combination provided
+     */
+    createSortFunction: function(sorterFn) {
+        var me        = this,
+            property  = me.property,
+            direction = me.direction || "ASC",
+            modifier  = direction.toUpperCase() == "DESC" ? -1 : 1;
+        
+        //create a comparison function. Takes 2 objects, returns 1 if object 1 is greater,
+        //-1 if object 2 is greater or 0 if they are equal
+        return function(o1, o2) {
+            return modifier * sorterFn.call(me, o1, o2);
+        };
+    },
+    
+    /**
+     * @private
+     * Basic default sorter function that just compares the defined property of each object
+     */
+    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);
+        }
 
-    url: null,
-    async: true,
-    method: null,
-    username: '',
-    password: '',
-
+        return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
+    },
+    
     /**
-     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
+     * @private
+     * Returns the root property of the given item, based on the configured {@link #root} property
+     * @param {Object} item The item
+     * @return {Object} The root property of the object
      */
-    disableCaching: true,
+    getRoot: function(item) {
+        return this.root === undefined ? item : item[this.root];
+    },
+    
+    /**
+     * Set the sorting direction for this sorter.
+     * @param {String} direction The direction to sort in. Should be either 'ASC' or 'DESC'.
+     */
+    setDirection: function(direction) {
+        var me = this;
+        me.direction = direction;
+        me.updateSortFunction();
+    },
+    
+    /**
+     * Toggles the sorting direction for this sorter.
+     */
+    toggle: function() {
+        var me = this;
+        me.direction = Ext.String.toggle(me.direction, "ASC", "DESC");
+        me.updateSortFunction();
+    },
+    
+    /**
+     * Update the sort function for this sorter.
+     * @param {Function} [fn] A new sorter function for this sorter. If not specified it will use the default
+     * sorting function.
+     */
+    updateSortFunction: function(fn) {
+        var me = this;
+        fn = fn || me.sorterFn || me.defaultSorterFn;
+        me.sort = me.createSortFunction(fn);
+    }
+});
+/**
+ * @author Ed Spencer
+ *
+ * Represents a single read or write operation performed by a {@link Ext.data.proxy.Proxy Proxy}. Operation objects are
+ * used to enable communication between Stores and Proxies. Application developers should rarely need to interact with
+ * Operation objects directly.
+ *
+ * Several Operations can be batched together in a {@link Ext.data.Batch batch}.
+ */
+Ext.define('Ext.data.Operation', {
+    /**
+     * @cfg {Boolean} synchronous
+     * True if this Operation is to be executed synchronously. This property is inspected by a
+     * {@link Ext.data.Batch Batch} to see if a series of Operations can be executed in parallel or not.
+     */
+    synchronous: true,
 
     /**
-     * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
-     * through a cache buster. Defaults to '_dc'
+     * @cfg {String} action
+     * The action being performed by this Operation. Should be one of 'create', 'read', 'update' or 'destroy'.
      */
-    disableCachingParam: '_dc',
+    action: undefined,
 
     /**
-     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
+     * @cfg {Ext.util.Filter[]} filters
+     * Optional array of filter objects. Only applies to 'read' actions.
      */
-    timeout : 30000,
+    filters: undefined,
 
     /**
-     * @cfg {Object} extraParams (Optional) Any parameters to be appended to the request.
+     * @cfg {Ext.util.Sorter[]} sorters
+     * Optional array of sorter objects. Only applies to 'read' actions.
      */
+    sorters: undefined,
 
-    useDefaultHeader : true,
-    defaultPostHeader : 'application/x-www-form-urlencoded; charset=UTF-8',
-    useDefaultXhrHeader : true,
-    defaultXhrHeader : 'XMLHttpRequest',
+    /**
+     * @cfg {Ext.util.Grouper} group
+     * Optional grouping configuration. Only applies to 'read' actions where grouping is desired.
+     */
+    group: undefined,
 
-    constructor : function(config) {
-        config = config || {};
-        Ext.apply(this, config);
+    /**
+     * @cfg {Number} start
+     * The start index (offset), used in paging when running a 'read' action.
+     */
+    start: undefined,
 
-        this.addEvents(
-            /**
-             * @event beforerequest
-             * Fires before a network request is made to retrieve a data object.
-             * @param {Connection} conn This Connection object.
-             * @param {Object} options The options config object passed to the {@link #request} method.
-             */
-            'beforerequest',
-            /**
-             * @event requestcomplete
-             * Fires if the request was successfully completed.
-             * @param {Connection} conn This Connection object.
-             * @param {Object} response The XHR object containing the response data.
-             * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
-             * for details.
-             * @param {Object} options The options config object passed to the {@link #request} method.
-             */
-            'requestcomplete',
-            /**
-             * @event requestexception
-             * Fires if an error HTTP status was returned from the server.
-             * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
-             * for details of HTTP status codes.
-             * @param {Connection} conn This Connection object.
-             * @param {Object} response The XHR object containing the response data.
-             * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
-             * for details.
-             * @param {Object} options The options config object passed to the {@link #request} method.
-             */
-            'requestexception'
-        );
-        this.requests = {};
-        this.mixins.observable.constructor.call(this);
-    },
+    /**
+     * @cfg {Number} limit
+     * The number of records to load. Used on 'read' actions when paging is being used.
+     */
+    limit: undefined,
 
     /**
-     * <p>Sends an HTTP request to a remote server.</p>
-     * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
-     * return before the response has been received. Process any returned data
-     * in a callback function.</p>
-     * <pre><code>
-Ext.Ajax.request({
-url: 'ajax_demo/sample.json',
-success: function(response, opts) {
-  var obj = Ext.decode(response.responseText);
-  console.dir(obj);
-},
-failure: function(response, opts) {
-  console.log('server-side failure with status code ' + response.status);
-}
-});
-     * </code></pre>
-     * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
-     * @param {Object} options An object which may contain the following properties:<ul>
-     * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
-     * which to send the request, or a function to call which returns a URL string. The scope of the
-     * function is specified by the <tt>scope</tt> option. Defaults to the configured
-     * <tt>{@link #url}</tt>.</div></li>
-     * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
-     * An object containing properties which are used as parameters to the
-     * request, a url encoded string or a function to call to get either. The scope of the function
-     * is specified by the <tt>scope</tt> option.</div></li>
-     * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
-     * for the request. Defaults to the configured method, or if no method was configured,
-     * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
-     * the method name is case-sensitive and should be all caps.</div></li>
-     * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
-     * function to be called upon receipt of the HTTP response. The callback is
-     * called regardless of success or failure and is passed the following
-     * parameters:<ul>
-     * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
-     * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
-     * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.
-     * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about
-     * accessing elements of the response.</div></li>
-     * </ul></div></li>
-     * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
-     * to be called upon success of the request. The callback is passed the following
-     * parameters:<ul>
-     * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
-     * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
-     * </ul></div></li>
-     * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
-     * to be called upon failure of the request. The callback is passed the
-     * following parameters:<ul>
-     * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
-     * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
-     * </ul></div></li>
-     * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
-     * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
-     * specified as functions from which to draw values, then this also serves as the scope for those function calls.
-     * Defaults to the browser window.</div></li>
-     * <li><b>timeout</b> : Number (Optional)<div class="sub-desc">The timeout in milliseconds to be used for this request. Defaults to 30 seconds.</div></li>
-     * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>
-     * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>
-     * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used
-     * with the <tt>form</tt> option</b>.
-     * <p>True if the form object is a file upload (will be set automatically if the form was
-     * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
-     * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
-     * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
-     * DOM <tt>&lt;form></tt> element temporarily modified to have its
-     * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
-     * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
-     * but removed after the return data has been gathered.</p>
-     * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
-     * server is using JSON to send the return object, then the
-     * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
-     * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
-     * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
-     * is created containing a <tt>responseText</tt> property in order to conform to the
-     * requirements of event handlers and callbacks.</p>
-     * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
-     * and some server technologies (notably JEE) may require some custom processing in order to
-     * retrieve parameter names and parameter values from the packet content.</p>
-     * </div></li>
-     * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
-     * headers to set for the request.</div></li>
-     * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
-     * to use for the post. Note: This will be used instead of params for the post
-     * data. Any params will be appended to the URL.</div></li>
-     * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
-     * data to use as the post. Note: This will be used instead of params for the post
-     * data. Any params will be appended to the URL.</div></li>
-     * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
-     * to add a unique cache-buster param to GET requests.</div></li>
-     * </ul></p>
-     * <p>The options object may also contain any other property which might be needed to perform
-     * postprocessing in a callback because it is passed to callback functions.</p>
-     * @return {Object} request The request object. This may be used
-     * to cancel the request.
+     * @cfg {Ext.data.Batch} batch
+     * The batch that this Operation is a part of.
      */
-    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;
+    batch: undefined,
 
-        if (me.fireEvent('beforerequest', me, options) !== false) {
+    /**
+     * @cfg {Function} callback
+     * Function to execute when operation completed.  Will be called with the following parameters:
+     *
+     * - records : Array of Ext.data.Model objects.
+     * - operation : The Ext.data.Operation itself.
+     * - success : True when operation completed successfully.
+     */
+    callback: undefined,
 
-            requestOptions = me.setOptions(options, scope);
+    /**
+     * @cfg {Object} scope
+     * Scope for the {@link #callback} function.
+     */
+    scope: undefined,
 
-            if (this.isFormUpload(options) === true) {
-                this.upload(options.form, requestOptions.url, requestOptions.data, options);
-                return null;
-            }
+    /**
+     * @property {Boolean} started
+     * Read-only property tracking the start status of this Operation. Use {@link #isStarted}.
+     * @private
+     */
+    started: false,
 
-            // if autoabort is set, cancel the current transactions
-            if (options.autoAbort === true || me.autoAbort) {
-                me.abort();
-            }
+    /**
+     * @property {Boolean} running
+     * Read-only property tracking the run status of this Operation. Use {@link #isRunning}.
+     * @private
+     */
+    running: false,
 
-            // create a connection object
-            xhr = this.getXhrInstance();
+    /**
+     * @property {Boolean} complete
+     * Read-only property tracking the completion status of this Operation. Use {@link #isComplete}.
+     * @private
+     */
+    complete: false,
 
-            async = options.async !== false ? (options.async || me.async) : false;
+    /**
+     * @property {Boolean} success
+     * Read-only property tracking whether the Operation was successful or not. This starts as undefined and is set to true
+     * or false by the Proxy that is executing the Operation. It is also set to false by {@link #setException}. Use
+     * {@link #wasSuccessful} to query success status.
+     * @private
+     */
+    success: undefined,
 
-            // open the request
-            if (username) {
-                xhr.open(requestOptions.method, requestOptions.url, async, username, password);
-            } else {
-                xhr.open(requestOptions.method, requestOptions.url, async);
-            }
+    /**
+     * @property {Boolean} exception
+     * Read-only property tracking the exception status of this Operation. Use {@link #hasException} and see {@link #getError}.
+     * @private
+     */
+    exception: false,
 
-            headers = me.setupHeaders(xhr, options, requestOptions.data, requestOptions.params);
+    /**
+     * @property {String/Object} error
+     * The error object passed when {@link #setException} was called. This could be any object or primitive.
+     * @private
+     */
+    error: undefined,
 
-            // create the transaction object
-            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;
+    /**
+     * @property {RegExp} actionCommitRecordsRe
+     * The RegExp used to categorize actions that require record commits.
+     */
+    actionCommitRecordsRe: /^(?:create|update)$/i,
 
-            // bind our statechange listener
-            if (async) {
-                xhr.onreadystatechange = Ext.Function.bind(me.onStateChange, me, [request]);
-            }
+    /**
+     * @property {RegExp} actionSkipSyncRe
+     * The RegExp used to categorize actions that skip local record synchronization. This defaults
+     * to match 'destroy'.
+     */
+    actionSkipSyncRe: /^destroy$/i,
 
-            // start the request!
-            xhr.send(requestOptions.data);
-            if (!async) {
-                return this.onComplete(request);
-            }
-            return request;
-        } else {
-            Ext.callback(options.callback, options.scope, [options, undefined, undefined]);
-            return null;
-        }
+    /**
+     * Creates new Operation object.
+     * @param {Object} config (optional) Config object.
+     */
+    constructor: function(config) {
+        Ext.apply(this, config || {});
     },
 
     /**
-     * Upload a form using a hidden iframe.
-     * @param {Mixed} form The form to upload
-     * @param {String} url The url to post to
-     * @param {String} params Any extra parameters to pass
-     * @param {Object} options The initial options
+     * This method is called to commit data to this instance's records given the records in
+     * the server response. This is followed by calling {@link Ext.data.Model#commit} on all
+     * those records (for 'create' and 'update' actions).
+     *
+     * If this {@link #action} is 'destroy', any server records are ignored and the
+     * {@link Ext.data.Model#commit} method is not called.
+     *
+     * @param {Ext.data.Model[]} serverRecords An array of {@link Ext.data.Model} objects returned by
+     * the server.
+     * @markdown
      */
-    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
-                }, hiddenItem;
-
-        /*
-         * Originally this behaviour was modified for Opera 10 to apply the secure URL after
-         * the frame had been added to the document. It seems this has since been corrected in
-         * Opera so the behaviour has been reverted, the URL will be set before being added.
-         */
-        Ext.fly(frame).set({
-            id: id,
-            name: id,
-            cls: Ext.baseCSSPrefix + 'hide-display',
-            src: Ext.SSL_SECURE_URL
-        });
-
-        document.body.appendChild(frame);
-
-        // This is required so that IE doesn't pop the response up in a new window.
-        if (document.frames) {
-           document.frames[id].name = id;
-        }
-
-        Ext.fly(form).set({
-            target: id,
-            method: 'POST',
-            enctype: encoding,
-            encoding: encoding,
-            action: url || buf.action
-        });
+    commitRecords: function (serverRecords) {
+        var me = this,
+            mc, index, clientRecords, serverRec, clientRec;
 
-        // add dynamic params
-        if (params) {
-            Ext.iterate(Ext.Object.fromQueryString(params), function(name, value){
-                hiddenItem = document.createElement('input');
-                Ext.fly(hiddenItem).set({
-                    type: 'hidden',
-                    value: value,
-                    name: name
-                });
-                form.appendChild(hiddenItem);
-                hiddens.push(hiddenItem);
-            });
-        }
+        if (!me.actionSkipSyncRe.test(me.action)) {
+            clientRecords = me.records;
 
-        Ext.fly(frame).on('load', Ext.Function.bind(this.onUploadComplete, this, [frame, options]), null, {single: true});
-        form.submit();
+            if (clientRecords && clientRecords.length) {
+                mc = Ext.create('Ext.util.MixedCollection', true, function(r) {return r.getId();});
+                mc.addAll(clientRecords);
 
-        Ext.fly(form).set(buf);
-        Ext.each(hiddens, function(h) {
-            Ext.removeNode(h);
-        });
-    },
+                for (index = serverRecords ? serverRecords.length : 0; index--; ) {
+                    serverRec = serverRecords[index];
+                    clientRec = mc.get(serverRec.getId());
 
-    onUploadComplete: function(frame, options){
-        var me = this,
-            // bogus response object
-            response = {
-                responseText: '',
-                responseXML: null
-            }, doc, firstChild;
+                    if (clientRec) {
+                        clientRec.beginEdit();
+                        clientRec.set(serverRec.data);
+                        clientRec.endEdit(true);
+                    }
+                }
 
-        try {
-            doc = frame.contentWindow.document || frame.contentDocument || window.frames[id].document;
-            if (doc) {
-                if (doc.body) {
-                    if (/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)) { // json response wrapped in textarea
-                        response.responseText = firstChild.value;
-                    } else {
-                        response.responseText = doc.body.innerHTML;
+                if (me.actionCommitRecordsRe.test(me.action)) {
+                    for (index = clientRecords.length; index--; ) {
+                        clientRecords[index].commit();
                     }
                 }
-                //in IE the document may still have a body even if returns XML.
-                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]);
+    /**
+     * Marks the Operation as started.
+     */
+    setStarted: function() {
+        this.started = true;
+        this.running = true;
+    },
 
-        setTimeout(function(){
-            Ext.removeNode(frame);
-        }, 100);
+    /**
+     * Marks the Operation as completed.
+     */
+    setCompleted: function() {
+        this.complete = true;
+        this.running  = false;
     },
 
     /**
-     * Detect whether the form is intended to be used for an upload.
-     * @private
+     * Marks the Operation as successful.
      */
-    isFormUpload: function(options){
-        var form = this.getForm(options);
-        if (form) {
-            return (options.isUpload || (/multipart\/form-data/i).test(form.getAttribute('enctype')));
-        }
-        return false;
+    setSuccessful: function() {
+        this.success = true;
     },
 
     /**
-     * Get the form object from options.
-     * @private
-     * @param {Object} options The request options
-     * @return {HTMLElement} The form, null if not passed
+     * Marks the Operation as having experienced an exception. Can be supplied with an option error message/object.
+     * @param {String/Object} error (optional) error string/object
      */
-    getForm: function(options){
-        return Ext.getDom(options.form) || null;
+    setException: function(error) {
+        this.exception = true;
+        this.success = false;
+        this.running = false;
+        this.error = error;
     },
 
     /**
-     * Set various options such as the url, params for the request
-     * @param {Object} options The initial options
-     * @param {Object} scope The scope to execute in
-     * @return {Object} The params for the request
+     * Returns true if this Operation encountered an exception (see also {@link #getError})
+     * @return {Boolean} True if there was an exception
      */
-    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;
-
-
-        // allow params to be a method that returns the params object
-        if (Ext.isFunction(params)) {
-            params = params.call(scope, options);
-        }
-
-        // allow url to be a method that returns the actual url
-        if (Ext.isFunction(url)) {
-            url = url.call(scope, options);
-        }
-
-        url = this.setupUrl(options, url);
-
-        //<debug>
-        if (!url) {
-            Ext.Error.raise({
-                options: options,
-                msg: 'No URL specified'
-            });
-        }
-        //</debug>
-
-        // check for xml or json data, and make sure json data is encoded
-        data = options.rawData || options.xmlData || jsonData || null;
-        if (jsonData && !Ext.isPrimitive(jsonData)) {
-            data = Ext.encode(data);
-        }
-
-        // make sure params are a url encoded string and include any extraParams if specified
-        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);
-
-        // decide the proper method for this request
-        method = (options.method || me.method || ((params || data) ? 'POST' : 'GET')).toUpperCase();
-        this.setupMethod(options, method);
-
-
-        disableCache = options.disableCaching !== false ? (options.disableCaching || me.disableCaching) : false;
-        // if the method is get append date to prevent caching
-        if (method === 'GET' && disableCache) {
-            url = Ext.urlAppend(url, (options.disableCachingParam || me.disableCachingParam) + '=' + (new Date().getTime()));
-        }
-
-        // if the method is get or there is json/xml data append the params to the url
-        if ((method == 'GET' || data) && params) {
-            url = Ext.urlAppend(url, params);
-            params = null;
-        }
-
-        // allow params to be forced into the url
-        if (urlParams) {
-            url = Ext.urlAppend(url, urlParams);
-        }
-
-        return {
-            url: url,
-            method: method,
-            data: data || params || null
-        };
-    },
-
-    /**
-     * Template method for overriding url
-     * @private
-     * @param {Object} options
-     * @param {String} url
-     * @return {String} The modified url
-     */
-    setupUrl: function(options, url){
-        var form = this.getForm(options);
-        if (form) {
-            url = url || form.action;
-        }
-        return url;
-    },
-
-
-    /**
-     * Template method for overriding params
-     * @private
-     * @param {Object} options
-     * @param {String} params
-     * @return {String} The modified params
-     */
-    setupParams: function(options, params) {
-        var form = this.getForm(options),
-            serializedForm;
-        if (form && !this.isFormUpload(options)) {
-            serializedForm = Ext.core.Element.serializeForm(form);
-            params = params ? (params + '&' + serializedForm) : serializedForm;
-        }
-        return params;
-    },
-
-    /**
-     * Template method for overriding method
-     * @private
-     * @param {Object} options
-     * @param {String} method
-     * @return {String} The modified method
-     */
-    setupMethod: function(options, method){
-        if (this.isFormUpload(options)) {
-            return 'POST';
-        }
-        return method;
-    },
-
-    /**
-     * Setup all the headers for the request
-     * @private
-     * @param {Object} xhr The xhr object
-     * @param {Object} options The options for the request
-     * @param {Object} data The data for the request
-     * @param {Object} params The params for the request
-     */
-    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;
-        }
-        // set up all the request headers on the xhr object
-        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;
+    hasException: function() {
+        return this.exception === true;
     },
 
     /**
-     * Creates the appropriate XHR transport for the browser.
-     * @private
-     */
-    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;
-    })(),
-
-    /**
-     * Determine whether this object has a request outstanding.
-     * @param {Object} request (Optional) defaults to the last transaction
-     * @return {Boolean} True if there is an outstanding request.
+     * Returns the error string or object that was set using {@link #setException}
+     * @return {String/Object} The error object
      */
-    isLoading : function(request) {
-        if (!(request && request.xhr)) {
-            return false;
-        }
-        // if there is a connection and readyState is not 0 or 4
-        var state = request.xhr.readyState;
-        return !(state === 0 || state == 4);
+    getError: function() {
+        return this.error;
     },
 
     /**
-     * Aborts any outstanding request.
-     * @param {Object} request (Optional) defaults to the last request
+     * Returns an array of Ext.data.Model instances as set by the Proxy.
+     * @return {Ext.data.Model[]} Any loaded Records
      */
-    abort : function(request) {
-        var me = this,
-            requests = me.requests,
-            id;
+    getRecords: function() {
+        var resultSet = this.getResultSet();
 
-        if (request && me.isLoading(request)) {
-            /*
-             * Clear out the onreadystatechange here, this allows us
-             * greater control, the browser may/may not fire the function
-             * depending on a series of conditions.
-             */
-            request.xhr.onreadystatechange = null;
-            request.xhr.abort();
-            me.clearTimeout(request);
-            if (!request.timedout) {
-                request.aborted = true;
-            }
-            me.onComplete(request);
-            me.cleanup(request);
-        } else if (!request) {
-            for(id in requests) {
-                if (requests.hasOwnProperty(id)) {
-                    me.abort(requests[id]);
-                }
-            }
-        }
+        return (resultSet === undefined ? this.records : resultSet.records);
     },
 
     /**
-     * Fires when the state of the xhr changes
-     * @private
-     * @param {Object} request The request
+     * Returns the ResultSet object (if set by the Proxy). This object will contain the {@link Ext.data.Model model}
+     * instances as well as meta data such as number of instances fetched, number available etc
+     * @return {Ext.data.ResultSet} The ResultSet object
      */
-    onStateChange : function(request) {
-        if (request.xhr.readyState == 4) {
-            this.clearTimeout(request);
-            this.onComplete(request);
-            this.cleanup(request);
-        }
+    getResultSet: function() {
+        return this.resultSet;
     },
 
     /**
-     * Clear the timeout on the request
-     * @private
-     * @param {Object} The request
+     * Returns true if the Operation has been started. Note that the Operation may have started AND completed, see
+     * {@link #isRunning} to test if the Operation is currently running.
+     * @return {Boolean} True if the Operation has started
      */
-    clearTimeout: function(request){
-        clearTimeout(request.timeout);
-        delete request.timeout;
+    isStarted: function() {
+        return this.started === true;
     },
 
     /**
-     * Clean up any left over information from the request
-     * @private
-     * @param {Object} The request
+     * Returns true if the Operation has been started but has not yet completed.
+     * @return {Boolean} True if the Operation is currently running
      */
-    cleanup: function(request){
-        request.xhr = null;
-        delete request.xhr;
+    isRunning: function() {
+        return this.running === true;
     },
 
     /**
-     * To be called when the request has come back from the server
-     * @private
-     * @param {Object} request
-     * @return {Object} The response
+     * Returns true if the Operation has been completed
+     * @return {Boolean} True if the Operation is complete
      */
-    onComplete : function(request) {
-        var me = this,
-            options = request.options,
-            result,
-            success,
-            response;
-            
-        try {
-            result = me.parseStatus(request.xhr.status);
-        } catch (e) {
-            // in some browsers we can't access the status if the readyState is not 4, so the request has failed
-            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;
+    isComplete: function() {
+        return this.complete === true;
     },
 
     /**
-     * Check if the response status was successful
-     * @param {Number} status The status code
-     * @return {Object} An object containing success/status state
+     * Returns true if the Operation has completed and was successful
+     * @return {Boolean} True if successful
      */
-    parseStatus: function(status) {
-        // see: https://prototype.lighthouseapp.com/projects/8886/tickets/129-ie-mangles-http-response-status-code-204-to-1223
-        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
-        };
+    wasSuccessful: function() {
+        return this.isComplete() && this.success === true;
     },
 
     /**
-     * Create the response object
      * @private
-     * @param {Object} request
+     * Associates this Operation with a Batch
+     * @param {Ext.data.Batch} batch The batch
      */
-    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
-        };
-
-        // If we don't explicitly tear down the xhr reference, IE6/IE7 will hold this in the closure of the
-        // functions created with getResponseHeader/getAllResponseHeaders
-        xhr = null;
-        return response;
+    setBatch: function(batch) {
+        this.batch = batch;
     },
 
     /**
-     * Create the exception object
-     * @private
-     * @param {Object} request
+     * Checks whether this operation should cause writing to occur.
+     * @return {Boolean} Whether the operation should cause a write to occur.
      */
-    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
-        };
+    allowWrite: function() {
+        return this.action != 'read';
     }
 });
-
 /**
- * @class Ext.Ajax
- * @singleton
- * @markdown
- * @extends Ext.data.Connection
-
-A singleton instance of an {@link Ext.data.Connection}. This class
-is used to communicate with your server side code. It can be used as follows:
-
-    Ext.Ajax.request({
-        url: 'page.php',
-        params: {
-            id: 1
-        },
-        success: function(response){
-            var text = response.responseText;
-            // process server response here
-        }
-    });
-
-Default options for all requests can be set by changing a property on the Ext.Ajax class:
-
-    Ext.Ajax.timeout = 60000; // 60 seconds
-
-Any options specified in the request method for the Ajax request will override any
-defaults set on the Ext.Ajax class. In the code sample below, the timeout for the
-request will be 60 seconds.
-
-    Ext.Ajax.timeout = 120000; // 120 seconds
-    Ext.Ajax.request({
-        url: 'page.aspx',
-        timeout: 60000
-    });
-
-In general, this class will be used for all Ajax requests in your application.
-The main reason for creating a separate {@link Ext.data.Connection} is for a
-series of requests that share common settings that are different to all other
-requests in the application.
-
+ * @author Ed Spencer
+ *
+ * This singleton contains a set of validation functions that can be used to validate any type of data. They are most
+ * often used in {@link Ext.data.Model Models}, where they are automatically set up and executed.
  */
-Ext.define('Ext.Ajax', {
-    extend: 'Ext.data.Connection',
+Ext.define('Ext.data.validations', {
     singleton: true,
-
+    
     /**
-     * @cfg {String} url @hide
+     * @property {String} presenceMessage
+     * The default error message used when a presence validation fails.
      */
+    presenceMessage: 'must be present',
+    
     /**
-     * @cfg {Object} extraParams @hide
+     * @property {String} lengthMessage
+     * The default error message used when a length validation fails.
      */
+    lengthMessage: 'is the wrong length',
+    
     /**
-     * @cfg {Object} defaultHeaders @hide
+     * @property {Boolean} formatMessage
+     * The default error message used when a format validation fails.
      */
+    formatMessage: 'is the wrong format',
+    
     /**
-     * @cfg {String} method (Optional) @hide
+     * @property {String} inclusionMessage
+     * The default error message used when an inclusion validation fails.
      */
+    inclusionMessage: 'is not included in the list of acceptable values',
+    
     /**
-     * @cfg {Number} timeout (Optional) @hide
+     * @property {String} exclusionMessage
+     * The default error message used when an exclusion validation fails.
      */
+    exclusionMessage: 'is not an acceptable value',
+    
     /**
-     * @cfg {Boolean} autoAbort (Optional) @hide
+     * @property {String} emailMessage
+     * The default error message used when an email validation fails
      */
-
+    emailMessage: 'is not a valid email address',
+    
     /**
-     * @cfg {Boolean} disableCaching (Optional) @hide
+     * @property {RegExp} emailRe
+     * The regular expression used to validate email addresses
      */
-
+    emailRe: /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,
+    
     /**
-     * @property  disableCaching
-     * True to add a unique cache-buster param to GET requests. (defaults to true)
-     * @type Boolean
+     * Validates that the given value is present.
+     * For example:
+     *
+     *     validations: [{type: 'presence', field: 'age'}]
+     *
+     * @param {Object} config Config object
+     * @param {Object} value The value to validate
+     * @return {Boolean} True if validation passed
      */
+    presence: function(config, value) {
+        if (value === undefined) {
+            value = config;
+        }
+        
+        //we need an additional check for zero here because zero is an acceptable form of present data
+        return !!value || value === 0;
+    },
+    
     /**
-     * @property  url
-     * The default URL to be used for requests to the server. (defaults to undefined)
-     * If the server receives all requests through one URL, setting this once is easier than
-     * entering it on every request.
-     * @type String
+     * Returns true if the given value is between the configured min and max values.
+     * For example:
+     *
+     *     validations: [{type: 'length', field: 'name', min: 2}]
+     *
+     * @param {Object} config Config object
+     * @param {String} value The value to validate
+     * @return {Boolean} True if the value passes validation
      */
+    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;
+        }
+    },
+    
     /**
-     * @property  extraParams
-     * An object containing properties which are used as extra parameters to each request made
-     * by this object (defaults to undefined). Session information and other data that you need
-     * to pass with each request are commonly put here.
-     * @type Object
+     * Validates that an email string is in the correct format
+     * @param {Object} config Config object
+     * @param {String} email The email address
+     * @return {Boolean} True if the value passes validation
      */
+    email: function(config, email) {
+        return Ext.data.validations.emailRe.test(email);
+    },
+    
     /**
-     * @property  defaultHeaders
-     * An object containing request headers which are added to each request made by this object
-     * (defaults to undefined).
-     * @type Object
+     * Returns true if the given value passes validation against the configured `matcher` regex.
+     * For example:
+     *
+     *     validations: [{type: 'format', field: 'username', matcher: /([a-z]+)[0-9]{2,3}/}]
+     *
+     * @param {Object} config Config object
+     * @param {String} value The value to validate
+     * @return {Boolean} True if the value passes the format validation
      */
+    format: function(config, value) {
+        return !!(config.matcher && config.matcher.test(value));
+    },
+    
     /**
-     * @property  method
-     * The default HTTP method to be used for requests. Note that this is case-sensitive and
-     * should be all caps (defaults to undefined; if not set but params are present will use
-     * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
-     * @type String
-     */
-    /**
-     * @property  timeout
-     * The timeout in milliseconds to be used for requests. (defaults to 30000)
-     * @type Number
+     * Validates that the given value is present in the configured `list`.
+     * For example:
+     *
+     *     validations: [{type: 'inclusion', field: 'gender', list: ['Male', 'Female']}]
+     *
+     * @param {Object} config Config object
+     * @param {String} value The value to validate
+     * @return {Boolean} True if the value is present in the list
      */
-
+    inclusion: function(config, value) {
+        return config.list && Ext.Array.indexOf(config.list,value) != -1;
+    },
+    
     /**
-     * @property  autoAbort
-     * Whether a new request should abort any pending requests. (defaults to false)
-     * @type Boolean
+     * Validates that the given value is present in the configured `list`.
+     * For example:
+     *
+     *     validations: [{type: 'exclusion', field: 'username', list: ['Admin', 'Operator']}]
+     *
+     * @param {Object} config Config object
+     * @param {String} value The value to validate
+     * @return {Boolean} True if the value is not present in the list
      */
-    autoAbort : false
+    exclusion: function(config, value) {
+        return config.list && Ext.Array.indexOf(config.list,value) == -1;
+    }
 });
 /**
  * @author Ed Spencer
- * @class Ext.data.Association
- * @extends Object
- *
- * <p>Associations enable you to express relationships between different {@link Ext.data.Model Models}. Let's say we're
- * writing an ecommerce system where Users can make Orders - there's a relationship between these Models that we can
- * express like this:</p>
  *
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'name', 'email'],
+ * Simple wrapper class that represents a set of records returned by a Proxy.
+ */
+Ext.define('Ext.data.ResultSet', {
+    /**
+     * @cfg {Boolean} loaded
+     * True if the records have already been loaded. This is only meaningful when dealing with
+     * SQL-backed proxies.
+     */
+    loaded: true,
 
-    hasMany: {model: 'Order', name: 'orders'}
-});
+    /**
+     * @cfg {Number} count
+     * The number of records in this ResultSet. Note that total may differ from this number.
+     */
+    count: 0,
 
-Ext.define('Order', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'user_id', 'status', 'price'],
+    /**
+     * @cfg {Number} total
+     * The total number of records reported by the data source. This ResultSet may form a subset of
+     * those records (see {@link #count}).
+     */
+    total: 0,
 
-    belongsTo: 'User'
-});
-</code></pre>
- *
- * <p>We've set up two models - User and Order - and told them about each other. You can set up as many associations on
- * each Model as you need using the two default types - {@link Ext.data.HasManyAssociation hasMany} and
- * {@link Ext.data.BelongsToAssociation belongsTo}. There's much more detail on the usage of each of those inside their
- * documentation pages. If you're not familiar with Models already, {@link Ext.data.Model there is plenty on those too}.</p>
- *
- * <p><u>Further Reading</u></p>
- *
- * <ul style="list-style-type: disc; padding-left: 20px;">
- *   <li>{@link Ext.data.HasManyAssociation hasMany associations}
- *   <li>{@link Ext.data.BelongsToAssociation belongsTo associations}
- *   <li>{@link Ext.data.Model using Models}
- * </ul>
- * 
- * <b>Self association models</b>
- * <p>We can also have models that create parent/child associations between the same type. Below is an example, where
- * groups can be nested inside other groups:</p>
- * <pre><code>
+    /**
+     * @cfg {Boolean} success
+     * True if the ResultSet loaded successfully, false if any errors were encountered.
+     */
+    success: false,
 
-// Server Data
-{
-    "groups": {
-        "id": 10,
-        "parent_id": 100,
-        "name": "Main Group",
-        "parent_group": {
-            "id": 100,
-            "parent_id": null,
-            "name": "Parent Group"
-        },
-        "child_groups": [{
-            "id": 2,
-            "parent_id": 10,
-            "name": "Child Group 1"
-        },{
-            "id": 3,
-            "parent_id": 10,
-            "name": "Child Group 2"
-        },{
-            "id": 4,
-            "parent_id": 10,
-            "name": "Child Group 3"
-        }]
-    }
-}
+    /**
+     * @cfg {Ext.data.Model[]} records (required)
+     * The array of record instances.
+     */
 
-// Client code
-Ext.define('Group', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'parent_id', 'name'],
-    proxy: {
-        type: 'ajax',
-        url: 'data.json',
-        reader: {
-            type: 'json',
-            root: 'groups'
-        }
-    },
-    associations: [{
-        type: 'hasMany',
-        model: 'Group',
-        primaryKey: 'id',
-        foreignKey: 'parent_id',
-        autoLoad: true,
-        associationKey: 'child_groups' // read child data from child_groups
-    }, {
-        type: 'belongsTo',
-        model: 'Group',
-        primaryKey: 'id',
-        foreignKey: 'parent_id',
-        autoLoad: true,
-        associationKey: 'parent_group' // read parent data from parent_group
-    }]
-});
+    /**
+     * Creates the resultSet
+     * @param {Object} [config] Config object.
+     */
+    constructor: function(config) {
+        Ext.apply(this, config);
 
+        /**
+         * @property {Number} totalRecords
+         * Copy of this.total.
+         * @deprecated Will be removed in Ext JS 5.0. Use {@link #total} instead.
+         */
+        this.totalRecords = this.total;
 
-Ext.onReady(function(){
-    
-    Group.load(10, {
-        success: function(group){
-            console.log(group.getGroup().get('name'));
-            
-            group.groups().each(function(rec){
-                console.log(rec.get('name'));
-            });
+        if (config.count === undefined) {
+            this.count = this.records.length;
         }
-    });
-    
+    }
 });
- * </code></pre>
+/**
+ * @author Ed Spencer
  *
+ * Base Writer class used by most subclasses of {@link Ext.data.proxy.Server}. This class is responsible for taking a
+ * set of {@link Ext.data.Operation} objects and a {@link Ext.data.Request} object and modifying that request based on
+ * the Operations.
+ *
+ * For example a Ext.data.writer.Json would format the Operations and their {@link Ext.data.Model} instances based on
+ * the config options passed to the JsonWriter's constructor.
+ *
+ * Writers are not needed for any kind of local storage - whether via a {@link Ext.data.proxy.WebStorage Web Storage
+ * proxy} (see {@link Ext.data.proxy.LocalStorage localStorage} and {@link Ext.data.proxy.SessionStorage
+ * sessionStorage}) or just in memory via a {@link Ext.data.proxy.Memory MemoryProxy}.
  */
-Ext.define('Ext.data.Association', {
+Ext.define('Ext.data.writer.Writer', {
+    alias: 'writer.base',
+    alternateClassName: ['Ext.data.DataWriter', 'Ext.data.Writer'],
+    
     /**
-     * @cfg {String} ownerModel The string name of the model that owns the association. Required
+     * @cfg {Boolean} writeAllFields
+     * True to write all fields from the record to the server. If set to false it will only send the fields that were
+     * modified. Note that any fields that have {@link Ext.data.Field#persist} set to false will still be ignored.
      */
-
+    writeAllFields: true,
+    
     /**
-     * @cfg {String} associatedModel The string name of the model that is being associated with. Required
+     * @cfg {String} nameProperty
+     * This property is used to read the key for each value that will be sent to the server. For example:
+     *
+     *     Ext.define('Person', {
+     *         extend: 'Ext.data.Model',
+     *         fields: [{
+     *             name: 'first',
+     *             mapping: 'firstName'
+     *         }, {
+     *             name: 'last',
+     *             mapping: 'lastName'
+     *         }, {
+     *             name: 'age'
+     *         }]
+     *     });
+     *     new Ext.data.writer.Writer({
+     *         writeAllFields: true,
+     *         nameProperty: 'mapping'
+     *     });
+     *
+     *     // This will be sent to the server
+     *     {
+     *         firstName: 'first name value',
+     *         lastName: 'last name value',
+     *         age: 1
+     *     }
+     *
+     * If the value is not present, the field name will always be used.
      */
+    nameProperty: 'name',
 
     /**
-     * @cfg {String} primaryKey The name of the primary key on the associated model. Defaults to 'id'.
-     * In general this will be the {@link Ext.data.Model#idProperty} of the Model.
+     * Creates new Writer.
+     * @param {Object} [config] Config object.
      */
-    primaryKey: 'id',
+    constructor: function(config) {
+        Ext.apply(this, config);
+    },
 
     /**
-     * @cfg {Ext.data.reader.Reader} reader A special reader to read associated data
-     */
-    
-    /**
-     * @cfg {String} associationKey The name of the property in the data to read the association from.
-     * Defaults to the name of the associated model.
+     * Prepares a Proxy's Ext.data.Request object
+     * @param {Ext.data.Request} request The request object
+     * @return {Ext.data.Request} The modified request object
      */
+    write: function(request) {
+        var operation = request.operation,
+            records   = operation.records || [],
+            len       = records.length,
+            i         = 0,
+            data      = [];
 
-    defaultReaderType: 'json',
+        for (; i < len; i++) {
+            data.push(this.getRecordData(records[i]));
+        }
+        return this.writeRecords(request, data);
+    },
 
-    statics: {
-        create: function(association){
-            if (!association.isAssociation) {
-                if (Ext.isString(association)) {
-                    association = {
-                        type: association
-                    };
+    /**
+     * Formats the data for each record before sending it to the server. This method should be overridden to format the
+     * data in a way that differs from the default.
+     * @param {Object} record The record that we are writing to the server.
+     * @return {Object} An object literal of name/value keys to be written to the server. By default this method returns
+     * the data property on the record.
+     */
+    getRecordData: function(record) {
+        var isPhantom = record.phantom === true,
+            writeAll = this.writeAllFields || isPhantom,
+            nameProperty = this.nameProperty,
+            fields = record.fields,
+            data = {},
+            changes,
+            name,
+            field,
+            key;
+        
+        if (writeAll) {
+            fields.each(function(field){
+                if (field.persist) {
+                    name = field[nameProperty] || field.name;
+                    data[name] = record.get(field.name);
                 }
-
-                switch (association.type) {
-                    case 'belongsTo':
-                        return Ext.create('Ext.data.BelongsToAssociation', association);
-                    case 'hasMany':
-                        return Ext.create('Ext.data.HasManyAssociation', association);
-                    //TODO Add this back when it's fixed
-//                    case 'polymorphic':
-//                        return Ext.create('Ext.data.PolymorphicAssociation', association);
-                    default:
-                        //<debug>
-                        Ext.Error.raise('Unknown Association type: "' + association.type + '"');
-                        //</debug>
+            });
+        } else {
+            // Only write the changes
+            changes = record.getChanges();
+            for (key in changes) {
+                if (changes.hasOwnProperty(key)) {
+                    field = fields.get(key);
+                    name = field[nameProperty] || field.name;
+                    data[name] = changes[key];
                 }
             }
-            return association;
+            if (!isPhantom) {
+                // always include the id for non phantoms
+                data[record.idProperty] = record.getId();
+            }
         }
-    },
+        return data;
+    }
+});
+
+/**
+ * A mixin to add floating capability to a Component.
+ */
+Ext.define('Ext.util.Floating', {
+
+    uses: ['Ext.Layer', 'Ext.window.Window'],
 
     /**
-     * Creates the Association object.
-     * @param {Object} config (optional) Config object.
+     * @cfg {Boolean} focusOnToFront
+     * Specifies whether the floated component should be automatically {@link Ext.Component#focus focused} when
+     * it is {@link #toFront brought to the front}.
+     */
+    focusOnToFront: true,
+
+    /**
+     * @cfg {String/Boolean} shadow
+     * Specifies whether the floating component should be given a shadow. Set to true to automatically create an {@link
+     * Ext.Shadow}, or a string indicating the shadow's display {@link Ext.Shadow#mode}. Set to false to disable the
+     * shadow.
      */
+    shadow: 'sides',
+
     constructor: function(config) {
-        Ext.apply(this, config);
+        var me = this;
+        
+        me.floating = true;
+        me.el = Ext.create('Ext.Layer', Ext.apply({}, config, {
+            hideMode: me.hideMode,
+            hidden: me.hidden,
+            shadow: Ext.isDefined(me.shadow) ? me.shadow : 'sides',
+            shadowOffset: me.shadowOffset,
+            constrain: false,
+            shim: me.shim === false ? false : undefined
+        }), me.el);
+    },
 
-        var types           = Ext.ModelManager.types,
-            ownerName       = config.ownerModel,
-            associatedName  = config.associatedModel,
-            ownerModel      = types[ownerName],
-            associatedModel = types[associatedName],
-            ownerProto;
+    onFloatRender: function() {
+        var me = this;
+        me.zIndexParent = me.getZIndexParent();
+        me.setFloatParent(me.ownerCt);
+        delete me.ownerCt;
 
-        //<debug>
-        if (ownerModel === undefined) {
-            Ext.Error.raise("The configured ownerModel was not valid (you tried " + ownerName + ")");
+        if (me.zIndexParent) {
+            me.zIndexParent.registerFloatingItem(me);
+        } else {
+            Ext.WindowManager.register(me);
         }
-        if (associatedModel === undefined) {
-            Ext.Error.raise("The configured associatedModel was not valid (you tried " + associatedName + ")");
+    },
+
+    setFloatParent: function(floatParent) {
+        var me = this;
+
+        // Remove listeners from previous floatParent
+        if (me.floatParent) {
+            me.mun(me.floatParent, {
+                hide: me.onFloatParentHide,
+                show: me.onFloatParentShow,
+                scope: me
+            });
         }
-        //</debug>
 
-        this.ownerModel = ownerModel;
-        this.associatedModel = associatedModel;
+        me.floatParent = floatParent;
 
-        /**
-         * The name of the model that 'owns' the association
-         * @property ownerName
-         * @type String
-         */
+        // Floating Components as children of Containers must hide when their parent hides.
+        if (floatParent) {
+            me.mon(me.floatParent, {
+                hide: me.onFloatParentHide,
+                show: me.onFloatParentShow,
+                scope: me
+            });
+        }
 
-        /**
-         * The name of the model is on the other end of the association (e.g. if a User model hasMany Orders, this is 'Order')
-         * @property associatedName
-         * @type String
-         */
+        // If a floating Component is configured to be constrained, but has no configured
+        // constrainTo setting, set its constrainTo to be it's ownerCt before rendering.
+        if ((me.constrain || me.constrainHeader) && !me.constrainTo) {
+            me.constrainTo = floatParent ? floatParent.getTargetEl() : me.container;
+        }
+    },
 
-        Ext.applyIf(this, {
-            ownerName : ownerName,
-            associatedName: associatedName
-        });
+    onFloatParentHide: function() {
+        var me = this;
+        
+        if (me.hideOnParentHide !== false) {
+            me.showOnParentShow = me.isVisible();
+            me.hide();
+        }
+    },
+
+    onFloatParentShow: function() {
+        if (this.showOnParentShow) {
+            delete this.showOnParentShow;
+            this.show();
+        }
     },
 
     /**
-     * Get a specialized reader for reading associated data
-     * @return {Ext.data.reader.Reader} The reader, null if not supplied
+     * @private
+     * Finds the ancestor Container responsible for allocating zIndexes for the passed Component.
+     *
+     * That will be the outermost floating Container (a Container which has no ownerCt and has floating:true).
+     *
+     * If we have no ancestors, or we walk all the way up to the document body, there's no zIndexParent,
+     * and the global Ext.WindowManager will be used.
      */
-    getReader: function(){
-        var me = this,
-            reader = me.reader,
-            model = me.associatedModel;
+    getZIndexParent: function() {
+        var p = this.ownerCt,
+            c;
 
-        if (reader) {
-            if (Ext.isString(reader)) {
-                reader = {
-                    type: reader
-                };
+        if (p) {
+            while (p) {
+                c = p;
+                p = p.ownerCt;
             }
-            if (reader.isReader) {
-                reader.setModel(model);
-            } else {
-                Ext.applyIf(reader, {
-                    model: model,
-                    type : me.defaultReaderType
-                });
+            if (c.floating) {
+                return c;
             }
-            me.reader = Ext.createByAlias('reader.' + reader.type, reader);
         }
-        return me.reader || null;
-    }
-});
-
-/**
- * @author Ed Spencer
- * @class Ext.ModelManager
- * @extends Ext.AbstractManager
-
-The ModelManager keeps track of all {@link Ext.data.Model} types defined in your application.
+    },
 
-__Creating Model Instances__
-Model instances can be created by using the {@link #create} function. It is also possible to do
-this by using the Model type directly. The following snippets are equivalent:
+    // private
+    // z-index is managed by the zIndexManager and may be overwritten at any time.
+    // Returns the next z-index to be used.
+    // If this is a Container, then it will have rebased any managed floating Components,
+    // and so the next available z-index will be approximately 10000 above that.
+    setZIndex: function(index) {
+        var me = this;
+        me.el.setZIndex(index);
 
-    Ext.define('User', {
-        extend: 'Ext.data.Model',
-        fields: ['first', 'last']
-    });
-    
-    // method 1, create through the manager
-    Ext.ModelManager.create({
-        first: 'Ed',
-        last: 'Spencer'
-    }, 'User');
-    
-    // method 2, create on the type directly
-    new User({
-        first: 'Ed',
-        last: 'Spencer'
-    });
-    
-__Accessing Model Types__
-A reference to a Model type can be obtained by using the {@link #getModel} function. Since models types
-are normal classes, you can access the type directly. The following snippets are equivalent:
+        // Next item goes 10 above;
+        index += 10;
 
-    Ext.define('User', {
-        extend: 'Ext.data.Model',
-        fields: ['first', 'last']
-    });
-    
-    // method 1, access model type through the manager
-    var UserType = Ext.ModelManager.getModel('User');
-    
-    // method 2, reference the type directly
-    var UserType = User;
+        // When a Container with floating items has its z-index set, it rebases any floating items it is managing.
+        // The returned value is a round number approximately 10000 above the last z-index used.
+        if (me.floatingItems) {
+            index = Math.floor(me.floatingItems.setBase(index) / 100) * 100 + 10000;
+        }
+        return index;
+    },
 
- * @markdown
- * @singleton
- */
-Ext.define('Ext.ModelManager', {
-    extend: 'Ext.AbstractManager',
-    alternateClassName: 'Ext.ModelMgr',
-    requires: ['Ext.data.Association'],
-    
-    singleton: true,
-    
-    typeName: 'mtype',
-    
-    /**
-     * Private stack of associations that must be created once their associated model has been defined
-     * @property associationStack
-     * @type Array
-     */
-    associationStack: [],
-    
     /**
-     * Registers a model definition. All model plugins marked with isDefault: true are bootstrapped
-     * immediately, as are any addition plugins defined in the model config.
-     * @private
+     * Moves this floating Component into a constrain region.
+     *
+     * By default, this Component is constrained to be within the container it was added to, or the element it was
+     * rendered to.
+     *
+     * An alternative constraint may be passed.
+     * @param {String/HTMLElement/Ext.Element/Ext.util.Region} constrainTo (Optional) The Element or {@link Ext.util.Region Region} into which this Component is
+     * to be constrained. Defaults to the element into which this floating Component was rendered.
      */
-    registerType: function(name, config) {
-        var proto = config.prototype,
-            model;
-        if (proto && proto.isModel) {
-            // registering an already defined model
-            model = config;
-        } else {
-            // passing in a configuration
-            if (!config.extend) {
-                config.extend = 'Ext.data.Model';
-            }
-            model = Ext.define(name, config);
+    doConstrain: function(constrainTo) {
+        var me = this,
+            vector = me.getConstrainVector(constrainTo || me.el.getScopeParent()),
+            xy;
+
+        if (vector) {
+            xy = me.getPosition();
+            xy[0] += vector[0];
+            xy[1] += vector[1];
+            me.setPosition(xy);
         }
-        this.types[name] = model;
-        return model;
     },
-    
+
+
     /**
+     * Gets the x/y offsets to constrain this float
      * @private
-     * Private callback called whenever a model has just been defined. This sets up any associations
-     * that were waiting for the given model to be defined
-     * @param {Function} model The model that was just created
+     * @param {String/HTMLElement/Ext.Element/Ext.util.Region} constrainTo (Optional) The Element or {@link Ext.util.Region Region} into which this Component is to be constrained.
+     * @return {Number[]} The x/y constraints
      */
-    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.create(created));
-            Ext.Array.remove(stack, created);
+    getConstrainVector: function(constrainTo){
+        var me = this,
+            el;
+
+        if (me.constrain || me.constrainHeader) {
+            el = me.constrainHeader ? me.header.el : me.el;
+            constrainTo = constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container;
+            return el.getConstrainVector(constrainTo);
         }
     },
-    
+
     /**
-     * Registers an association where one of the models defined doesn't exist yet.
-     * The ModelManager will check when new models are registered if it can link them
-     * together
-     * @private
-     * @param {Ext.data.Association} association The association
+     * Aligns this floating Component to the specified element
+     *
+     * @param {Ext.Component/Ext.Element/HTMLElement/String} element
+     * The element or {@link Ext.Component} to align to. If passing a component, it must be a
+     * omponent instance. If a string id is passed, it will be used as an element id.
+     * @param {String} [position="tl-bl?"] The position to align to (see {@link
+     * Ext.Element#alignTo} for more details).
+     * @param {Number[]} [offsets] Offset the positioning by [x, y]
+     * @return {Ext.Component} this
      */
-    registerDeferredAssociation: function(association){
-        this.associationStack.push(association);
+    alignTo: function(element, position, offsets) {
+        if (element.isComponent) {
+            element = element.getEl();
+        }
+        var xy = this.el.getAlignToXY(element, position, offsets);
+        this.setPagePosition(xy);
+        return this;
     },
-    
+
     /**
-     * Returns the {@link Ext.data.Model} for a given model name
-     * @param {String/Object} id The id of the model or the model instance.
+     * Brings this floating Component to the front of any other visible, floating Components managed by the same {@link
+     * Ext.ZIndexManager ZIndexManager}
+     *
+     * If this Component is modal, inserts the modal mask just below this Component in the z-index stack.
+     *
+     * @param {Boolean} [preventFocus=false] Specify `true` to prevent the Component from being focused.
+     * @return {Ext.Component} this
      */
-    getModel: function(id) {
-        var model = id;
-        if (typeof model == 'string') {
-            model = this.types[model];
+    toFront: function(preventFocus) {
+        var me = this;
+
+        // Find the floating Component which provides the base for this Component's zIndexing.
+        // That must move to front to then be able to rebase its zIndex stack and move this to the front
+        if (me.zIndexParent) {
+            me.zIndexParent.toFront(true);
         }
-        return model;
+        if (me.zIndexManager.bringToFront(me)) {
+            if (!Ext.isDefined(preventFocus)) {
+                preventFocus = !me.focusOnToFront;
+            }
+            if (!preventFocus) {
+                // Kick off a delayed focus request.
+                // If another floating Component is toFronted before the delay expires
+                // this will not receive focus.
+                me.focus(false, true);
+            }
+        }
+        return me;
     },
-    
+
     /**
-     * Creates a new instance of a Model using the given data.
-     * @param {Object} data Data to initialize the Model's fields with
-     * @param {String} name The name of the model to create
-     * @param {Number} id Optional unique id of the Model instance (see {@link Ext.data.Model})
-     */
-    create: function(config, name, id) {
-        var con = typeof name == 'function' ? name : this.types[name || config.name];
-        
-        return new con(config, id);
-    }
-}, function() {
-    
-    /**
-     * Creates a new Model class from the specified config object. See {@link Ext.data.Model} for full examples.
-     * 
-     * @param {Object} config A configuration object for the Model you wish to create.
-     * @return {Ext.data.Model} The newly registered Model
-     * @member Ext
-     * @method regModel
+     * This method is called internally by {@link Ext.ZIndexManager} to signal that a floating Component has either been
+     * moved to the top of its zIndex stack, or pushed from the top of its zIndex stack.
+     *
+     * If a _Window_ is superceded by another Window, deactivating it hides its shadow.
+     *
+     * This method also fires the {@link Ext.Component#activate activate} or
+     * {@link Ext.Component#deactivate deactivate} event depending on which action occurred.
+     *
+     * @param {Boolean} [active=false] True to activate the Component, false to deactivate it.
+     * @param {Ext.Component} [newActive] The newly active Component which is taking over topmost zIndex position.
      */
-    Ext.regModel = function() {
-        //<debug>
-        if (Ext.isDefined(Ext.global.console)) {
-            Ext.global.console.warn('Ext.regModel has been deprecated. Models can now be created by extending Ext.data.Model: Ext.define("MyModel", {extend: "Ext.data.Model", fields: []});.');
+    setActive: function(active, newActive) {
+        var me = this;
+        
+        if (active) {
+            if (me.el.shadow && !me.maximized) {
+                me.el.enableShadow(true);
+            }
+            me.fireEvent('activate', me);
+        } else {
+            // Only the *Windows* in a zIndex stack share a shadow. All other types of floaters
+            // can keep their shadows all the time
+            if ((me instanceof Ext.window.Window) && (newActive instanceof Ext.window.Window)) {
+                me.el.disableShadow();
+            }
+            me.fireEvent('deactivate', me);
         }
-        //</debug>
-        return this.ModelManager.registerType.apply(this.ModelManager, arguments);
-    };
-});
-
-/**
- * @class Ext.app.Controller
- * 
- * 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 THIS GUIDE for a full explanation. 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.
- * 
- * <u>Using refs</u>
- * 
- * 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.
- * 
- * <u>Generated getter methods</u>
- * 
- * 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.
- * 
- * <u>Further Reading</u>
- * 
- * 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'
     },
 
     /**
-     * @cfg {String} id The id of this controller. You can use this id when dispatching.
+     * Sends this Component to the back of (lower z-index than) any other visible windows
+     * @return {Ext.Component} this
      */
+    toBack: function() {
+        this.zIndexManager.sendToBack(this);
+        return this;
+    },
 
-    onClassExtended: function(cls, data) {
-        var className = Ext.getClassName(cls),
-            match = className.match(/^(.*)\.controller\./);
+    /**
+     * Center this Component in its container.
+     * @return {Ext.Component} this
+     */
+    center: function() {
+        var me = this,
+            xy = me.el.getAlignToXY(me.container, 'c-c');
+        me.setPagePosition(xy);
+        return me;
+    },
 
-        if (match !== null) {
-            var namespace = Ext.Loader.getPrefix(className) || match[1],
-                onBeforeClassCreated = data.onBeforeClassCreated,
-                requires = [],
-                modules = ['model', 'view', 'store'],
-                prefix;
+    // private
+    syncShadow : function(){
+        if (this.floating) {
+            this.el.sync(true);
+        }
+    },
 
-            data.onBeforeClassCreated = function(cls, data) {
-                var i, ln, module,
-                    items, j, subLn, item;
+    // private
+    fitContainer: function() {
+        var parent = this.floatParent,
+            container = parent ? parent.getTargetEl() : this.container,
+            size = container.getViewSize(false);
 
-                for (i = 0,ln = modules.length; i < ln; i++) {
-                    module = modules[i];
+        this.setSize(size);
+    }
+});
+/**
+ * Base Layout class - extended by ComponentLayout and ContainerLayout
+ */
+Ext.define('Ext.layout.Layout', {
 
-                    items = Ext.Array.from(data[module + 's']);
+    /* Begin Definitions */
 
-                    for (j = 0,subLn = items.length; j < subLn; j++) {
-                        item = items[j];
+    /* End Definitions */
 
-                        prefix = Ext.Loader.getPrefix(item);
+    isLayout: true,
+    initialized: false,
 
-                        if (prefix === '' || prefix === item) {
-                            requires.push(namespace + '.' + module + '.' + item);
-                        }
-                        else {
-                            requires.push(item);
-                        }
-                    }
+    statics: {
+        create: function(layout, defaultType) {
+            var type;
+            if (layout instanceof Ext.layout.Layout) {
+                return Ext.createByAlias('layout.' + layout);
+            } else {
+                if (!layout || typeof layout === 'string') {
+                    type = layout || defaultType;
+                    layout = {};                    
                 }
-
-                Ext.require(requires, Ext.Function.pass(onBeforeClassCreated, arguments, this));
-            };
+                else {
+                    type = layout.type || defaultType;
+                }
+                return Ext.createByAlias('layout.' + type, layout || {});
+            }
         }
     },
 
+    constructor : function(config) {
+        this.id = Ext.id(null, this.type + '-');
+        Ext.apply(this, config);
+    },
+
     /**
-     * Creates new Controller.
-     * @param {Object} config (optional) Config object.
+     * @private
      */
-    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);
+    layout : function() {
+        var me = this;
+        me.layoutBusy = true;
+        me.initLayout();
 
-        if (this.refs) {
-            this.ref(this.refs);
+        if (me.beforeLayout.apply(me, arguments) !== false) {
+            me.layoutCancelled = false;
+            me.onLayout.apply(me, arguments);
+            me.childrenChanged = false;
+            me.owner.needsLayout = false;
+            me.layoutBusy = false;
+            me.afterLayout.apply(me, arguments);
+        }
+        else {
+            me.layoutCancelled = true;
         }
+        me.layoutBusy = false;
+        me.doOwnerCtLayouts();
     },
 
-    // Template method
-    init: function(application) {},
-    // Template method
-    onLaunch: function(application) {},
+    beforeLayout : function() {
+        this.renderChildren();
+        return true;
+    },
 
-    createGetters: function(type, refs) {
-        type = Ext.String.capitalize(type);
-        Ext.Array.each(refs, function(ref) {
-            var fn = 'get',
-                parts = ref.split('.');
+    renderChildren: function () {
+        this.renderItems(this.getLayoutItems(), this.getRenderTarget());
+    },
 
-            // Handle namespaced class names. E.g. feed.Add becomes getFeedAddView etc.
-            Ext.Array.each(parts, function(part) {
-                fn += Ext.String.capitalize(part);
-            });
-            fn += type;
+    /**
+     * @private
+     * Iterates over all passed items, ensuring they are rendered.  If the items are already rendered,
+     * also determines if the items are in the proper place dom.
+     */
+    renderItems : function(items, target) {
+        var me = this,
+            ln = items.length,
+            i = 0,
+            item;
 
-            if (!this[fn]) {
-                this[fn] = Ext.Function.pass(this['get' + type], [ref], this);
+        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 {
+                // still need to configure the item, it may have moved in the container.
+                me.configureItem(item);
             }
-            // Execute it right away
-            this[fn](ref);
-        },
-        this);
+        }
     },
 
-    ref: function(refs) {
-        var me = this;
-        refs = Ext.Array.from(refs);
-        Ext.Array.each(refs, function(info) {
-            var ref = info.ref,
-                fn = 'get' + Ext.String.capitalize(ref);
-            if (!me[fn]) {
-                me[fn] = Ext.Function.pass(me.getRef, [ref, info], me);
+    // @private - Validates item is in the proper place in the dom.
+    isValidParent : function(item, target, position) {
+        var dom = item.el ? item.el.dom : Ext.getDom(item);
+        if (dom && target && target.dom) {
+            if (Ext.isNumber(position) && dom !== target.dom.childNodes[position]) {
+                return false;
             }
-        });
-    },
-
-    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');
+            return (dom.parentNode == (target.dom || target));
         }
+        return false;
+    },
 
-        var me = this,
-            selector = info.selector,
-            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');
+    /**
+     * @private
+     * Renders the given Component into the target Element.
+     * @param {Ext.Component} item The Component to render
+     * @param {Ext.Element} target The target Element
+     * @param {Number} position The position within the target to render the item to
+     */
+    renderItem : function(item, target, position) {
+        var me = this;
+        if (!item.rendered) {
+            if (me.itemCls) {
+                item.addCls(me.itemCls);
             }
-            if (cached) {
-                cached.on('beforedestroy', function() {
-                    me.refCache[ref] = null;
-                });
+            if (me.owner.itemCls) {
+                item.addCls(me.owner.itemCls);
             }
+            item.render(target, position);
+            me.configureItem(item);
+            me.childrenChanged = true;
         }
-
-        return cached;
     },
 
     /**
-     * Adds listeners to components selected via {@link Ext.ComponentQuery}. Accepts an 
-     * object containing component paths mapped to a hash of listener functions. 
-     *
-     * In the following example the `updateUser` function is mapped to to the `click` 
-     * event on a button component, which is a child of the `useredit` component.
-     *
-     *     Ext.define('AM.controller.Users', {
-     *         init: function() {
-     *             this.control({
-     *                 'useredit button[action=save]': {
-     *                     click: this.updateUser
-     *                 }
-     *             });
-     *         },
-     *     
-     *         updateUser: function(button) {
-     *             console.log('clicked the Save button');
-     *         }
-     *     });
-     *
-     * See {@link Ext.ComponentQuery} for more information on component selectors.
-     *
-     * @param {String|Object} selectors If a String, the second argument is used as the 
-     * listeners, otherwise an object of selectors -> listeners is assumed
-     * @param {Object} listeners
+     * @private
+     * Moved Component to the provided target instead.
      */
-    control: function(selectors, listeners) {
-        this.application.control(selectors, listeners, this);
+    moveItem : function(item, target, position) {
+        // Make sure target is a dom element
+        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);
+        this.childrenChanged = true;
     },
 
     /**
-     * Returns a reference to a {@link Ext.app.Controller controller} with the given name
-     * @param name {String}
+     * @private
+     * Adds the layout's targetCls if necessary and sets
+     * initialized flag when complete.
      */
-    getController: function(name) {
-        return this.application.getController(name);
+    initLayout : function() {
+        var me = this,
+            targetCls = me.targetCls;
+            
+        if (!me.initialized && !Ext.isEmpty(targetCls)) {
+            me.getTarget().addCls(targetCls);
+        }
+        me.initialized = true;
     },
 
-    /**
-     * Returns a reference to a {@link Ext.data.Store store} with the given name
-     * @param name {String}
-     */
-    getStore: function(name) {
-        return this.application.getStore(name);
+    // @private Sets the layout owner
+    setOwner : function(owner) {
+        this.owner = owner;
     },
 
-    /**
-     * Returns a reference to a {@link Ext.data.Model Model} with the given name
-     * @param name {String}
-     */
-    getModel: function(model) {
-        return this.application.getModel(model);
+    // @private - Returns empty array
+    getLayoutItems : function() {
+        return [];
     },
 
     /**
-     * Returns a reference to a view with the given name
-     * @param name {String}
+     * @private
+     * Applies itemCls
+     * Empty template method
      */
-    getView: function(view) {
-        return this.application.getView(view);
-    }
-});
-
-/**
- * @class Ext.data.SortTypes
- * This class defines a series of static methods that are used on a
- * {@link Ext.data.Field} for performing sorting. The methods cast the 
- * underlying values into a data type that is appropriate for sorting on
- * that particular field.  If a {@link Ext.data.Field#type} is specified, 
- * the sortType will be set to a sane default if the sortType is not 
- * explicitly defined on the field. The sortType will make any necessary
- * modifications to the value and return it.
- * <ul>
- * <li><b>asText</b> - Removes any tags and converts the value to a string</li>
- * <li><b>asUCText</b> - Removes any tags and converts the value to an uppercase string</li>
- * <li><b>asUCText</b> - Converts the value to an uppercase string</li>
- * <li><b>asDate</b> - Converts the value into Unix epoch time</li>
- * <li><b>asFloat</b> - Converts the value to a floating point number</li>
- * <li><b>asInt</b> - Converts the value to an integer number</li>
- * </ul>
- * <p>
- * It is also possible to create a custom sortType that can be used throughout
- * an application.
- * <pre><code>
-Ext.apply(Ext.data.SortTypes, {
-    asPerson: function(person){
-        // expects an object with a first and last name property
-        return person.lastName.toUpperCase() + person.firstName.toLowerCase();
-    }    
-});
-
-Ext.define('Employee', {
-    extend: 'Ext.data.Model',
-    fields: [{
-        name: 'person',
-        sortType: 'asPerson'
-    }, {
-        name: 'salary',
-        type: 'float' // sortType set to asFloat
-    }]
-});
- * </code></pre>
- * </p>
- * @singleton
- * @docauthor Evan Trimboli <evan@sencha.com>
- */
-Ext.define('Ext.data.SortTypes', {
-    
-    singleton: true,
+    configureItem: Ext.emptyFn,
     
-    /**
-     * Default sort that does nothing
-     * @param {Mixed} s The value being converted
-     * @return {Mixed} The comparison value
-     */
-    none : function(s) {
-        return s;
-    },
+    // Placeholder empty functions for subclasses to extend
+    onLayout : Ext.emptyFn,
+    afterLayout : Ext.emptyFn,
+    onRemove : Ext.emptyFn,
+    onDestroy : Ext.emptyFn,
+    doOwnerCtLayouts : Ext.emptyFn,
 
     /**
-     * The regular expression used to strip tags
-     * @type {RegExp}
-     * @property
+     * @private
+     * Removes itemCls
      */
-    stripTagsRE : /<\/?[^>]+>/gi,
+    afterRemove : function(item) {
+        var el = item.el,
+            owner = this.owner,
+            itemCls = this.itemCls,
+            ownerCls = owner.itemCls;
+            
+        // Clear managed dimensions flag when removed from the layout.
+        if (item.rendered && !item.isDestroyed) {
+            if (itemCls) {
+                el.removeCls(itemCls);
+            }
+            if (ownerCls) {
+                el.removeCls(ownerCls);
+            }
+        }
 
-    /**
-     * Strips all HTML tags to sort on text only
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
-     */
-    asText : function(s) {
-        return String(s).replace(this.stripTagsRE, "");
+        // These flags are set at the time a child item is added to a layout.
+        // The layout must decide if it is managing the item's width, or its height, or both.
+        // See AbstractComponent for docs on these properties.
+        delete item.layoutManagedWidth;
+        delete item.layoutManagedHeight;
     },
 
     /**
-     * Strips all HTML tags to sort on text only - Case insensitive
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * Destroys this layout. This is a template method that is empty by default, but should be implemented
+     * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
+     * @template
      */
-    asUCText : function(s) {
-        return String(s).toUpperCase().replace(this.stripTagsRE, "");
-    },
+    destroy : function() {
+        var targetCls = this.targetCls,
+            target;
+        
+        if (!Ext.isEmpty(targetCls)) {
+            target = this.getTarget();
+            if (target) {
+                target.removeCls(targetCls);
+            }
+        }
+        this.onDestroy();
+    }
+});
+/**
+ * @class Ext.ZIndexManager
+ * <p>A class that manages a group of {@link Ext.Component#floating} Components and provides z-order management,
+ * and Component activation behavior, including masking below the active (topmost) Component.</p>
+ * <p>{@link Ext.Component#floating Floating} Components which are rendered directly into the document (such as {@link Ext.window.Window Window}s) which are
+ * {@link Ext.Component#show show}n are managed by a {@link Ext.WindowManager global instance}.</p>
+ * <p>{@link Ext.Component#floating Floating} Components which are descendants of {@link Ext.Component#floating floating} <i>Containers</i>
+ * (for example a {@link Ext.view.BoundList BoundList} within an {@link Ext.window.Window Window}, or a {@link Ext.menu.Menu Menu}),
+ * are managed by a ZIndexManager owned by that floating Container. Therefore ComboBox dropdowns within Windows will have managed z-indices
+ * guaranteed to be correct, relative to the Window.</p>
+ */
+Ext.define('Ext.ZIndexManager', {
 
-    /**
-     * Case insensitive string
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
-     */
-    asUCString : function(s) {
-        return String(s).toUpperCase();
+    alternateClassName: 'Ext.WindowGroup',
+
+    statics: {
+        zBase : 9000
     },
 
-    /**
-     * Date sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
-     */
-    asDate : function(s) {
-        if(!s){
-            return 0;
+    constructor: function(container) {
+        var me = this;
+
+        me.list = {};
+        me.zIndexStack = [];
+        me.front = null;
+
+        if (container) {
+
+            // This is the ZIndexManager for an Ext.container.Container, base its zseed on the zIndex of the Container's element
+            if (container.isContainer) {
+                container.on('resize', me._onContainerResize, me);
+                me.zseed = Ext.Number.from(container.getEl().getStyle('zIndex'), me.getNextZSeed());
+                // The containing element we will be dealing with (eg masking) is the content target
+                me.targetEl = container.getTargetEl();
+                me.container = container;
+            }
+            // This is the ZIndexManager for a DOM element
+            else {
+                Ext.EventManager.onWindowResize(me._onContainerResize, me);
+                me.zseed = me.getNextZSeed();
+                me.targetEl = Ext.get(container);
+            }
         }
-        if(Ext.isDate(s)){
-            return s.getTime();
+        // No container passed means we are the global WindowManager. Our target is the doc body.
+        // DOM must be ready to collect that ref.
+        else {
+            Ext.EventManager.onWindowResize(me._onContainerResize, me);
+            me.zseed = me.getNextZSeed();
+            Ext.onDocumentReady(function() {
+                me.targetEl = Ext.getBody();
+            });
         }
-        return Date.parse(String(s));
     },
 
-    /**
-     * Float sorting
-     * @param {Mixed} s The value being converted
-     * @return {Float} The comparison value
-     */
-    asFloat : function(s) {
-        var val = parseFloat(String(s).replace(/,/g, ""));
-        return isNaN(val) ? 0 : val;
+    getNextZSeed: function() {
+        return (Ext.ZIndexManager.zBase += 10000);
     },
 
-    /**
-     * Integer sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
-     */
-    asInt : function(s) {
-        var val = parseInt(String(s).replace(/,/g, ""), 10);
-        return isNaN(val) ? 0 : val;
-    }
-});
-/**
- * @author Ed Spencer
- * @class Ext.data.Errors
- * @extends Ext.util.MixedCollection
- * 
- * <p>Wraps a collection of validation error responses and provides convenient functions for
- * accessing and errors for specific fields.</p>
- * 
- * <p>Usually this class does not need to be instantiated directly - instances are instead created
- * automatically when {@link Ext.data.Model#validate validate} on a model instance:</p>
- * 
-<pre><code>
-//validate some existing model instance - in this case it returned 2 failures messages
-var errors = myModel.validate();
+    setBase: function(baseZIndex) {
+        this.zseed = baseZIndex;
+        return this.assignZIndices();
+    },
 
-errors.isValid(); //false
+    // private
+    assignZIndices: function() {
+        var a = this.zIndexStack,
+            len = a.length,
+            i = 0,
+            zIndex = this.zseed,
+            comp;
 
-errors.length; //2
-errors.getByField('name');  // [{field: 'name',  message: 'must be present'}]
-errors.getByField('title'); // [{field: 'title', message: 'is too short'}]
-</code></pre>
- */
-Ext.define('Ext.data.Errors', {
-    extend: 'Ext.util.MixedCollection',
-    
-    /**
-     * Returns true if there are no errors in the collection
-     * @return {Boolean} 
-     */
-    isValid: function() {
-        return this.length === 0;
+        for (; i < len; i++) {
+            comp = a[i];
+            if (comp && !comp.hidden) {
+
+                // Setting the zIndex of a Component returns the topmost zIndex consumed by
+                // that Component.
+                // If it's just a plain floating Component such as a BoundList, then the
+                // return value is the passed value plus 10, ready for the next item.
+                // If a floating *Container* has its zIndex set, it re-orders its managed
+                // floating children, starting from that new base, and returns a value 10000 above
+                // the highest zIndex which it allocates.
+                zIndex = comp.setZIndex(zIndex);
+            }
+        }
+        this._activateLast();
+        return zIndex;
     },
-    
-    /**
-     * Returns all of the errors for the given field
-     * @param {String} fieldName The field to get errors for
-     * @return {Array} All errors for the given field
-     */
-    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);
+
+    // private
+    _setActiveChild: function(comp) {
+        if (comp !== this.front) {
+
+            if (this.front) {
+                this.front.setActive(false, comp);
+            }
+            this.front = comp;
+            if (comp) {
+                comp.setActive(true);
+                if (comp.modal) {
+                    this._showModalMask(comp);
+                }
             }
         }
-        
-        return errors;
-    }
-});
+    },
 
-/**
- * @author Ed Spencer
- * @class Ext.data.Operation
- * @extends Object
- * 
- * <p>Represents a single read or write operation performed by a {@link Ext.data.proxy.Proxy Proxy}.
- * Operation objects are used to enable communication between Stores and Proxies. Application
- * developers should rarely need to interact with Operation objects directly.</p>
- * 
- * <p>Several Operations can be batched together in a {@link Ext.data.Batch batch}.</p>
- * 
- */
-Ext.define('Ext.data.Operation', {
-    /**
-     * @cfg {Boolean} synchronous True if this Operation is to be executed synchronously (defaults to true). This
-     * property is inspected by a {@link Ext.data.Batch Batch} to see if a series of Operations can be executed in
-     * parallel or not.
-     */
-    synchronous: true,
-    
-    /**
-     * @cfg {String} action The action being performed by this Operation. Should be one of 'create', 'read', 'update' or 'destroy'
-     */
-    action: undefined,
-    
-    /**
-     * @cfg {Array} filters Optional array of filter objects. Only applies to 'read' actions.
-     */
-    filters: undefined,
-    
-    /**
-     * @cfg {Array} sorters Optional array of sorter objects. Only applies to 'read' actions.
-     */
-    sorters: undefined,
-    
-    /**
-     * @cfg {Object} group Optional grouping configuration. Only applies to 'read' actions where grouping is desired.
-     */
-    group: undefined,
-    
-    /**
-     * @cfg {Number} start The start index (offset), used in paging when running a 'read' action.
-     */
-    start: undefined,
-    
-    /**
-     * @cfg {Number} limit The number of records to load. Used on 'read' actions when paging is being used.
-     */
-    limit: undefined,
-    
-    /**
-     * @cfg {Ext.data.Batch} batch The batch that this Operation is a part of (optional)
-     */
-    batch: undefined,
+    // private
+    _activateLast: function(justHidden) {
+        var comp,
+            lastActivated = false,
+            i;
+
+        // Go down through the z-index stack.
+        // Activate the next visible one down.
+        // Keep going down to find the next visible modal one to shift the modal mask down under
+        for (i = this.zIndexStack.length-1; i >= 0; --i) {
+            comp = this.zIndexStack[i];
+            if (!comp.hidden) {
+                if (!lastActivated) {
+                    this._setActiveChild(comp);
+                    lastActivated = true;
+                }
+
+                // Move any modal mask down to just under the next modal floater down the stack
+                if (comp.modal) {
+                    this._showModalMask(comp);
+                    return;
+                }
+            }
+        }
+
+        // none to activate, so there must be no modal mask.
+        // And clear the currently active property
+        this._hideModalMask();
+        if (!lastActivated) {
+            this._setActiveChild(null);
+        }
+    },
+
+    _showModalMask: function(comp) {
+        var zIndex = comp.el.getStyle('zIndex') - 4,
+            maskTarget = comp.floatParent ? comp.floatParent.getTargetEl() : Ext.get(comp.getEl().dom.parentNode),
+            parentBox;
         
-    /**
-     * Read-only property tracking the start status of this Operation. Use {@link #isStarted}.
-     * @property started
-     * @type Boolean
-     * @private
-     */
-    started: false,
-    
-    /**
-     * Read-only property tracking the run status of this Operation. Use {@link #isRunning}.
-     * @property running
-     * @type Boolean
-     * @private
-     */
-    running: false,
-    
-    /**
-     * Read-only property tracking the completion status of this Operation. Use {@link #isComplete}.
-     * @property complete
-     * @type Boolean
-     * @private
-     */
-    complete: false,
-    
-    /**
-     * Read-only property tracking whether the Operation was successful or not. This starts as undefined and is set to true
-     * or false by the Proxy that is executing the Operation. It is also set to false by {@link #setException}. Use
-     * {@link #wasSuccessful} to query success status.
-     * @property success
-     * @type Boolean
-     * @private
-     */
-    success: undefined,
-    
-    /**
-     * Read-only property tracking the exception status of this Operation. Use {@link #hasException} and see {@link #getError}.
-     * @property exception
-     * @type Boolean
-     * @private
-     */
-    exception: false,
-    
-    /**
-     * The error object passed when {@link #setException} was called. This could be any object or primitive.
-     * @property error
-     * @type Mixed
-     * @private
-     */
-    error: undefined,
+        if (!maskTarget) {
+            //<debug>
+            Ext.global.console && Ext.global.console.warn && Ext.global.console.warn('mask target could not be found. Mask cannot be shown');
+            //</debug>
+            return;
+        }
+        
+        parentBox = maskTarget.getBox();
 
-    /**
-     * Creates new Operation object.
-     * @param {Object} config (optional) Config object.
-     */
-    constructor: function(config) {
-        Ext.apply(this, config || {});
+        if (!this.mask) {
+            this.mask = Ext.getBody().createChild({
+                cls: Ext.baseCSSPrefix + 'mask'
+            });
+            this.mask.setVisibilityMode(Ext.Element.DISPLAY);
+            this.mask.on('click', this._onMaskClick, this);
+        }
+        if (maskTarget.dom === document.body) {
+            parentBox.height = Ext.Element.getViewHeight();
+        }
+        maskTarget.addCls(Ext.baseCSSPrefix + 'body-masked');
+        this.mask.setBox(parentBox);
+        this.mask.setStyle('zIndex', zIndex);
+        this.mask.show();
     },
-    
-    /**
-     * Marks the Operation as started
-     */
-    setStarted: function() {
-        this.started = true;
-        this.running = true;
+
+    _hideModalMask: function() {
+        if (this.mask && this.mask.dom.parentNode) {
+            Ext.get(this.mask.dom.parentNode).removeCls(Ext.baseCSSPrefix + 'body-masked');
+            this.mask.hide();
+        }
     },
-    
-    /**
-     * Marks the Operation as completed
-     */
-    setCompleted: function() {
-        this.complete = true;
-        this.running  = false;
+
+    _onMaskClick: function() {
+        if (this.front) {
+            this.front.focus();
+        }
     },
-    
-    /**
-     * Marks the Operation as successful
-     */
-    setSuccessful: function() {
-        this.success = true;
+
+    _onContainerResize: function() {
+        if (this.mask && this.mask.isVisible()) {
+            this.mask.setSize(Ext.get(this.mask.dom.parentNode).getViewSize(true));
+        }
     },
-    
+
     /**
-     * Marks the Operation as having experienced an exception. Can be supplied with an option error message/object.
-     * @param {Mixed} error Optional error string/object
+     * <p>Registers a floating {@link Ext.Component} with this ZIndexManager. This should not
+     * need to be called under normal circumstances. Floating Components (such as Windows, BoundLists and Menus) are automatically registered
+     * with a {@link Ext.Component#zIndexManager zIndexManager} at render time.</p>
+     * <p>Where this may be useful is moving Windows between two ZIndexManagers. For example,
+     * to bring the Ext.MessageBox dialog under the same manager as the Desktop's
+     * ZIndexManager in the desktop sample app:</p><code><pre>
+MyDesktop.getDesktop().getManager().register(Ext.MessageBox);
+</pre></code>
+     * @param {Ext.Component} comp The Component to register.
      */
-    setException: function(error) {
-        this.exception = true;
-        this.success = false;
-        this.running = false;
-        this.error = error;
+    register : function(comp) {
+        if (comp.zIndexManager) {
+            comp.zIndexManager.unregister(comp);
+        }
+        comp.zIndexManager = this;
+
+        this.list[comp.id] = comp;
+        this.zIndexStack.push(comp);
+        comp.on('hide', this._activateLast, this);
     },
-    
+
     /**
-     * Returns true if this Operation encountered an exception (see also {@link #getError})
-     * @return {Boolean} True if there was an exception
+     * <p>Unregisters a {@link Ext.Component} from this ZIndexManager. This should not
+     * need to be called. Components are automatically unregistered upon destruction.
+     * See {@link #register}.</p>
+     * @param {Ext.Component} comp The Component to unregister.
      */
-    hasException: function() {
-        return this.exception === true;
+    unregister : function(comp) {
+        delete comp.zIndexManager;
+        if (this.list && this.list[comp.id]) {
+            delete this.list[comp.id];
+            comp.un('hide', this._activateLast);
+            Ext.Array.remove(this.zIndexStack, comp);
+
+            // Destruction requires that the topmost visible floater be activated. Same as hiding.
+            this._activateLast(comp);
+        }
     },
-    
+
     /**
-     * Returns the error string or object that was set using {@link #setException}
-     * @return {Mixed} The error object
+     * Gets a registered Component by id.
+     * @param {String/Object} id The id of the Component or a {@link Ext.Component} instance
+     * @return {Ext.Component}
      */
-    getError: function() {
-        return this.error;
+    get : function(id) {
+        return typeof id == "object" ? id : this.list[id];
     },
-    
-    /**
-     * Returns an array of Ext.data.Model instances as set by the Proxy.
-     * @return {Array} Any loaded Records
+
+   /**
+     * Brings the specified Component to the front of any other active Components in this ZIndexManager.
+     * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
+     * @return {Boolean} True if the dialog was brought to the front, else false
+     * if it was already in front
      */
-    getRecords: function() {
-        var resultSet = this.getResultSet();
-        
-        return (resultSet === undefined ? this.records : resultSet.records);
+    bringToFront : function(comp) {
+        comp = this.get(comp);
+        if (comp !== this.front) {
+            Ext.Array.remove(this.zIndexStack, comp);
+            this.zIndexStack.push(comp);
+            this.assignZIndices();
+            return true;
+        }
+        if (comp.modal) {
+            this._showModalMask(comp);
+        }
+        return false;
     },
-    
+
     /**
-     * Returns the ResultSet object (if set by the Proxy). This object will contain the {@link Ext.data.Model model} instances
-     * as well as meta data such as number of instances fetched, number available etc
-     * @return {Ext.data.ResultSet} The ResultSet object
+     * Sends the specified Component to the back of other active Components in this ZIndexManager.
+     * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
+     * @return {Ext.Component} The Component
      */
-    getResultSet: function() {
-        return this.resultSet;
+    sendToBack : function(comp) {
+        comp = this.get(comp);
+        Ext.Array.remove(this.zIndexStack, comp);
+        this.zIndexStack.unshift(comp);
+        this.assignZIndices();
+        return comp;
     },
-    
+
     /**
-     * Returns true if the Operation has been started. Note that the Operation may have started AND completed,
-     * see {@link #isRunning} to test if the Operation is currently running.
-     * @return {Boolean} True if the Operation has started
+     * Hides all Components managed by this ZIndexManager.
      */
-    isStarted: function() {
-        return this.started === true;
+    hideAll : function() {
+        for (var id in this.list) {
+            if (this.list[id].isComponent && this.list[id].isVisible()) {
+                this.list[id].hide();
+            }
+        }
     },
-    
+
     /**
-     * Returns true if the Operation has been started but has not yet completed.
-     * @return {Boolean} True if the Operation is currently running
+     * @private
+     * Temporarily hides all currently visible managed Components. This is for when
+     * dragging a Window which may manage a set of floating descendants in its ZIndexManager;
+     * they should all be hidden just for the duration of the drag.
      */
-    isRunning: function() {
-        return this.running === true;
+    hide: function() {
+        var i = 0,
+            ln = this.zIndexStack.length,
+            comp;
+
+        this.tempHidden = [];
+        for (; i < ln; i++) {
+            comp = this.zIndexStack[i];
+            if (comp.isVisible()) {
+                this.tempHidden.push(comp);
+                comp.hide();
+            }
+        }
     },
-    
+
     /**
-     * Returns true if the Operation has been completed
-     * @return {Boolean} True if the Operation is complete
+     * @private
+     * Restores temporarily hidden managed Components to visibility.
      */
-    isComplete: function() {
-        return this.complete === true;
+    show: function() {
+        var i = 0,
+            ln = this.tempHidden.length,
+            comp,
+            x,
+            y;
+
+        for (; i < ln; i++) {
+            comp = this.tempHidden[i];
+            x = comp.x;
+            y = comp.y;
+            comp.show();
+            comp.setPosition(x, y);
+        }
+        delete this.tempHidden;
     },
-    
+
     /**
-     * Returns true if the Operation has completed and was successful
-     * @return {Boolean} True if successful
+     * Gets the currently-active Component in this ZIndexManager.
+     * @return {Ext.Component} The active Component
      */
-    wasSuccessful: function() {
-        return this.isComplete() && this.success === true;
+    getActive : function() {
+        return this.front;
     },
-    
+
     /**
-     * @private
-     * Associates this Operation with a Batch
-     * @param {Ext.data.Batch} batch The batch
+     * Returns zero or more Components in this ZIndexManager using the custom search function passed to this method.
+     * The function should accept a single {@link Ext.Component} reference as its only argument and should
+     * return true if the Component matches the search criteria, otherwise it should return false.
+     * @param {Function} fn The search function
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component being tested.
+     * that gets passed to the function if not specified)
+     * @return {Array} An array of zero or more matching windows
      */
-    setBatch: function(batch) {
-        this.batch = batch;
-    },
-    
-    /**
-     * Checks whether this operation should cause writing to occur.
-     * @return {Boolean} Whether the operation should cause a write to occur.
-     */
-    allowWrite: function() {
-        return this.action != 'read';
-    }
-});
-/**
- * @author Ed Spencer
- * @class Ext.data.validations
- * @extends Object
- * 
- * <p>This singleton contains a set of validation functions that can be used to validate any type
- * of data. They are most often used in {@link Ext.data.Model Models}, where they are automatically
- * set up and executed.</p>
- */
-Ext.define('Ext.data.validations', {
-    singleton: true,
-    
-    /**
-     * The default error message used when a presence validation fails
-     * @property presenceMessage
-     * @type String
-     */
-    presenceMessage: 'must be present',
-    
-    /**
-     * The default error message used when a length validation fails
-     * @property lengthMessage
-     * @type String
-     */
-    lengthMessage: 'is the wrong length',
-    
-    /**
-     * The default error message used when a format validation fails
-     * @property formatMessage
-     * @type Boolean
-     */
-    formatMessage: 'is the wrong format',
-    
-    /**
-     * The default error message used when an inclusion validation fails
-     * @property inclusionMessage
-     * @type String
-     */
-    inclusionMessage: 'is not included in the list of acceptable values',
-    
-    /**
-     * The default error message used when an exclusion validation fails
-     * @property exclusionMessage
-     * @type String
-     */
-    exclusionMessage: 'is not an acceptable value',
-    
-    /**
-     * Validates that the given value is present
-     * @param {Object} config Optional config object
-     * @param {Mixed} value The value to validate
-     * @return {Boolean} True if validation passed
-     */
-    presence: function(config, value) {
-        if (value === undefined) {
-            value = config;
+    getBy : function(fn, scope) {
+        var r = [],
+            i = 0,
+            len = this.zIndexStack.length,
+            comp;
+
+        for (; i < len; i++) {
+            comp = this.zIndexStack[i];
+            if (fn.call(scope||comp, comp) !== false) {
+                r.push(comp);
+            }
         }
-        
-        return !!value;
+        return r;
     },
-    
+
     /**
-     * Returns true if the given value is between the configured min and max values
-     * @param {Object} config Optional config object
-     * @param {String} value The value to validate
-     * @return {Boolean} True if the value passes validation
+     * Executes the specified function once for every Component in this ZIndexManager, passing each
+     * Component as the only parameter. Returning false from the function will stop the iteration.
+     * @param {Function} fn The function to execute for each item
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Component in the iteration.
      */
-    length: function(config, value) {
-        if (value === undefined) {
-            return false;
-        }
-        
-        var length = value.length,
-            min    = config.min,
-            max    = config.max;
-        
-        if ((min && length < min) || (max && length > max)) {
-            return false;
-        } else {
-            return true;
+    each : function(fn, scope) {
+        var comp;
+        for (var id in this.list) {
+            comp = this.list[id];
+            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
+                return;
+            }
         }
     },
-    
+
     /**
-     * Returns true if the given value passes validation against the configured {@link #matcher} regex
-     * @param {Object} config Optional config object
-     * @param {String} value The value to validate
-     * @return {Boolean} True if the value passes the format validation
+     * Executes the specified function once for every Component in this ZIndexManager, passing each
+     * Component as the only parameter. Returning false from the function will stop the iteration.
+     * The components are passed to the function starting at the bottom and proceeding to the top.
+     * @param {Function} fn The function to execute for each item
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
+     * is executed. Defaults to the current Component in the iteration.
      */
-    format: function(config, value) {
-        return !!(config.matcher && config.matcher.test(value));
+    eachBottomUp: function (fn, scope) {
+        var comp,
+            stack = this.zIndexStack,
+            i, n;
+
+        for (i = 0, n = stack.length ; i < n; i++) {
+            comp = stack[i];
+            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
+                return;
+            }
+        }
     },
-    
+
     /**
-     * Validates that the given value is present in the configured {@link #list}
-     * @param {String} value The value to validate
-     * @return {Boolean} True if the value is present in the list
+     * Executes the specified function once for every Component in this ZIndexManager, passing each
+     * Component as the only parameter. Returning false from the function will stop the iteration.
+     * The components are passed to the function starting at the top and proceeding to the bottom.
+     * @param {Function} fn The function to execute for each item
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
+     * is executed. Defaults to the current Component in the iteration.
      */
-    inclusion: function(config, value) {
-        return config.list && Ext.Array.indexOf(config.list,value) != -1;
+    eachTopDown: function (fn, scope) {
+        var comp,
+            stack = this.zIndexStack,
+            i;
+
+        for (i = stack.length ; i-- > 0; ) {
+            comp = stack[i];
+            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
+                return;
+            }
+        }
     },
-    
+
+    destroy: function() {
+        this.each(function(c) {
+            c.destroy();
+        });
+        delete this.zIndexStack;
+        delete this.list;
+        delete this.container;
+        delete this.targetEl;
+    }
+}, function() {
     /**
-     * Validates that the given value is present in the configured {@link #list}
-     * @param {Object} config Optional config object
-     * @param {String} value The value to validate
-     * @return {Boolean} True if the value is not present in the list
+     * @class Ext.WindowManager
+     * @extends Ext.ZIndexManager
+     * <p>The default global floating Component group that is available automatically.</p>
+     * <p>This manages instances of floating Components which were rendered programatically without
+     * being added to a {@link Ext.container.Container Container}, and for floating Components which were added into non-floating Containers.</p>
+     * <p><i>Floating</i> Containers create their own instance of ZIndexManager, and floating Components added at any depth below
+     * there are managed by that ZIndexManager.</p>
+     * @singleton
      */
-    exclusion: function(config, value) {
-        return config.list && Ext.Array.indexOf(config.list,value) == -1;
-    }
+    Ext.WindowManager = Ext.WindowMgr = new this();
 });
+
 /**
- * @author Ed Spencer
- * @class Ext.data.ResultSet
- * @extends Object
- * 
- * <p>Simple wrapper class that represents a set of records returned by a Proxy.</p>
+ * @private
+ * Base class for Box Layout overflow handlers. These specialized classes are invoked when a Box Layout
+ * (either an HBox or a VBox) has child items that are either too wide (for HBox) or too tall (for VBox)
+ * for its container.
  */
-Ext.define('Ext.data.ResultSet', {
-    /**
-     * @cfg {Boolean} loaded
-     * True if the records have already been loaded. This is only meaningful when dealing with
-     * SQL-backed proxies
-     */
-    loaded: true,
-    
-    /**
-     * @cfg {Number} count
-     * The number of records in this ResultSet. Note that total may differ from this number
-     */
-    count: 0,
-    
-    /**
-     * @cfg {Number} total
-     * The total number of records reported by the data source. This ResultSet may form a subset of
-     * those records (see count)
-     */
-    total: 0,
+Ext.define('Ext.layout.container.boxOverflow.None', {
     
-    /**
-     * @cfg {Boolean} success
-     * True if the ResultSet loaded successfully, false if any errors were encountered
-     */
-    success: false,
+    alternateClassName: 'Ext.layout.boxOverflow.None',
     
-    /**
-     * @cfg {Array} records The array of record instances. Required
-     */
+    constructor: function(layout, config) {
+        this.layout = layout;
+        Ext.apply(this, config || {});
+    },
 
-    /**
-     * Creates the resultSet
-     * @param {Object} config (optional) Config object.
-     */
-    constructor: function(config) {
-        Ext.apply(this, config);
-        
-        /**
-         * DEPRECATED - will be removed in Ext JS 5.0. This is just a copy of this.total - use that instead
-         * @property totalRecords
-         * @type Mixed
-         */
-        this.totalRecords = this.total;
-        
-        if (config.count === undefined) {
-            this.count = this.records.length;
-        }
-    }
-});
-/**
- * @author Ed Spencer
- * @class Ext.data.writer.Writer
- * @extends Object
- * 
- * <p>Base Writer class used by most subclasses of {@link Ext.data.proxy.Server}. This class is
- * responsible for taking a set of {@link Ext.data.Operation} objects and a {@link Ext.data.Request}
- * object and modifying that request based on the Operations.</p>
- * 
- * <p>For example a Ext.data.writer.Json would format the Operations and their {@link Ext.data.Model} 
- * instances based on the config options passed to the JsonWriter's constructor.</p>
- * 
- * <p>Writers are not needed for any kind of local storage - whether via a
- * {@link Ext.data.proxy.WebStorage Web Storage proxy} (see {@link Ext.data.proxy.LocalStorage localStorage}
- * and {@link Ext.data.proxy.SessionStorage sessionStorage}) or just in memory via a
- * {@link Ext.data.proxy.Memory MemoryProxy}.</p>
- */
-Ext.define('Ext.data.writer.Writer', {
-    alias: 'writer.base',
-    alternateClassName: ['Ext.data.DataWriter', 'Ext.data.Writer'],
+    handleOverflow: Ext.emptyFn,
+
+    clearOverflow: Ext.emptyFn,
     
+    onRemove: Ext.emptyFn,
+
     /**
-     * @cfg {Boolean} writeAllFields True to write all fields from the record to the server. If set to false it
-     * will only send the fields that were modified. Defaults to <tt>true</tt>. Note that any fields that have
-     * {@link Ext.data.Field#persist} set to false will still be ignored.
+     * @private
+     * Normalizes an item reference, string id or numerical index into a reference to the item
+     * @param {Ext.Component/String/Number} item The item reference, id or index
+     * @return {Ext.Component} The item
      */
-    writeAllFields: true,
+    getItem: function(item) {
+        return this.layout.owner.getComponent(item);
+    },
     
-    /**
-     * @cfg {String} nameProperty This property is used to read the key for each value that will be sent to the server.
-     * For example:
-     * <pre><code>
-Ext.define('Person', {
-    extend: 'Ext.data.Model',
-    fields: [{
-        name: 'first',
-        mapping: 'firstName'
-    }, {
-        name: 'last',
-        mapping: 'lastName'
-    }, {
-        name: 'age'
-    }]
+    onRemove: Ext.emptyFn
 });
-new Ext.data.writer.Writer({
-    writeAllFields: true,
-    nameProperty: 'mapping'
+/**
+ * @class Ext.util.KeyMap
+ * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
+ * The constructor accepts the same config object as defined by {@link #addBinding}.
+ * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
+ * combination it will call the function with this signature (if the match is a multi-key
+ * combination the callback will still be called only once): (String key, Ext.EventObject e)
+ * A KeyMap can also handle a string representation of keys. By default KeyMap starts enabled.<br />
+ * Usage:
+ <pre><code>
+// map one key by key code
+var map = new Ext.util.KeyMap("my-element", {
+    key: 13, // or Ext.EventObject.ENTER
+    fn: myHandler,
+    scope: myObject
 });
 
-// This will be sent to the server
-{
-    firstName: 'first name value',
-    lastName: 'last name value',
-    age: 1
-}
-
-     * </code></pre>
-     * Defaults to <tt>name</tt>. If the value is not present, the field name will always be used.
-     */
-    nameProperty: 'name',
+// map multiple keys to one action by string
+var map = new Ext.util.KeyMap("my-element", {
+    key: "a\r\n\t",
+    fn: myHandler,
+    scope: myObject
+});
 
-    /**
-     * Creates new Writer.
-     * @param {Object} config (optional) Config object.
-     */
-    constructor: function(config) {
-        Ext.apply(this, config);
-    },
+// map multiple keys to multiple actions by strings and array of codes
+var map = new Ext.util.KeyMap("my-element", [
+    {
+        key: [10,13],
+        fn: function(){ alert("Return was pressed"); }
+    }, {
+        key: "abc",
+        fn: function(){ alert('a, b or c was pressed'); }
+    }, {
+        key: "\t",
+        ctrl:true,
+        shift:true,
+        fn: function(){ alert('Control + shift + tab was pressed.'); }
+    }
+]);
+</code></pre>
+ */
+Ext.define('Ext.util.KeyMap', {
+    alternateClassName: 'Ext.KeyMap',
 
     /**
-     * Prepares a Proxy's Ext.data.Request object
-     * @param {Ext.data.Request} request The request object
-     * @return {Ext.data.Request} The modified request object
+     * Creates new KeyMap.
+     * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
+     * @param {Object} binding The binding (see {@link #addBinding})
+     * @param {String} [eventName="keydown"] The event to bind to
      */
-    write: function(request) {
-        var operation = request.operation,
-            records   = operation.records || [],
-            len       = records.length,
-            i         = 0,
-            data      = [];
+    constructor: function(el, binding, eventName){
+        var me = this;
 
-        for (; i < len; i++) {
-            data.push(this.getRecordData(records[i]));
+        Ext.apply(me, {
+            el: Ext.get(el),
+            eventName: eventName || me.eventName,
+            bindings: []
+        });
+        if (binding) {
+            me.addBinding(binding);
         }
-        return this.writeRecords(request, data);
+        me.enable();
     },
 
-    /**
-     * Formats the data for each record before sending it to the server. This
-     * method should be overridden to format the data in a way that differs from the default.
-     * @param {Object} record The record that we are writing to the server.
-     * @return {Object} An object literal of name/value keys to be written to the server.
-     * By default this method returns the data property on the record.
-     */
-    getRecordData: function(record) {
-        var isPhantom = record.phantom === true,
-            writeAll = this.writeAllFields || isPhantom,
-            nameProperty = this.nameProperty,
-            fields = record.fields,
-            data = {},
-            changes,
-            name,
-            field,
-            key;
-        
-        if (writeAll) {
-            fields.each(function(field){
-                if (field.persist) {
-                    name = field[nameProperty] || field.name;
-                    data[name] = record.get(field.name);
-                }
-            });
-        } else {
-            // Only write the changes
-            changes = record.getChanges();
-            for (key in changes) {
-                if (changes.hasOwnProperty(key)) {
-                    field = fields.get(key);
-                    name = field[nameProperty] || field.name;
-                    data[name] = changes[key];
-                }
-            }
-            if (!isPhantom) {
-                // always include the id for non phantoms
-                data[record.idProperty] = record.getId();
-            }
-        }
-        return data;
-    }
-});
-
-/**
- * @class Ext.util.Floating
- * A mixin to add floating capability to a Component
- */
-Ext.define('Ext.util.Floating', {
-
-    uses: ['Ext.Layer', 'Ext.window.Window'],
+    eventName: 'keydown',
 
     /**
-     * @cfg {Boolean} focusOnToFront
-     * Specifies whether the floated component should be automatically {@link #focus focused} when it is
-     * {@link #toFront brought to the front}. Defaults to true.
-     */
-    focusOnToFront: true,
+     * Add a new binding to this KeyMap. The following config object properties are supported:
+     * <pre>
+Property            Type             Description
+----------          ---------------  ----------------------------------------------------------------------
+key                 String/Array     A single keycode or an array of keycodes to handle
+shift               Boolean          True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
+ctrl                Boolean          True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
+alt                 Boolean          True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
+handler             Function         The function to call when KeyMap finds the expected key combination
+fn                  Function         Alias of handler (for backwards-compatibility)
+scope               Object           The scope of the callback function
+defaultEventAction  String           A default action to apply to the event. Possible values are: stopEvent, stopPropagation, preventDefault. If no value is set no action is performed.
+</pre>
+     *
+     * Usage:
+     * <pre><code>
+// Create a KeyMap
+var map = new Ext.util.KeyMap(document, {
+    key: Ext.EventObject.ENTER,
+    fn: handleKey,
+    scope: this
+});
 
-    /**
-     * @cfg {String/Boolean} shadow Specifies whether the floating component should be given a shadow. Set to
-     * <tt>true</tt> to automatically create an {@link Ext.Shadow}, or a string indicating the
-     * shadow's display {@link Ext.Shadow#mode}. Set to <tt>false</tt> to disable the shadow.
-     * (Defaults to <tt>'sides'</tt>.)
+//Add a new binding to the existing KeyMap later
+map.addBinding({
+    key: 'abc',
+    shift: true,
+    fn: handleKey,
+    scope: this
+});
+</code></pre>
+     * @param {Object/Object[]} binding A single KeyMap config or an array of configs
      */
-    shadow: 'sides',
-
-    constructor: function(config) {
-        this.floating = true;
-        this.el = Ext.create('Ext.Layer', Ext.apply({}, config, {
-            hideMode: this.hideMode,
-            hidden: this.hidden,
-            shadow: Ext.isDefined(this.shadow) ? this.shadow : 'sides',
-            shadowOffset: this.shadowOffset,
-            constrain: false,
-            shim: this.shim === false ? false : undefined
-        }), this.el);
-    },
-
-    onFloatRender: function() {
-        var me = this;
-        me.zIndexParent = me.getZIndexParent();
-        me.setFloatParent(me.ownerCt);
-        delete me.ownerCt;
-
-        if (me.zIndexParent) {
-            me.zIndexParent.registerFloatingItem(me);
-        } else {
-            Ext.WindowManager.register(me);
+    addBinding : function(binding){
+        if (Ext.isArray(binding)) {
+            Ext.each(binding, this.addBinding, this);
+            return;
         }
-    },
-
-    setFloatParent: function(floatParent) {
-        var me = this;
 
-        // Remove listeners from previous floatParent
-        if (me.floatParent) {
-            me.mun(me.floatParent, {
-                hide: me.onFloatParentHide,
-                show: me.onFloatParentShow,
-                scope: me
-            });
-        }
+        var keyCode = binding.key,
+            processed = false,
+            key,
+            keys,
+            keyString,
+            i,
+            len;
 
-        me.floatParent = floatParent;
+        if (Ext.isString(keyCode)) {
+            keys = [];
+            keyString = keyCode.toUpperCase();
 
-        // Floating Components as children of Containers must hide when their parent hides.
-        if (floatParent) {
-            me.mon(me.floatParent, {
-                hide: me.onFloatParentHide,
-                show: me.onFloatParentShow,
-                scope: me
-            });
+            for (i = 0, len = keyString.length; i < len; ++i){
+                keys.push(keyString.charCodeAt(i));
+            }
+            keyCode = keys;
+            processed = true;
         }
 
-        // If a floating Component is configured to be constrained, but has no configured
-        // constrainTo setting, set its constrainTo to be it's ownerCt before rendering.
-        if ((me.constrain || me.constrainHeader) && !me.constrainTo) {
-            me.constrainTo = floatParent ? floatParent.getTargetEl() : me.container;
+        if (!Ext.isArray(keyCode)) {
+            keyCode = [keyCode];
         }
-    },
 
-    onFloatParentHide: function() {
-        if (this.hideOnParentHide !== false) {
-            this.showOnParentShow = this.isVisible();
-            this.hide();
+        if (!processed) {
+            for (i = 0, len = keyCode.length; i < len; ++i) {
+                key = keyCode[i];
+                if (Ext.isString(key)) {
+                    keyCode[i] = key.toUpperCase().charCodeAt(0);
+                }
+            }
         }
-    },
 
-    onFloatParentShow: function() {
-        if (this.showOnParentShow) {
-            delete this.showOnParentShow;
-            this.show();
-        }
+        this.bindings.push(Ext.apply({
+            keyCode: keyCode
+        }, binding));
     },
 
     /**
+     * Process any keydown events on the element
      * @private
-     * <p>Finds the ancestor Container responsible for allocating zIndexes for the passed Component.</p>
-     * <p>That will be the outermost floating Container (a Container which has no ownerCt and has floating:true).</p>
-     * <p>If we have no ancestors, or we walk all the way up to the document body, there's no zIndexParent,
-     * and the global Ext.WindowManager will be used.</p>
+     * @param {Ext.EventObject} event
      */
-    getZIndexParent: function() {
-        var p = this.ownerCt,
-            c;
+    handleKeyDown: function(event) {
+        if (this.enabled) { //just in case
+            var bindings = this.bindings,
+                i = 0,
+                len = bindings.length;
 
-        if (p) {
-            while (p) {
-                c = p;
-                p = p.ownerCt;
-            }
-            if (c.floating) {
-                return c;
+            event = this.processEvent(event);
+            for(; i < len; ++i){
+                this.processBinding(bindings[i], event);
             }
         }
     },
 
-    // private
-    // z-index is managed by the zIndexManager and may be overwritten at any time.
-    // Returns the next z-index to be used.
-    // If this is a Container, then it will have rebased any managed floating Components,
-    // and so the next available z-index will be approximately 10000 above that.
-    setZIndex: function(index) {
-        var me = this;
-        this.el.setZIndex(index);
-
-        // Next item goes 10 above;
-        index += 10;
-
-        // When a Container with floating items has its z-index set, it rebases any floating items it is managing.
-        // The returned value is a round number approximately 10000 above the last z-index used.
-        if (me.floatingItems) {
-            index = Math.floor(me.floatingItems.setBase(index) / 100) * 100 + 10000;
-        }
-        return index;
+    /**
+     * Ugly hack to allow this class to be tested. Currently WebKit gives
+     * no way to raise a key event properly with both
+     * a) A keycode
+     * b) The alt/ctrl/shift modifiers
+     * So we have to simulate them here. Yuk!
+     * This is a stub method intended to be overridden by tests.
+     * More info: https://bugs.webkit.org/show_bug.cgi?id=16735
+     * @private
+     */
+    processEvent: function(event){
+        return event;
     },
 
     /**
-     * <p>Moves this floating Component into a constrain region.</p>
-     * <p>By default, this Component is constrained to be within the container it was added to, or the element
-     * it was rendered to.</p>
-     * <p>An alternative constraint may be passed.</p>
-     * @param {Mixed} constrainTo Optional. The Element or {@link Ext.util.Region Region} into which this Component is to be constrained.
+     * Process a particular binding and fire the handler if necessary.
+     * @private
+     * @param {Object} binding The binding information
+     * @param {Ext.EventObject} event
      */
-    doConstrain: function(constrainTo) {
-        var me = this,
-            vector = me.getConstrainVector(constrainTo),
-            xy;
+    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);
 
-        if (vector) {
-            xy = me.getPosition();
-            xy[0] += vector[0];
-            xy[1] += vector[1];
-            me.setPosition(xy);
+
+            for (i = 0, len = keyCode.length; i < len; ++i) {
+                if (key === keyCode[i]) {
+                    if (handler.call(scope, key, event) !== true && defaultEventAction) {
+                        keydownEvent[defaultEventAction]();
+                    }
+                    break;
+                }
+            }
         }
     },
 
-
     /**
-     * Gets the x/y offsets to constrain this float
+     * Check if the modifiers on the event match those on the binding
      * @private
-     * @param {Mixed} constrainTo Optional. The Element or {@link Ext.util.Region Region} into which this Component is to be constrained.
-     * @return {Array} The x/y constraints
+     * @param {Object} binding
+     * @param {Ext.EventObject} event
+     * @return {Boolean} True if the event matches the binding
      */
-    getConstrainVector: function(constrainTo){
-        var me = this,
-            el;
+    checkModifiers: function(binding, e){
+        var keys = ['shift', 'ctrl', 'alt'],
+            i = 0,
+            len = keys.length,
+            val, key;
 
-        if (me.constrain || me.constrainHeader) {
-            el = me.constrainHeader ? me.header.el : me.el;
-            constrainTo = constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container;
-            return el.getConstrainVector(constrainTo);
+        for (; i < len; ++i){
+            key = keys[i];
+            val = binding[key];
+            if (!(val === undefined || (val === e[key + 'Key']))) {
+                return false;
+            }
         }
+        return true;
     },
 
     /**
-     * Aligns this floating Component to the specified element
-     * @param {Mixed} element The element or {@link Ext.Component} to align to. If passing a component, it must
-     * be a omponent instance. If a string id is passed, it will be used as an element id.
-     * @param {String} position (optional, defaults to "tl-bl?") The position to align to (see {@link Ext.core.Element#alignTo} for more details).
-     * @param {Array} offsets (optional) Offset the positioning by [x, y]
-     * @return {Component} this
+     * Shorthand for adding a single key listener
+     * @param {Number/Number[]/Object} key Either the numeric key code, array of key codes or an object with the
+     * following options:
+     * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
      */
-    alignTo: function(element, position, offsets) {
-        if (element.isComponent) {
-            element = element.getEl();
+    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;
         }
-        var xy = this.el.getAlignToXY(element, position, offsets);
-        this.setPagePosition(xy);
-        return this;
+        this.addBinding({
+            key: keyCode,
+            shift: shift,
+            ctrl: ctrl,
+            alt: alt,
+            fn: fn,
+            scope: scope
+        });
     },
 
     /**
-     * <p>Brings this floating Component to the front of any other visible, floating Components managed by the same {@link Ext.ZIndexManager ZIndexManager}</p>
-     * <p>If this Component is modal, inserts the modal mask just below this Component in the z-index stack.</p>
-     * @param {Boolean} preventFocus (optional) Specify <code>true</code> to prevent the Component from being focused.
-     * @return {Component} this
+     * Returns true if this KeyMap is enabled
+     * @return {Boolean}
      */
-    toFront: function(preventFocus) {
-        var me = this;
-
-        // Find the floating Component which provides the base for this Component's zIndexing.
-        // That must move to front to then be able to rebase its zIndex stack and move this to the front
-        if (me.zIndexParent) {
-            me.zIndexParent.toFront(true);
-        }
-        if (me.zIndexManager.bringToFront(me)) {
-            if (!Ext.isDefined(preventFocus)) {
-                preventFocus = !me.focusOnToFront;
-            }
-            if (!preventFocus) {
-                // Kick off a delayed focus request.
-                // If another floating Component is toFronted before the delay expires
-                // this will not receive focus.
-                me.focus(false, true);
-            }
-        }
-        return me;
+    isEnabled : function(){
+        return this.enabled;
     },
 
     /**
-     * <p>This method is called internally by {@link Ext.ZIndexManager} to signal that a floating
-     * Component has either been moved to the top of its zIndex stack, or pushed from the top of its zIndex stack.</p>
-     * <p>If a <i>Window</i> is superceded by another Window, deactivating it hides its shadow.</p>
-     * <p>This method also fires the {@link #activate} or {@link #deactivate} event depending on which action occurred.</p>
-     * @param {Boolean} active True to activate the Component, false to deactivate it (defaults to false)
-     * @param {Component} newActive The newly active Component which is taking over topmost zIndex position.
+     * Enables this KeyMap
      */
-    setActive: function(active, newActive) {
-        if (active) {
-            if ((this instanceof Ext.window.Window) && !this.maximized) {
-                this.el.enableShadow(true);
-            }
-            this.fireEvent('activate', this);
-        } else {
-            // Only the *Windows* in a zIndex stack share a shadow. All other types of floaters
-            // can keep their shadows all the time
-            if ((this instanceof Ext.window.Window) && (newActive instanceof Ext.window.Window)) {
-                this.el.disableShadow();
-            }
-            this.fireEvent('deactivate', this);
+    enable: function(){
+        var me = this;
+        
+        if (!me.enabled) {
+            me.el.on(me.eventName, me.handleKeyDown, me);
+            me.enabled = true;
         }
     },
 
     /**
-     * Sends this Component to the back of (lower z-index than) any other visible windows
-     * @return {Component} this
+     * Disable this KeyMap
      */
-    toBack: function() {
-        this.zIndexManager.sendToBack(this);
-        return this;
+    disable: function(){
+        var me = this;
+        
+        if (me.enabled) {
+            me.el.removeListener(me.eventName, me.handleKeyDown, me);
+            me.enabled = false;
+        }
     },
 
     /**
-     * Center this Component in its container.
-     * @return {Component} this
+     * Convenience function for setting disabled/enabled by boolean.
+     * @param {Boolean} disabled
      */
-    center: function() {
-        var xy = this.el.getAlignToXY(this.container, 'c-c');
-        this.setPagePosition(xy);
-        return this;
-    },
-
-    // private
-    syncShadow : function(){
-        if (this.floating) {
-            this.el.sync(true);
+    setDisabled : function(disabled){
+        if (disabled) {
+            this.disable();
+        } else {
+            this.enable();
         }
     },
 
-    // private
-    fitContainer: function() {
-        var parent = this.floatParent,
-            container = parent ? parent.getTargetEl() : this.container,
-            size = container.getViewSize(false);
+    /**
+     * Destroys the KeyMap instance and removes all handlers.
+     * @param {Boolean} removeEl True to also remove the attached element
+     */
+    destroy: function(removeEl){
+        var me = this;
 
-        this.setSize(size);
+        me.bindings = [];
+        me.disable();
+        if (removeEl === true) {
+            me.el.remove();
+        }
+        delete me.el;
     }
 });
 /**
- * @class Ext.layout.container.AbstractContainer
- * @extends Ext.layout.Layout
- * Please refer to sub classes documentation
+ * @class Ext.util.ClickRepeater
+ * @extends Ext.util.Observable
+ *
+ * A wrapper class which can be applied to any element. Fires a "click" event while the
+ * mouse is pressed. The interval between firings may be specified in the config but
+ * defaults to 20 milliseconds.
+ *
+ * Optionally, a CSS class may be applied to the element during the time it is pressed.
+ *
  */
+Ext.define('Ext.util.ClickRepeater', {
+    extend: 'Ext.util.Observable',
 
-Ext.define('Ext.layout.container.AbstractContainer', {
+    /**
+     * Creates new ClickRepeater.
+     * @param {String/HTMLElement/Ext.Element} el The element or its ID to listen on
+     * @param {Object} config (optional) Config object.
+     */
+    constructor : function(el, config){
+        this.el = Ext.get(el);
+        this.el.unselectable();
 
-    /* Begin Definitions */
+        Ext.apply(this, config);
 
-    extend: 'Ext.layout.Layout',
+        this.addEvents(
+        /**
+         * @event mousedown
+         * Fires when the mouse button is depressed.
+         * @param {Ext.util.ClickRepeater} this
+         * @param {Ext.EventObject} e
+         */
+        "mousedown",
+        /**
+         * @event click
+         * Fires on a specified interval during the time the element is pressed.
+         * @param {Ext.util.ClickRepeater} this
+         * @param {Ext.EventObject} e
+         */
+        "click",
+        /**
+         * @event mouseup
+         * Fires when the mouse key is released.
+         * @param {Ext.util.ClickRepeater} this
+         * @param {Ext.EventObject} e
+         */
+        "mouseup"
+        );
 
-    /* End Definitions */
+        if(!this.disabled){
+            this.disabled = true;
+            this.enable();
+        }
 
-    type: 'container',
+        // allow inline handler
+        if(this.handler){
+            this.on("click", this.handler,  this.scope || this);
+        }
+
+        this.callParent();
+    },
 
     /**
-     * @cfg {Boolean} bindToOwnerCtComponent
-     * Flag to notify the ownerCt Component on afterLayout of a change
+     * @cfg {String/HTMLElement/Ext.Element} el The element to act as a button.
      */
-    bindToOwnerCtComponent: false,
 
     /**
-     * @cfg {Boolean} bindToOwnerCtContainer
-     * Flag to notify the ownerCt Container on afterLayout of a change
+     * @cfg {String} pressedCls A CSS class name to be applied to the element while pressed.
      */
-    bindToOwnerCtContainer: false,
 
     /**
-     * @cfg {String} itemCls
-     * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
-     * customized styles to the container or any of its children using standard CSS rules. See
-     * {@link Ext.Component}.{@link Ext.Component#ctCls ctCls} also.</p>
-     * </p>
+     * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
+     * "interval" and "delay" are ignored.
      */
 
     /**
-    * Set the size of an item within the Container.  We should always use setCalculatedSize.
-    * @private
-    */
-    setItemSize: function(item, width, height) {
-        if (Ext.isObject(width)) {
-            height = width.height;
-            width = width.width;
-        }
-        item.setCalculatedSize(width, height, this.owner);
-    },
+     * @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.
+     */
+    interval : 20,
 
     /**
-     * <p>Returns an array of child components either for a render phase (Performed in the beforeLayout method of the layout's
-     * base class), or the layout phase (onLayout).</p>
-     * @return {Array} of child components
+     * @cfg {Number} delay The initial delay before the repeating event begins firing.
+     * Similar to an autorepeat key delay.
      */
-    getLayoutItems: function() {
-        return this.owner && this.owner.items && this.owner.items.items || [];
-    },
+    delay: 250,
 
-    afterLayout: function() {
-        this.owner.afterLayout(this);
-    },
     /**
-     * Returns the owner component's resize element.
-     * @return {Ext.core.Element}
+     * @cfg {Boolean} preventDefault True to prevent the default click event
      */
-     getTarget: function() {
-         return this.owner.getTargetEl();
-     },
+    preventDefault : true,
     /**
-     * <p>Returns the element into which rendering must take place. Defaults to the owner Container's {@link Ext.AbstractComponent#targetEl}.</p>
-     * May be overridden in layout managers which implement an inner element.
-     * @return {Ext.core.Element}
+     * @cfg {Boolean} stopDefault True to stop the default click event
      */
-     getRenderTarget: function() {
-         return this.owner.getTargetEl();
-     }
-});
-
-/**
- * @class Ext.ZIndexManager
- * <p>A class that manages a group of {@link Ext.Component#floating} Components and provides z-order management,
- * and Component activation behavior, including masking below the active (topmost) Component.</p>
- * <p>{@link Ext.Component#floating Floating} Components which are rendered directly into the document (Such as {@link Ext.window.Window Window}s which are
- * {@link Ext.Component#show show}n are managed by a {@link Ext.WindowManager global instance}.</p>
- * <p>{@link Ext.Component#floating Floating} Components which are descendants of {@link Ext.Component#floating floating} <i>Containers</i>
- * (For example a {Ext.view.BoundList BoundList} within an {@link Ext.window.Window Window}, or a {@link Ext.menu.Menu Menu}),
- * are managed by a ZIndexManager owned by that floating Container. So ComboBox dropdowns within Windows will have managed z-indices
- * guaranteed to be correct, relative to the Window.</p>
- */
-Ext.define('Ext.ZIndexManager', {
-
-    alternateClassName: 'Ext.WindowGroup',
-
-    statics: {
-        zBase : 9000
-    },
-
-    constructor: function(container) {
-        var me = this;
-
-        me.list = {};
-        me.zIndexStack = [];
-        me.front = null;
+    stopDefault : false,
 
-        if (container) {
+    timer : 0,
 
-            // This is the ZIndexManager for an Ext.container.Container, base its zseed on the zIndex of the Container's element
-            if (container.isContainer) {
-                container.on('resize', me._onContainerResize, me);
-                me.zseed = Ext.Number.from(container.getEl().getStyle('zIndex'), me.getNextZSeed());
-                // The containing element we will be dealing with (eg masking) is the content target
-                me.targetEl = container.getTargetEl();
-                me.container = container;
+    /**
+     * Enables the repeater and allows events to fire.
+     */
+    enable: function(){
+        if(this.disabled){
+            this.el.on('mousedown', this.handleMouseDown, this);
+            if (Ext.isIE){
+                this.el.on('dblclick', this.handleDblClick, this);
             }
-            // This is the ZIndexManager for a DOM element
-            else {
-                Ext.EventManager.onWindowResize(me._onContainerResize, me);
-                me.zseed = me.getNextZSeed();
-                me.targetEl = Ext.get(container);
+            if(this.preventDefault || this.stopDefault){
+                this.el.on('click', this.eventOptions, this);
             }
         }
-        // No container passed means we are the global WindowManager. Our target is the doc body.
-        // DOM must be ready to collect that ref.
-        else {
-            Ext.EventManager.onWindowResize(me._onContainerResize, me);
-            me.zseed = me.getNextZSeed();
-            Ext.onDocumentReady(function() {
-                me.targetEl = Ext.getBody();
-            });
+        this.disabled = false;
+    },
+
+    /**
+     * Disables the repeater and stops events from firing.
+     */
+    disable: function(/* private */ 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;
     },
 
-    getNextZSeed: function() {
-        return (Ext.ZIndexManager.zBase += 10000);
+    /**
+     * Convenience function for setting disabled/enabled by boolean.
+     * @param {Boolean} disabled
+     */
+    setDisabled: function(disabled){
+        this[disabled ? 'disable' : 'enable']();
     },
 
-    setBase: function(baseZIndex) {
-        this.zseed = baseZIndex;
-        return this.assignZIndices();
+    eventOptions: function(e){
+        if(this.preventDefault){
+            e.preventDefault();
+        }
+        if(this.stopDefault){
+            e.stopEvent();
+        }
     },
 
     // private
-    assignZIndices: function() {
-        var a = this.zIndexStack,
-            len = a.length,
-            i = 0,
-            zIndex = this.zseed,
-            comp;
+    destroy : function() {
+        this.disable(true);
+        Ext.destroy(this.el);
+        this.clearListeners();
+    },
 
-        for (; i < len; i++) {
-            comp = a[i];
-            if (comp && !comp.hidden) {
+    handleDblClick : function(e){
+        clearTimeout(this.timer);
+        this.el.blur();
 
-                // Setting the zIndex of a Component returns the topmost zIndex consumed by
-                // that Component.
-                // If it's just a plain floating Component such as a BoundList, then the
-                // return value is the passed value plus 10, ready for the next item.
-                // If a floating *Container* has its zIndex set, it re-orders its managed
-                // floating children, starting from that new base, and returns a value 10000 above
-                // the highest zIndex which it allocates.
-                zIndex = comp.setZIndex(zIndex);
-            }
-        }
-        this._activateLast();
-        return zIndex;
+        this.fireEvent("mousedown", this, e);
+        this.fireEvent("click", this, e);
     },
 
     // private
-    _setActiveChild: function(comp) {
-        if (comp != this.front) {
-
-            if (this.front) {
-                this.front.setActive(false, comp);
-            }
-            this.front = comp;
-            if (comp) {
-                comp.setActive(true);
-                if (comp.modal) {
-                    this._showModalMask(comp.el.getStyle('zIndex') - 4);
-                }
-            }
+    handleMouseDown : function(e){
+        clearTimeout(this.timer);
+        this.el.blur();
+        if(this.pressedCls){
+            this.el.addCls(this.pressedCls);
         }
-    },
+        this.mousedownTime = new Date();
 
-    // private
-    _activateLast: function(justHidden) {
-        var comp,
-            lastActivated = false,
-            i;
+        Ext.getDoc().on("mouseup", this.handleMouseUp, this);
+        this.el.on("mouseout", this.handleMouseOut, this);
 
-        // Go down through the z-index stack.
-        // Activate the next visible one down.
-        // Keep going down to find the next visible modal one to shift the modal mask down under
-        for (i = this.zIndexStack.length-1; i >= 0; --i) {
-            comp = this.zIndexStack[i];
-            if (!comp.hidden) {
-                if (!lastActivated) {
-                    this._setActiveChild(comp);
-                    lastActivated = true;
-                }
+        this.fireEvent("mousedown", this, e);
+        this.fireEvent("click", this, e);
 
-                // Move any modal mask down to just under the next modal floater down the stack
-                if (comp.modal) {
-                    this._showModalMask(comp.el.getStyle('zIndex') - 4);
-                    return;
-                }
-            }
+        // Do not honor delay or interval if acceleration wanted.
+        if (this.accelerate) {
+            this.delay = 400;
         }
 
-        // none to activate, so there must be no modal mask.
-        // And clear the currently active property
-        this._hideModalMask();
-        if (!lastActivated) {
-            this._setActiveChild(null);
-        }
+        // Re-wrap the event object in a non-shared object, so it doesn't lose its context if
+        // the global shared EventObject gets a new Event put into it before the timer fires.
+        e = new Ext.EventObjectImpl(e);
+
+        this.timer =  Ext.defer(this.click, this.delay || this.interval, this, [e]);
     },
 
-    _showModalMask: function(zIndex) {
-        if (!this.mask) {
-            this.mask = this.targetEl.createChild({
-                cls: Ext.baseCSSPrefix + 'mask'
-            });
-            this.mask.setVisibilityMode(Ext.core.Element.DISPLAY);
-            this.mask.on('click', this._onMaskClick, this);
-        }
-        Ext.getBody().addCls(Ext.baseCSSPrefix + 'body-masked');
-        this.mask.setSize(this.targetEl.getViewSize(true));
-        this.mask.setStyle('zIndex', zIndex);
-        this.mask.show();
+    // private
+    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]);
     },
 
-    _hideModalMask: function() {
-        if (this.mask) {
-            Ext.getBody().removeCls(Ext.baseCSSPrefix + 'body-masked');
-            this.mask.hide();
-        }
+    easeOutExpo : function (t, b, c, d) {
+        return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
     },
 
-    _onMaskClick: function() {
-        if (this.front) {
-            this.front.focus();
+    // private
+    handleMouseOut : function(){
+        clearTimeout(this.timer);
+        if(this.pressedCls){
+            this.el.removeCls(this.pressedCls);
         }
+        this.el.on("mouseover", this.handleMouseReturn, this);
     },
 
-    _onContainerResize: function() {
-        if (this.mask && this.mask.isVisible()) {
-            this.mask.setSize(this.targetEl.getViewSize(true));
+    // private
+    handleMouseReturn : function(){
+        this.el.un("mouseover", this.handleMouseReturn, this);
+        if(this.pressedCls){
+            this.el.addCls(this.pressedCls);
         }
+        this.click();
     },
 
-    /**
-     * <p>Registers a floating {@link Ext.Component} with this ZIndexManager. This should not
-     * need to be called under normal circumstances. Floating Components (such as Windows, BoundLists and Menus) are automatically registered
-     * with a {@link Ext.Component#zIndexManager zIndexManager} at render time.</p>
-     * <p>Where this may be useful is moving Windows between two ZIndexManagers. For example,
-     * to bring the Ext.MessageBox dialog under the same manager as the Desktop's
-     * ZIndexManager in the desktop sample app:</p><code><pre>
-MyDesktop.getDesktop().getManager().register(Ext.MessageBox);
-</pre></code>
-     * @param {Component} comp The Component to register.
-     */
-    register : function(comp) {
-        if (comp.zIndexManager) {
-            comp.zIndexManager.unregister(comp);
+    // private
+    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);
         }
-        comp.zIndexManager = this;
+        this.fireEvent("mouseup", this, e);
+    }
+});
 
-        this.list[comp.id] = comp;
-        this.zIndexStack.push(comp);
-        comp.on('hide', this._activateLast, this);
-    },
+/**
+ * @class Ext.layout.component.Component
+ * @extends Ext.layout.Layout
+ *
+ * This class is intended to be extended or created via the {@link Ext.Component#componentLayout layout}
+ * configuration property.  See {@link Ext.Component#componentLayout} for additional details.
+ *
+ * @private
+ */
+Ext.define('Ext.layout.component.Component', {
 
-    /**
-     * <p>Unregisters a {@link Ext.Component} from this ZIndexManager. This should not
-     * need to be called. Components are automatically unregistered upon destruction.
-     * See {@link #register}.</p>
-     * @param {Component} comp The Component to unregister.
-     */
-    unregister : function(comp) {
-        delete comp.zIndexManager;
-        if (this.list && this.list[comp.id]) {
-            delete this.list[comp.id];
-            comp.un('hide', this._activateLast);
-            Ext.Array.remove(this.zIndexStack, comp);
+    /* Begin Definitions */
 
-            // Destruction requires that the topmost visible floater be activated. Same as hiding.
-            this._activateLast(comp);
+    extend: 'Ext.layout.Layout',
+
+    /* End Definitions */
+
+    type: 'component',
+
+    monitorChildren: true,
+
+    initLayout : function() {
+        var me = this,
+            owner = me.owner,
+            ownerEl = owner.el;
+
+        if (!me.initialized) {
+            if (owner.frameSize) {
+                me.frameSize = owner.frameSize;
+            }
+            else {
+                owner.frameSize = me.frameSize = {
+                    top: 0,
+                    left: 0,
+                    bottom: 0,
+                    right: 0
+                };
+            }
         }
+        me.callParent(arguments);
     },
 
-    /**
-     * Gets a registered Component by id.
-     * @param {String/Object} id The id of the Component or a {@link Ext.Component} instance
-     * @return {Ext.Component}
-     */
-    get : function(id) {
-        return typeof id == "object" ? id : this.list[id];
-    },
+    beforeLayout : function(width, height, isSetSize, callingContainer) {
+        this.callParent(arguments);
 
-   /**
-     * Brings the specified Component to the front of any other active Components in this ZIndexManager.
-     * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
-     * @return {Boolean} True if the dialog was brought to the front, else false
-     * if it was already in front
-     */
-    bringToFront : function(comp) {
-        comp = this.get(comp);
-        if (comp != this.front) {
-            Ext.Array.remove(this.zIndexStack, comp);
-            this.zIndexStack.push(comp);
-            this.assignZIndices();
-            return true;
+        var me = this,
+            owner = me.owner,
+            ownerCt = owner.ownerCt,
+            layout = owner.layout,
+            isVisible = owner.isVisible(true),
+            ownerElChild = owner.el.child,
+            layoutCollection;
+
+        // Cache the size we began with so we can see if there has been any effect.
+        me.previousComponentSize = me.lastComponentSize;
+
+        // Do not allow autoing of any dimensions which are fixed
+        if (!isSetSize
+            && ((!Ext.isNumber(width) && owner.isFixedWidth()) ||
+                (!Ext.isNumber(height) && owner.isFixedHeight()))
+            // unless we are being told to do so by the ownerCt's layout
+            && callingContainer && callingContainer !== ownerCt) {
+            
+            me.doContainerLayout();
+            return false;
         }
-        if (comp.modal) {
-            Ext.getBody().addCls(Ext.baseCSSPrefix + 'body-masked');
-            this.mask.setSize(Ext.core.Element.getViewWidth(true), Ext.core.Element.getViewHeight(true));
-            this.mask.show();
+
+        // If an ownerCt is hidden, add my reference onto the layoutOnShow stack.  Set the needsLayout flag.
+        // If the owner itself is a directly hidden floater, set the needsLayout object on that for when it is shown.
+        if (!isVisible && (owner.hiddenAncestor || owner.floating)) {
+            if (owner.hiddenAncestor) {
+                layoutCollection = owner.hiddenAncestor.layoutOnShow;
+                layoutCollection.remove(owner);
+                layoutCollection.add(owner);
+            }
+            owner.needsLayout = {
+                width: width,
+                height: height,
+                isSetSize: false
+            };
+        }
+
+        if (isVisible && this.needsLayout(width, height)) {
+            return owner.beforeComponentLayout(width, height, isSetSize, callingContainer);
+        }
+        else {
+            return false;
         }
-        return false;
     },
 
     /**
-     * Sends the specified Component to the back of other active Components in this ZIndexManager.
-     * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
-     * @return {Ext.Component} The Component
-     */
-    sendToBack : function(comp) {
-        comp = this.get(comp);
-        Ext.Array.remove(this.zIndexStack, comp);
-        this.zIndexStack.unshift(comp);
-        this.assignZIndices();
-        return comp;
+    * Check if the new size is different from the current size and only
+    * trigger a layout if it is necessary.
+    * @param {Number} width The new width to set.
+    * @param {Number} height The new height to set.
+    */
+    needsLayout : function(width, height) {
+        var me = this,
+            widthBeingChanged,
+            heightBeingChanged;
+            me.lastComponentSize = me.lastComponentSize || {
+                width: -Infinity,
+                height: -Infinity
+            };
+
+        // If autoWidthing, or an explicitly different width is passed, then the width is being changed.
+        widthBeingChanged  = !Ext.isDefined(width)  || me.lastComponentSize.width  !== width;
+
+        // If autoHeighting, or an explicitly different height is passed, then the height is being changed.
+        heightBeingChanged = !Ext.isDefined(height) || me.lastComponentSize.height !== height;
+
+
+        // isSizing flag added to prevent redundant layouts when going up the layout chain
+        return !me.isSizing && (me.childrenChanged || widthBeingChanged || heightBeingChanged);
     },
 
     /**
-     * Hides all Components managed by this ZIndexManager.
-     */
-    hideAll : function() {
-        for (var id in this.list) {
-            if (this.list[id].isComponent && this.list[id].isVisible()) {
-                this.list[id].hide();
-            }
+    * Set the size of any element supporting undefined, null, and values.
+    * @param {Number} width The new width to set.
+    * @param {Number} height The new height to set.
+    */
+    setElementSize: function(el, width, height) {
+        if (width !== undefined && height !== undefined) {
+            el.setSize(width, height);
+        }
+        else if (height !== undefined) {
+            el.setHeight(height);
+        }
+        else if (width !== undefined) {
+            el.setWidth(width);
         }
     },
 
     /**
-     * @private
-     * Temporarily hides all currently visible managed Components. This is for when
-     * dragging a Window which may manage a set of floating descendants in its ZIndexManager;
-     * they should all be hidden just for the duration of the drag.
+     * Returns the owner component's resize element.
+     * @return {Ext.Element}
      */
-    hide: function() {
-        var i = 0,
-            ln = this.zIndexStack.length,
-            comp;
+     getTarget : function() {
+         return this.owner.el;
+     },
 
-        this.tempHidden = [];
-        for (; i < ln; i++) {
-            comp = this.zIndexStack[i];
-            if (comp.isVisible()) {
-                this.tempHidden.push(comp);
-                comp.hide();
-            }
-        }
+    /**
+     * <p>Returns the element into which rendering must take place. Defaults to the owner Component's encapsulating element.</p>
+     * May be overridden in Component layout managers which implement an inner element.
+     * @return {Ext.Element}
+     */
+    getRenderTarget : function() {
+        return this.owner.el;
     },
 
     /**
-     * @private
-     * Restores temporarily hidden managed Components to visibility.
-     */
-    show: function() {
-        var i = 0,
-            ln = this.tempHidden.length,
-            comp,
-            x,
-            y;
+    * Set the size of the target element.
+    * @param {Number} width The new width to set.
+    * @param {Number} height The new height to set.
+    */
+    setTargetSize : function(width, height) {
+        var me = this;
+        me.setElementSize(me.owner.el, width, height);
 
-        for (; i < ln; i++) {
-            comp = this.tempHidden[i];
-            x = comp.x;
-            y = comp.y;
-            comp.show();
-            comp.setPosition(x, y);
+        if (me.owner.frameBody) {
+            var targetInfo = me.getTargetInfo(),
+                padding = targetInfo.padding,
+                border = targetInfo.border,
+                frameSize = me.frameSize;
+
+            me.setElementSize(me.owner.frameBody,
+                Ext.isNumber(width) ? (width - frameSize.left - frameSize.right - padding.left - padding.right - border.left - border.right) : width,
+                Ext.isNumber(height) ? (height - frameSize.top - frameSize.bottom - padding.top - padding.bottom - border.top - border.bottom) : height
+            );
         }
-        delete this.tempHidden;
-    },
 
-    /**
-     * Gets the currently-active Component in this ZIndexManager.
-     * @return {Ext.Component} The active Component
-     */
-    getActive : function() {
-        return this.front;
+        me.autoSized = {
+            width: !Ext.isNumber(width),
+            height: !Ext.isNumber(height)
+        };
+
+        me.lastComponentSize = {
+            width: width,
+            height: height
+        };
     },
 
-    /**
-     * Returns zero or more Components in this ZIndexManager using the custom search function passed to this method.
-     * The function should accept a single {@link Ext.Component} reference as its only argument and should
-     * return true if the Component matches the search criteria, otherwise it should return false.
-     * @param {Function} fn The search function
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component being tested.
-     * that gets passed to the function if not specified)
-     * @return {Array} An array of zero or more matching windows
-     */
-    getBy : function(fn, scope) {
-        var r = [],
-            i = 0,
-            len = this.zIndexStack.length,
-            comp;
+    getTargetInfo : function() {
+        if (!this.targetInfo) {
+            var target = this.getTarget(),
+                body = this.owner.getTargetEl();
 
-        for (; i < len; i++) {
-            comp = this.zIndexStack[i];
-            if (fn.call(scope||comp, comp) !== false) {
-                r.push(comp);
-            }
+            this.targetInfo = {
+                padding: {
+                    top: target.getPadding('t'),
+                    right: target.getPadding('r'),
+                    bottom: target.getPadding('b'),
+                    left: target.getPadding('l')
+                },
+                border: {
+                    top: target.getBorderWidth('t'),
+                    right: target.getBorderWidth('r'),
+                    bottom: target.getBorderWidth('b'),
+                    left: target.getBorderWidth('l')
+                },
+                bodyMargin: {
+                    top: body.getMargin('t'),
+                    right: body.getMargin('r'),
+                    bottom: body.getMargin('b'),
+                    left: body.getMargin('l')
+                }
+            };
         }
-        return r;
+        return this.targetInfo;
     },
 
-    /**
-     * Executes the specified function once for every Component in this ZIndexManager, passing each
-     * Component as the only parameter. Returning false from the function will stop the iteration.
-     * @param {Function} fn The function to execute for each item
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Component in the iteration.
-     */
-    each : function(fn, scope) {
-        var comp;
-        for (var id in this.list) {
-            comp = this.list[id];
-            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
-                return;
-            }
+    // Start laying out UP the ownerCt's layout when flagged to do so.
+    doOwnerCtLayouts: function() {
+        var owner = this.owner,
+            ownerCt = owner.ownerCt,
+            ownerCtComponentLayout, ownerCtContainerLayout,
+            curSize = this.lastComponentSize,
+            prevSize = this.previousComponentSize,
+            widthChange  = (prevSize && curSize && Ext.isNumber(curSize.width )) ? curSize.width  !== prevSize.width  : true,
+            heightChange = (prevSize && curSize && Ext.isNumber(curSize.height)) ? curSize.height !== prevSize.height : true;
+
+        // If size has not changed, do not inform upstream layouts
+        if (!ownerCt || (!widthChange && !heightChange)) {
+            return;
         }
-    },
 
-    /**
-     * Executes the specified function once for every Component in this ZIndexManager, passing each
-     * Component as the only parameter. Returning false from the function will stop the iteration.
-     * The components are passed to the function starting at the bottom and proceeding to the top.
-     * @param {Function} fn The function to execute for each item
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
-     * is executed. Defaults to the current Component in the iteration.
-     */
-    eachBottomUp: function (fn, scope) {
-        var comp,
-            stack = this.zIndexStack,
-            i, n;
+        ownerCtComponentLayout = ownerCt.componentLayout;
+        ownerCtContainerLayout = ownerCt.layout;
 
-        for (i = 0, n = stack.length ; i < n; i++) {
-            comp = stack[i];
-            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
-                return;
+        if (!owner.floating && ownerCtComponentLayout && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
+            if (!ownerCt.suspendLayout && ownerCtContainerLayout && !ownerCtContainerLayout.layoutBusy) {
+
+                // If the owning Container may be adjusted in any of the the dimension which have changed, perform its Component layout
+                if (((widthChange && !ownerCt.isFixedWidth()) || (heightChange && !ownerCt.isFixedHeight()))) {
+                    // Set the isSizing flag so that the upstream Container layout (called after a Component layout) can omit this component from sizing operations
+                    this.isSizing = true;
+                    ownerCt.doComponentLayout();
+                    this.isSizing = false;
+                }
+                // Execute upstream Container layout
+                else if (ownerCtContainerLayout.bindToOwnerCtContainer === true) {
+                    ownerCtContainerLayout.layout();
+                }
             }
         }
     },
 
-    /**
-     * Executes the specified function once for every Component in this ZIndexManager, passing each
-     * Component as the only parameter. Returning false from the function will stop the iteration.
-     * The components are passed to the function starting at the top and proceeding to the bottom.
-     * @param {Function} fn The function to execute for each item
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
-     * is executed. Defaults to the current Component in the iteration.
-     */
-    eachTopDown: function (fn, scope) {
-        var comp,
-            stack = this.zIndexStack,
-            i;
+    doContainerLayout: function() {
+        var me = this,
+            owner = me.owner,
+            ownerCt = owner.ownerCt,
+            layout = owner.layout,
+            ownerCtComponentLayout;
 
-        for (i = stack.length ; i-- > 0; ) {
-            comp = stack[i];
-            if (comp.isComponent && fn.call(scope || comp, comp) === false) {
-                return;
+        // Run the container layout if it exists (layout for child items)
+        // **Unless automatic laying out is suspended, or the layout is currently running**
+        if (!owner.suspendLayout && layout && layout.isLayout && !layout.layoutBusy && !layout.isAutoDock) {
+            layout.layout();
+        }
+
+        // Tell the ownerCt that it's child has changed and can be re-layed by ignoring the lastComponentSize cache.
+        if (ownerCt && ownerCt.componentLayout) {
+            ownerCtComponentLayout = ownerCt.componentLayout;
+            if (!owner.floating && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
+                ownerCtComponentLayout.childrenChanged = true;
             }
         }
     },
 
-    destroy: function() {
-        delete this.zIndexStack;
-        delete this.list;
-        delete this.container;
-        delete this.targetEl;
+    afterLayout : function(width, height, isSetSize, layoutOwner) {
+        this.doContainerLayout();
+        this.owner.afterComponentLayout(width, height, isSetSize, layoutOwner);
     }
-}, function() {
-    /**
-     * @class Ext.WindowManager
-     * @extends Ext.ZIndexManager
-     * <p>The default global floating Component group that is available automatically.</p>
-     * <p>This manages instances of floating Components which were rendered programatically without
-     * being added to a {@link Ext.container.Container Container}, and for floating Components which were added into non-floating Containers.</p>
-     * <p><i>Floating</i> Containers create their own instance of ZIndexManager, and floating Components added at any depth below
-     * there are managed by that ZIndexManager.</p>
-     * @singleton
-     */
-    Ext.WindowManager = Ext.WindowMgr = new this();
 });
 
 /**
- * @class Ext.layout.container.boxOverflow.None
- * @extends Object
- * @private
- * Base class for Box Layout overflow handlers. These specialized classes are invoked when a Box Layout
- * (either an HBox or a VBox) has child items that are either too wide (for HBox) or too tall (for VBox)
- * for its container.
+ * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
+ * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
+ * should not contain any HTML, otherwise it may not be measured correctly.
+ *
+ * The measurement works by copying the relevant CSS styles that can affect the font related display, 
+ * then checking the size of an element that is auto-sized. Note that if the text is multi-lined, you must 
+ * provide a **fixed width** when doing the measurement.
+ *
+ * If multiple measurements are being done on the same element, you create a new instance to initialize 
+ * to avoid the overhead of copying the styles to the element repeatedly.
  */
-Ext.define('Ext.layout.container.boxOverflow.None', {
+Ext.define('Ext.util.TextMetrics', {
+    statics: {
+        shared: null,
+        /**
+         * Measures the size of the specified text
+         * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
+         * that can affect the size of the rendered text
+         * @param {String} text The text to measure
+         * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
+         * in order to accurately measure the text height
+         * @return {Object} An object containing the text's size `{width: (width), height: (height)}`
+         */
+        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 the TextMetrics instance created by {@link #measure}.
+          */
+         destroy: function(){
+             var me = this;
+             Ext.destroy(me.shared);
+             me.shared = null;
+         }
+    },
     
-    alternateClassName: 'Ext.layout.boxOverflow.None',
+    /**
+     * Creates new TextMetrics.
+     * @param {String/HTMLElement/Ext.Element} bindTo The element or its ID to bind to.
+     * @param {Number} fixedWidth (optional) A fixed width to apply to the measuring element.
+     */
+    constructor: function(bindTo, fixedWidth){
+        var measure = this.measure = Ext.getBody().createChild({
+            cls: 'x-textmetrics'
+        });
+        this.el = Ext.get(bindTo);
+        
+        measure.position('absolute');
+        measure.setLeftTop(-1000, -1000);
+        measure.hide();
+
+        if (fixedWidth) {
+           measure.setWidth(fixedWidth);
+        }
+    },
     
-    constructor: function(layout, config) {
-        this.layout = layout;
-        Ext.apply(this, config || {});
+    /**
+     * Returns the size of the specified text based on the internal element's style and width properties
+     * @param {String} text The text to measure
+     * @return {Object} An object containing the text's size `{width: (width), height: (height)}`
+     */
+    getSize: function(text){
+        var measure = this.measure,
+            size;
+        
+        measure.update(text);
+        size = measure.getSize();
+        measure.update('');
+        return size;
     },
-
-    handleOverflow: Ext.emptyFn,
-
-    clearOverflow: Ext.emptyFn,
     
-    onRemove: Ext.emptyFn,
-
     /**
-     * @private
-     * Normalizes an item reference, string id or numerical index into a reference to the item
-     * @param {Ext.Component|String|Number} item The item reference, id or index
-     * @return {Ext.Component} The item
+     * Binds this TextMetrics instance to a new element
+     * @param {String/HTMLElement/Ext.Element} el The element or its ID.
      */
-    getItem: function(item) {
-        return this.layout.owner.getComponent(item);
+    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')
+        );
     },
     
-    onRemove: Ext.emptyFn
-});
-/**
- * @class Ext.util.KeyMap
- * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
- * The constructor accepts the same config object as defined by {@link #addBinding}.
- * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
- * combination it will call the function with this signature (if the match is a multi-key
- * combination the callback will still be called only once): (String key, Ext.EventObject e)
- * A KeyMap can also handle a string representation of keys.<br />
- * Usage:
- <pre><code>
-// map one key by key code
-var map = new Ext.util.KeyMap("my-element", {
-    key: 13, // or Ext.EventObject.ENTER
-    fn: myHandler,
-    scope: myObject
-});
-
-// map multiple keys to one action by string
-var map = new Ext.util.KeyMap("my-element", {
-    key: "a\r\n\t",
-    fn: myHandler,
-    scope: myObject
+    /**
+     * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
+     * to set a fixed width in order to accurately measure the text height.
+     * @param {Number} width The width to set on the element
+     */
+     setFixedWidth : function(width){
+         this.measure.setWidth(width);
+     },
+     
+     /**
+      * Returns the measured width of the specified text
+      * @param {String} text The text to measure
+      * @return {Number} width The width in pixels
+      */
+     getWidth : function(text){
+         this.measure.dom.style.width = 'auto';
+         return this.getSize(text).width;
+     },
+     
+     /**
+      * Returns the measured height of the specified text
+      * @param {String} text The text to measure
+      * @return {Number} height The height in pixels
+      */
+     getHeight : function(text){
+         return this.getSize(text).height;
+     },
+     
+     /**
+      * Destroy this instance
+      */
+     destroy: function(){
+         var me = this;
+         me.measure.remove();
+         delete me.el;
+         delete me.measure;
+     }
+}, function(){
+    Ext.Element.addMethods({
+        /**
+         * Returns the width in pixels of the passed text, or the width of the text in this Element.
+         * @param {String} text The text to measure. Defaults to the innerHTML of the element.
+         * @param {Number} min (optional) The minumum value to return.
+         * @param {Number} max (optional) The maximum value to return.
+         * @return {Number} The text width in pixels.
+         * @member Ext.Element
+         */
+        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);
+        }
+    });
 });
 
-// map multiple keys to multiple actions by strings and array of codes
-var map = new Ext.util.KeyMap("my-element", [
-    {
-        key: [10,13],
-        fn: function(){ alert("Return was pressed"); }
-    }, {
-        key: "abc",
-        fn: function(){ alert('a, b or c was pressed'); }
-    }, {
-        key: "\t",
-        ctrl:true,
-        shift:true,
-        fn: function(){ alert('Control + shift + tab was pressed.'); }
-    }
-]);
-</code></pre>
- * <b>Note: A KeyMap starts enabled</b>
+/**
+ * @class Ext.layout.container.boxOverflow.Scroller
+ * @extends Ext.layout.container.boxOverflow.None
+ * @private
  */
-Ext.define('Ext.util.KeyMap', {
-    alternateClassName: 'Ext.KeyMap',
+Ext.define('Ext.layout.container.boxOverflow.Scroller', {
 
-    /**
-     * Creates new KeyMap.
-     * @param {Mixed} el The element to bind to
-     * @param {Object} binding The binding (see {@link #addBinding})
-     * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
-     */
-    constructor: function(el, binding, eventName){
-        var me = this;
-        
-        Ext.apply(me, {
-            el: Ext.get(el),
-            eventName: eventName || me.eventName,
-            bindings: []
-        });
-        if (binding) {
-            me.addBinding(binding);
-        }
-        me.enable();
+    /* Begin Definitions */
+
+    extend: 'Ext.layout.container.boxOverflow.None',
+    requires: ['Ext.util.ClickRepeater', 'Ext.Element'],
+    alternateClassName: 'Ext.layout.boxOverflow.Scroller',
+    mixins: {
+        observable: 'Ext.util.Observable'
     },
     
-    eventName: 'keydown',
+    /* End Definitions */
 
     /**
-     * Add a new binding to this KeyMap. The following config object properties are supported:
-     * <pre>
-Property            Type             Description
-----------          ---------------  ----------------------------------------------------------------------
-key                 String/Array     A single keycode or an array of keycodes to handle
-shift               Boolean          True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
-ctrl                Boolean          True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
-alt                 Boolean          True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
-handler             Function         The function to call when KeyMap finds the expected key combination
-fn                  Function         Alias of handler (for backwards-compatibility)
-scope               Object           The scope of the callback function
-defaultEventAction  String           A default action to apply to the event. Possible values are: stopEvent, stopPropagation, preventDefault. If no value is set no action is performed. 
-</pre>
-     *
-     * Usage:
-     * <pre><code>
-// Create a KeyMap
-var map = new Ext.util.KeyMap(document, {
-    key: Ext.EventObject.ENTER,
-    fn: handleKey,
-    scope: this
-});
-
-//Add a new binding to the existing KeyMap later
-map.addBinding({
-    key: 'abc',
-    shift: true,
-    fn: handleKey,
-    scope: this
-});
-</code></pre>
-     * @param {Object/Array} binding A single KeyMap config or an array of configs
+     * @cfg {Boolean} animateScroll
+     * True to animate the scrolling of items within the layout (ignored if enableScroll is false)
      */
-    addBinding : function(binding){
-        if (Ext.isArray(binding)) {
-            Ext.each(binding, this.addBinding, this);
-            return;
-        }
-        
-        var keyCode = binding.key,
-            processed = false,
-            key,
-            keys,
-            keyString,
-            i,
-            len;
+    animateScroll: false,
 
-        if (Ext.isString(keyCode)) {
-            keys = [];
-            keyString = keyCode.toLowerCase();
-            
-            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.toLowerCase().charCodeAt(0);
-                }
-            }
-        }
-        
-        this.bindings.push(Ext.apply({
-            keyCode: keyCode
-        }, binding));
-    },
-    
     /**
-     * Process any keydown events on the element
-     * @private
-     * @param {Ext.EventObject} event
+     * @cfg {Number} scrollIncrement
+     * The number of pixels to scroll by on scroller click
      */
-    handleKeyDown: function(event) {
-        if (this.enabled) { //just in case
-            var bindings = this.bindings,
-                i = 0,
-                len = bindings.length;
-                
-            event = this.processEvent(event);
-            for(; i < len; ++i){
-                this.processBinding(bindings[i], event);
-            }
-        }
-    },
-    
+    scrollIncrement: 20,
+
     /**
-     * Ugly hack to allow this class to be tested. Currently WebKit gives
-     * no way to raise a key event properly with both
-     * a) A keycode
-     * b) The alt/ctrl/shift modifiers
-     * So we have to simulate them here. Yuk! 
-     * This is a stub method intended to be overridden by tests.
-     * More info: https://bugs.webkit.org/show_bug.cgi?id=16735
-     * @private
+     * @cfg {Number} wheelIncrement
+     * The number of pixels to increment on mouse wheel scrolling.
      */
-    processEvent: function(event){
-        return event;
-    },
-    
+    wheelIncrement: 10,
+
     /**
-     * Process a particular binding and fire the handler if necessary.
-     * @private
-     * @param {Object} binding The binding information
-     * @param {Ext.EventObject} event
+     * @cfg {Number} scrollRepeatInterval
+     * Number of milliseconds between each scroll while a scroller button is held down
      */
-    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;
-                }
-            }
-        }
-    },
-    
+    scrollRepeatInterval: 60,
+
     /**
-     * Check if the modifiers on the event match those on the binding
-     * @private
-     * @param {Object} binding
-     * @param {Ext.EventObject} event
-     * @return {Boolean} True if the event matches the binding
+     * @cfg {Number} scrollDuration
+     * Number of milliseconds that each scroll animation lasts
      */
-    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;
-    },
+    scrollDuration: 400,
 
     /**
-     * Shorthand for adding a single key listener
-     * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
-     * following options:
-     * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
+     * @cfg {String} beforeCtCls
+     * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
+     * which must always be present at the leftmost edge of the Container
      */
-    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
-        });
-    },
 
     /**
-     * Returns true if this KeyMap is enabled
-     * @return {Boolean}
+     * @cfg {String} afterCtCls
+     * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
+     * which must always be present at the rightmost edge of the Container
      */
-    isEnabled : function(){
-        return this.enabled;
-    },
 
     /**
-     * Enables this KeyMap
+     * @cfg {String} [scrollerCls='x-box-scroller']
+     * CSS class added to both scroller elements if enableScroll is used
      */
-    enable: function(){
-        if(!this.enabled){
-            this.el.on(this.eventName, this.handleKeyDown, this);
-            this.enabled = true;
-        }
-    },
+    scrollerCls: Ext.baseCSSPrefix + 'box-scroller',
 
     /**
-     * Disable this KeyMap
+     * @cfg {String} beforeScrollerCls
+     * CSS class added to the left scroller element if enableScroll is used
      */
-    disable: function(){
-        if(this.enabled){
-            this.el.removeListener(this.eventName, this.handleKeyDown, this);
-            this.enabled = false;
-        }
-    },
 
     /**
-     * Convenience function for setting disabled/enabled by boolean.
-     * @param {Boolean} disabled
+     * @cfg {String} afterScrollerCls
+     * CSS class added to the right scroller element if enableScroll is used
      */
-    setDisabled : function(disabled){
-        if (disabled) {
-            this.disable();
-        } else {
-            this.enable();
-        }
-    },
     
-    /**
-     * Destroys the KeyMap instance and removes all handlers.
-     * @param {Boolean} removeEl True to also remove the attached element
-     */
-    destroy: function(removeEl){
-        var me = this;
+    constructor: function(layout, config) {
+        this.layout = layout;
+        Ext.apply(this, config || {});
         
-        me.bindings = [];
-        me.disable();
-        if (removeEl === true) {
-            me.el.remove();
-        }
-        delete me.el;
-    }
-});
-/**
- * @class Ext.util.ClickRepeater
- * @extends Ext.util.Observable
- *
- * A wrapper class which can be applied to any element. Fires a "click" event while the
- * mouse is pressed. The interval between firings may be specified in the config but
- * defaults to 20 milliseconds.
- *
- * Optionally, a CSS class may be applied to the element during the time it is pressed.
- *
- */
-Ext.define('Ext.util.ClickRepeater', {
-    extend: 'Ext.util.Observable',
-
-    /**
-     * Creates new ClickRepeater.
-     * @param {Mixed} el The element to listen on
-     * @param {Object} config (optional) Config object.
-     */
-    constructor : function(el, config){
-        this.el = Ext.get(el);
-        this.el.unselectable();
-
-        Ext.apply(this, config);
-
         this.addEvents(
-        /**
-         * @event mousedown
-         * Fires when the mouse button is depressed.
-         * @param {Ext.util.ClickRepeater} this
-         * @param {Ext.EventObject} e
-         */
-        "mousedown",
-        /**
-         * @event click
-         * Fires on a specified interval during the time the element is pressed.
-         * @param {Ext.util.ClickRepeater} this
-         * @param {Ext.EventObject} e
-         */
-        "click",
-        /**
-         * @event mouseup
-         * Fires when the mouse key is released.
-         * @param {Ext.util.ClickRepeater} this
-         * @param {Ext.EventObject} e
-         */
-        "mouseup"
+            /**
+             * @event scroll
+             * @param {Ext.layout.container.boxOverflow.Scroller} scroller The layout scroller
+             * @param {Number} newPosition The new position of the scroller
+             * @param {Boolean/Object} animate If animating or not. If true, it will be a animation configuration, else it will be false
+             */
+            'scroll'
         );
+    },
+    
+    initCSSClasses: function() {
+        var me = this,
+        layout = me.layout;
 
-        if(!this.disabled){
-            this.disabled = true;
-            this.enable();
+        if (!me.CSSinitialized) {
+            me.beforeCtCls = me.beforeCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelBefore;
+            me.afterCtCls  = me.afterCtCls  || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelAfter;
+            me.beforeScrollerCls = me.beforeScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelBefore;
+            me.afterScrollerCls  = me.afterScrollerCls  || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelAfter;
+            me.CSSinitializes = true;
         }
+    },
 
-        // allow inline handler
-        if(this.handler){
-            this.on("click", this.handler,  this.scope || this);
-        }
+    handleOverflow: function(calculations, targetSize) {
+        var me = this,
+            layout = me.layout,
+            methodName = 'get' + layout.parallelPrefixCap,
+            newSize = {};
 
-        this.callParent();
+        me.initCSSClasses();
+        me.callParent(arguments);
+        this.createInnerElements();
+        this.showScrollers();
+        newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
+        newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - (me.beforeCt[methodName]() + me.afterCt[methodName]());
+        return { targetSize: newSize };
     },
 
     /**
-     * @cfg {Mixed} el The element to act as a button.
+     * @private
+     * Creates the beforeCt and afterCt elements if they have not already been created
      */
+    createInnerElements: function() {
+        var me = this,
+            target = me.layout.getRenderTarget();
 
-    /**
-     * @cfg {String} pressedCls A CSS class name to be applied to the element while pressed.
-     */
+        //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
+        //special items such as scrollers or dropdown menu triggers
+        if (!me.beforeCt) {
+            target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
+            me.beforeCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls}, 'before');
+            me.afterCt  = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls},  'after');
+            me.createWheelListener();
+        }
+    },
 
     /**
-     * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
-     * "interval" and "delay" are ignored.
+     * @private
+     * Sets up an listener to scroll on the layout's innerCt mousewheel event
      */
+    createWheelListener: function() {
+        this.layout.innerCt.on({
+            scope     : this,
+            mousewheel: function(e) {
+                e.stopEvent();
 
-    /**
-     * @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.
-     */
-    interval : 20,
+                this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
+            }
+        });
+    },
 
     /**
-     * @cfg {Number} delay The initial delay before the repeating event begins firing.
-     * Similar to an autorepeat key delay.
+     * @private
      */
-    delay: 250,
+    clearOverflow: function() {
+        this.hideScrollers();
+    },
 
     /**
-     * @cfg {Boolean} preventDefault True to prevent the default click event
-     */
-    preventDefault : true,
-    /**
-     * @cfg {Boolean} stopDefault True to stop the default click event
+     * @private
+     * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
+     * present. 
      */
-    stopDefault : false,
-
-    timer : 0,
+    showScrollers: function() {
+        this.createScrollers();
+        this.beforeScroller.show();
+        this.afterScroller.show();
+        this.updateScrollButtons();
+        
+        this.layout.owner.addClsWithUI('scroller');
+    },
 
     /**
-     * Enables the repeater and allows events to fire.
+     * @private
+     * Hides the scroller elements in the beforeCt and afterCt
      */
-    enable: function(){
-        if(this.disabled){
-            this.el.on('mousedown', this.handleMouseDown, this);
-            if (Ext.isIE){
-                this.el.on('dblclick', this.handleDblClick, this);
-            }
-            if(this.preventDefault || this.stopDefault){
-                this.el.on('click', this.eventOptions, this);
-            }
+    hideScrollers: function() {
+        if (this.beforeScroller != undefined) {
+            this.beforeScroller.hide();
+            this.afterScroller.hide();
+            
+            this.layout.owner.removeClsWithUI('scroller');
         }
-        this.disabled = false;
     },
 
     /**
-     * Disables the repeater and stops events from firing.
+     * @private
+     * Creates the clickable scroller elements and places them into the beforeCt and afterCt
      */
-    disable: function(/* private */ 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();
+    createScrollers: function() {
+        if (!this.beforeScroller && !this.afterScroller) {
+            var before = this.beforeCt.createChild({
+                cls: Ext.String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls)
+            });
+
+            var after = this.afterCt.createChild({
+                cls: Ext.String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls)
+            });
+
+            before.addClsOnOver(this.beforeScrollerCls + '-hover');
+            after.addClsOnOver(this.afterScrollerCls + '-hover');
+
+            before.setVisibilityMode(Ext.Element.DISPLAY);
+            after.setVisibilityMode(Ext.Element.DISPLAY);
+
+            this.beforeRepeater = Ext.create('Ext.util.ClickRepeater', before, {
+                interval: this.scrollRepeatInterval,
+                handler : this.scrollLeft,
+                scope   : this
+            });
+
+            this.afterRepeater = Ext.create('Ext.util.ClickRepeater', after, {
+                interval: this.scrollRepeatInterval,
+                handler : this.scrollRight,
+                scope   : this
+            });
+
+            /**
+             * @property beforeScroller
+             * @type Ext.Element
+             * The left scroller element. Only created when needed.
+             */
+            this.beforeScroller = before;
+
+            /**
+             * @property afterScroller
+             * @type Ext.Element
+             * The left scroller element. Only created when needed.
+             */
+            this.afterScroller = after;
         }
-        this.disabled = true;
     },
 
     /**
-     * Convenience function for setting disabled/enabled by boolean.
-     * @param {Boolean} disabled
+     * @private
      */
-    setDisabled: function(disabled){
-        this[disabled ? 'disable' : 'enable']();
-    },
-
-    eventOptions: function(e){
-        if(this.preventDefault){
-            e.preventDefault();
-        }
-        if(this.stopDefault){
-            e.stopEvent();
-        }
+    destroy: function() {
+        Ext.destroy(this.beforeRepeater, this.afterRepeater, this.beforeScroller, this.afterScroller, this.beforeCt, this.afterCt);
     },
 
-    // private
-    destroy : function() {
-        this.disable(true);
-        Ext.destroy(this.el);
-        this.clearListeners();
+    /**
+     * @private
+     * Scrolls left or right by the number of pixels specified
+     * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
+     */
+    scrollBy: function(delta, animate) {
+        this.scrollTo(this.getScrollPosition() + delta, animate);
     },
 
-    handleDblClick : function(e){
-        clearTimeout(this.timer);
-        this.el.blur();
-
-        this.fireEvent("mousedown", this, e);
-        this.fireEvent("click", this, e);
+    /**
+     * @private
+     * @return {Object} Object passed to scrollTo when scrolling
+     */
+    getScrollAnim: function() {
+        return {
+            duration: this.scrollDuration, 
+            callback: this.updateScrollButtons, 
+            scope   : this
+        };
     },
 
-    // private
-    handleMouseDown : function(e){
-        clearTimeout(this.timer);
-        this.el.blur();
-        if(this.pressedCls){
-            this.el.addCls(this.pressedCls);
+    /**
+     * @private
+     * Enables or disables each scroller button based on the current scroll position
+     */
+    updateScrollButtons: function() {
+        if (this.beforeScroller == undefined || this.afterScroller == undefined) {
+            return;
         }
-        this.mousedownTime = new Date();
 
-        Ext.getDoc().on("mouseup", this.handleMouseUp, this);
-        this.el.on("mouseout", this.handleMouseOut, this);
+        var beforeMeth = this.atExtremeBefore()  ? 'addCls' : 'removeCls',
+            afterMeth  = this.atExtremeAfter() ? 'addCls' : 'removeCls',
+            beforeCls  = this.beforeScrollerCls + '-disabled',
+            afterCls   = this.afterScrollerCls  + '-disabled';
+        
+        this.beforeScroller[beforeMeth](beforeCls);
+        this.afterScroller[afterMeth](afterCls);
+        this.scrolling = false;
+    },
 
-        this.fireEvent("mousedown", this, e);
-        this.fireEvent("click", this, e);
+    /**
+     * @private
+     * Returns true if the innerCt scroll is already at its left-most point
+     * @return {Boolean} True if already at furthest left point
+     */
+    atExtremeBefore: function() {
+        return this.getScrollPosition() === 0;
+    },
 
-        // Do not honor delay or interval if acceleration wanted.
-        if (this.accelerate) {
-            this.delay = 400;
-        }
+    /**
+     * @private
+     * Scrolls to the left by the configured amount
+     */
+    scrollLeft: function() {
+        this.scrollBy(-this.scrollIncrement, false);
+    },
 
-        // Re-wrap the event object in a non-shared object, so it doesn't lose its context if
-        // the global shared EventObject gets a new Event put into it before the timer fires.
-        e = new Ext.EventObjectImpl(e);
+    /**
+     * @private
+     * Scrolls to the right by the configured amount
+     */
+    scrollRight: function() {
+        this.scrollBy(this.scrollIncrement, false);
+    },
 
-        this.timer =  Ext.defer(this.click, this.delay || this.interval, this, [e]);
+    /**
+     * Returns the current scroll position of the innerCt element
+     * @return {Number} The current scroll position
+     */
+    getScrollPosition: function(){
+        var layout = this.layout;
+        return parseInt(layout.innerCt.dom['scroll' + layout.parallelBeforeCap], 10) || 0;
     },
 
-    // private
-    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]);
+    /**
+     * @private
+     * Returns the maximum value we can scrollTo
+     * @return {Number} The max scroll value
+     */
+    getMaxScrollPosition: function() {
+        var layout = this.layout;
+        return layout.innerCt.dom['scroll' + layout.parallelPrefixCap] - this.layout.innerCt['get' + layout.parallelPrefixCap]();
     },
 
-    easeOutExpo : function (t, b, c, d) {
-        return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
+    /**
+     * @private
+     * Returns true if the innerCt scroll is already at its right-most point
+     * @return {Boolean} True if already at furthest right point
+     */
+    atExtremeAfter: function() {
+        return this.getScrollPosition() >= this.getMaxScrollPosition();
     },
 
-    // private
-    handleMouseOut : function(){
-        clearTimeout(this.timer);
-        if(this.pressedCls){
-            this.el.removeCls(this.pressedCls);
+    /**
+     * @private
+     * Scrolls to the given position. Performs bounds checking.
+     * @param {Number} position The position to scroll to. This is constrained.
+     * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
+     */
+    scrollTo: function(position, animate) {
+        var me = this,
+            layout = me.layout,
+            oldPosition = me.getScrollPosition(),
+            newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition());
+
+        if (newPosition != oldPosition && !me.scrolling) {
+            if (animate == undefined) {
+                animate = me.animateScroll;
+            }
+
+            layout.innerCt.scrollTo(layout.parallelBefore, newPosition, animate ? me.getScrollAnim() : false);
+            if (animate) {
+                me.scrolling = true;
+            } else {
+                me.scrolling = false;
+                me.updateScrollButtons();
+            }
+            
+            me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false);
         }
-        this.el.on("mouseover", this.handleMouseReturn, this);
     },
 
-    // private
-    handleMouseReturn : function(){
-        this.el.un("mouseover", this.handleMouseReturn, this);
-        if(this.pressedCls){
-            this.el.addCls(this.pressedCls);
+    /**
+     * Scrolls to the given component.
+     * @param {String/Number/Ext.Component} item The item to scroll to. Can be a numerical index, component id 
+     * or a reference to the component itself.
+     * @param {Boolean} animate True to animate the scrolling
+     */
+    scrollToItem: function(item, animate) {
+        var me = this,
+            layout = me.layout,
+            visibility,
+            box,
+            newPos;
+
+        item = me.getItem(item);
+        if (item != undefined) {
+            visibility = this.getItemVisibility(item);
+            if (!visibility.fullyVisible) {
+                box  = item.getBox(true, true);
+                newPos = box[layout.parallelPosition];
+                if (visibility.hiddenEnd) {
+                    newPos -= (this.layout.innerCt['get' + layout.parallelPrefixCap]() - box[layout.parallelPrefix]);
+                }
+                this.scrollTo(newPos, animate);
+            }
         }
-        this.click();
     },
 
-    // private
-    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);
+    /**
+     * @private
+     * For a given item in the container, return an object with information on whether the item is visible
+     * with the current innerCt scroll value.
+     * @param {Ext.Component} item The item
+     * @return {Object} Values for fullyVisible, hiddenStart and hiddenEnd
+     */
+    getItemVisibility: function(item) {
+        var me          = this,
+            box         = me.getItem(item).getBox(true, true),
+            layout      = me.layout,
+            itemStart   = box[layout.parallelPosition],
+            itemEnd     = itemStart + box[layout.parallelPrefix],
+            scrollStart = me.getScrollPosition(),
+            scrollEnd   = scrollStart + layout.innerCt['get' + layout.parallelPrefixCap]();
+
+        return {
+            hiddenStart : itemStart < scrollStart,
+            hiddenEnd   : itemEnd > scrollEnd,
+            fullyVisible: itemStart > scrollStart && itemEnd < scrollEnd
+        };
     }
 });
-
 /**
- * Component layout for buttons
- * @class Ext.layout.component.Button
- * @extends Ext.layout.component.Component
- * @private
+ * @class Ext.util.Offset
+ * @ignore
  */
-Ext.define('Ext.layout.component.Button', {
+Ext.define('Ext.util.Offset', {
 
     /* Begin Definitions */
 
-    alias: ['layout.button'],
-
-    extend: 'Ext.layout.component.Component',
+    statics: {
+        fromObject: function(obj) {
+            return new this(obj.x, obj.y);
+        }
+    },
 
     /* End Definitions */
 
-    type: 'button',
-
-    cellClsRE: /-btn-(tl|br)\b/,
-    htmlRE: /<.*>/,
+    constructor: function(x, y) {
+        this.x = (x != null && !isNaN(x)) ? x : 0;
+        this.y = (y != null && !isNaN(y)) ? y : 0;
 
-    beforeLayout: function() {
-        return this.callParent(arguments) || this.lastText !== this.owner.text;
+        return this;
     },
 
-    /**
-     * Set the dimensions of the inner &lt;button&gt; element to match the
-     * component dimensions.
-     */
-    onLayout: function(width, height) {
-        var me = this,
-            isNum = Ext.isNumber,
-            owner = me.owner,
-            ownerEl = owner.el,
-            btnEl = owner.btnEl,
-            btnInnerEl = owner.btnInnerEl,
-            btnIconEl = owner.btnIconEl,
-            sizeIconEl = (owner.icon || owner.iconCls) && (owner.iconAlign == "top" || owner.iconAlign == "bottom"),
-            minWidth = owner.minWidth,
-            maxWidth = owner.maxWidth,
-            ownerWidth, btnFrameWidth, metrics;
-
-        me.getTargetInfo();
-        me.callParent(arguments);
-
-        btnInnerEl.unclip();
-        me.setTargetSize(width, height);
-
-        if (!isNum(width)) {
-            // In IE7 strict mode button elements with width:auto get strange extra side margins within
-            // the wrapping table cell, but they go away if the width is explicitly set. So we measure
-            // the size of the text and set the width to match.
-            if (owner.text && Ext.isIE7 && Ext.isStrict && btnEl && btnEl.getWidth() > 20) {
-                btnFrameWidth = me.btnFrameWidth;
-                metrics = Ext.util.TextMetrics.measure(btnInnerEl, owner.text);
-                ownerEl.setWidth(metrics.width + btnFrameWidth + me.adjWidth);
-                btnEl.setWidth(metrics.width + btnFrameWidth);
-                btnInnerEl.setWidth(metrics.width + btnFrameWidth);
-
-                if (sizeIconEl) {
-                    btnIconEl.setWidth(metrics.width + btnFrameWidth);
-                }
-            } else {
-                // Remove any previous fixed widths
-                ownerEl.setWidth(null);
-                btnEl.setWidth(null);
-                btnInnerEl.setWidth(null);
-                btnIconEl.setWidth(null);
-            }
-
-            // Handle maxWidth/minWidth config
-            if (minWidth || maxWidth) {
-                ownerWidth = ownerEl.getWidth();
-                if (minWidth && (ownerWidth < minWidth)) {
-                    me.setTargetSize(minWidth, height);
-                }
-                else if (maxWidth && (ownerWidth > maxWidth)) {
-                    btnInnerEl.clip();
-                    me.setTargetSize(maxWidth, height);
-                }
-            }
-        }
+    copy: function() {
+        return new Ext.util.Offset(this.x, this.y);
+    },
 
-        this.lastText = owner.text;
+    copyFrom: function(p) {
+        this.x = p.x;
+        this.y = p.y;
     },
 
-    setTargetSize: function(width, height) {
-        var me = this,
-            owner = me.owner,
-            isNum = Ext.isNumber,
-            btnInnerEl = owner.btnInnerEl,
-            btnWidth = (isNum(width) ? width - me.adjWidth : width),
-            btnHeight = (isNum(height) ? height - me.adjHeight : height),
-            btnFrameHeight = me.btnFrameHeight,
-            text = owner.getText(),
-            textHeight;
+    toString: function() {
+        return "Offset[" + this.x + "," + this.y + "]";
+    },
 
-        me.callParent(arguments);
-        me.setElementSize(owner.btnEl, btnWidth, btnHeight);
-        me.setElementSize(btnInnerEl, btnWidth, btnHeight);
-        if (isNum(btnHeight)) {
-            btnInnerEl.setStyle('line-height', btnHeight - btnFrameHeight + 'px');
+    equals: function(offset) {
+        //<debug>
+        if(!(offset instanceof this.statics())) {
+            Ext.Error.raise('Offset must be an instance of Ext.util.Offset');
         }
+        //</debug>
 
-        // Button text may contain markup that would force it to wrap to more than one line (e.g. 'Button<br>Label').
-        // When this happens, we cannot use the line-height set above for vertical centering; we instead reset the
-        // line-height to normal, measure the rendered text height, and add padding-top to center the text block
-        // vertically within the button's height. This is more expensive than the basic line-height approach so
-        // we only do it if the text contains markup.
-        if (text && this.htmlRE.test(text)) {
-            btnInnerEl.setStyle('line-height', 'normal');
-            textHeight = Ext.util.TextMetrics.measure(btnInnerEl, text).height;
-            btnInnerEl.setStyle('padding-top', me.btnFrameTop + Math.max(btnInnerEl.getHeight() - btnFrameHeight - textHeight, 0) / 2 + 'px');
-            me.setElementSize(btnInnerEl, btnWidth, btnHeight);
-        }
+        return (this.x == offset.x && this.y == offset.y);
     },
 
-    getTargetInfo: function() {
-        var me = this,
-            owner = me.owner,
-            ownerEl = owner.el,
-            frameSize = me.frameSize,
-            frameBody = owner.frameBody,
-            btnWrap = owner.btnWrap,
-            innerEl = owner.btnInnerEl;
-
-        if (!('adjWidth' in me)) {
-            Ext.apply(me, {
-                // Width adjustment must take into account the arrow area. The btnWrap is the <em> which has padding to accommodate the arrow.
-                adjWidth: frameSize.left + frameSize.right + ownerEl.getBorderWidth('lr') + ownerEl.getPadding('lr') +
-                          btnWrap.getPadding('lr') + (frameBody ? frameBody.getFrameWidth('lr') : 0),
-                adjHeight: frameSize.top + frameSize.bottom + ownerEl.getBorderWidth('tb') + ownerEl.getPadding('tb') +
-                           btnWrap.getPadding('tb') + (frameBody ? frameBody.getFrameWidth('tb') : 0),
-                btnFrameWidth: innerEl.getFrameWidth('lr'),
-                btnFrameHeight: innerEl.getFrameWidth('tb'),
-                btnFrameTop: innerEl.getFrameWidth('t')
-            });
+    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);
         }
+    },
 
-        return me.callParent();
+    isZero: function() {
+        return this.x == 0 && this.y == 0;
     }
 });
+
 /**
- * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
- * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
- * should not contain any HTML, otherwise it may not be measured correctly.
- *
- * The measurement works by copying the relevant CSS styles that can affect the font related display, 
- * then checking the size of an element that is auto-sized. Note that if the text is multi-lined, you must 
- * provide a **fixed width** when doing the measurement.
- *
- * If multiple measurements are being done on the same element, you create a new instance to initialize 
- * to avoid the overhead of copying the styles to the element repeatedly.
- */
-Ext.define('Ext.util.TextMetrics', {
-    statics: {
-        shared: null,
-        /**
-         * Measures the size of the specified text
-         * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
-         * that can affect the size of the rendered text
-         * @param {String} text The text to measure
-         * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
-         * in order to accurately measure the text height
-         * @return {Object} An object containing the text's size `{width: (width), height: (height)}`
-         */
-        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 the TextMetrics instance created by {@link #measure}.
-          */
-         destroy: function(){
-             var me = this;
-             Ext.destroy(me.shared);
-             me.shared = null;
-         }
+ * @class Ext.util.KeyNav
+ * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
+ * navigation keys to function calls that will get called when the keys are pressed, providing an easy
+ * way to implement custom navigation schemes for any UI component.</p>
+ * <p>The following are all of the possible keys that can be implemented: enter, space, left, right, up, down, tab, esc,
+ * pageUp, pageDown, del, backspace, home, end.  Usage:</p>
+ <pre><code>
+var nav = new Ext.util.KeyNav("my-element", {
+    "left" : function(e){
+        this.moveLeft(e.ctrlKey);
     },
-    
-    /**
-     * Creates new TextMetrics.
-     * @param {Mixed} bindTo The element to bind to.
-     * @param {Number} fixedWidth (optional) A fixed width to apply to the measuring element.
-     */
-    constructor: function(bindTo, fixedWidth){
-        var measure = this.measure = Ext.getBody().createChild({
-            cls: 'x-textmetrics'
-        });
-        this.el = Ext.get(bindTo);
-        
-        measure.position('absolute');
-        measure.setLeftTop(-1000, -1000);
-        measure.hide();
-
-        if (fixedWidth) {
-           measure.setWidth(fixedWidth);
-        }
+    "right" : function(e){
+        this.moveRight(e.ctrlKey);
+    },
+    "enter" : function(e){
+        this.save();
     },
+    scope : this
+});
+</code></pre>
+ */
+Ext.define('Ext.util.KeyNav', {
     
-    /**
-     * Returns the size of the specified text based on the internal element's style and width properties
-     * @param {String} text The text to measure
-     * @return {Object} An object containing the text's size `{width: (width), height: (height)}`
+    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
+        }
+    },
+
+    /**
+     * Creates new KeyNav.
+     * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
+     * @param {Object} config The config
      */
-    getSize: function(text){
-        var measure = this.measure,
-            size;
-        
-        measure.update(text);
-        size = measure.getSize();
-        measure.update('');
-        return size;
+    constructor: function(el, config){
+        this.setConfig(el, config || {});
     },
     
     /**
-     * Binds this TextMetrics instance to a new element
-     * @param {Mixed} el The element
+     * Sets up a configuration for the KeyNav.
+     * @private
+     * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
+     * @param {Object} config A configuration object as specified in the constructor.
      */
-    bind: function(el){
-        var me = this;
+    setConfig: function(el, config) {
+        if (this.map) {
+            this.map.destroy();
+        }
         
-        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')
-        );
+        var map = Ext.create('Ext.util.KeyMap', el, null, this.getKeyEvent('forceKeyDown' in config ? config.forceKeyDown : this.forceKeyDown)),
+            keys = Ext.util.KeyNav.keyOptions,
+            scope = config.scope || this,
+            key;
+        
+        this.map = map;
+        for (key in keys) {
+            if (keys.hasOwnProperty(key)) {
+                if (config[key]) {
+                    map.addBinding({
+                        scope: scope,
+                        key: keys[key],
+                        handler: Ext.Function.bind(this.handleEvent, scope, [config[key]], true),
+                        defaultEventAction: config.defaultEventAction || this.defaultEventAction
+                    });
+                }
+            }
+        }
+        
+        map.disable();
+        if (!config.disabled) {
+            map.enable();
+        }
     },
     
     /**
-     * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
-     * to set a fixed width in order to accurately measure the text height.
-     * @param {Number} width The width to set on the element
+     * Method for filtering out the map argument
+     * @private
+     * @param {Ext.util.KeyMap} map
+     * @param {Ext.EventObject} event
+     * @param {Object} options Contains the handler to call
      */
-     setFixedWidth : function(width){
-         this.measure.setWidth(width);
-     },
-     
-     /**
-      * Returns the measured width of the specified text
-      * @param {String} text The text to measure
-      * @return {Number} width The width in pixels
-      */
-     getWidth : function(text){
-         this.measure.dom.style.width = 'auto';
-         return this.getSize(text).width;
-     },
-     
-     /**
-      * Returns the measured height of the specified text
-      * @param {String} text The text to measure
-      * @return {Number} height The height in pixels
-      */
-     getHeight : function(text){
-         return this.getSize(text).height;
-     },
-     
-     /**
-      * Destroy this instance
-      */
-     destroy: function(){
-         var me = this;
-         me.measure.remove();
-         delete me.el;
-         delete me.measure;
-     }
-}, function(){
-    Ext.core.Element.addMethods({
-        /**
-         * Returns the width in pixels of the passed text, or the width of the text in this Element.
-         * @param {String} text The text to measure. Defaults to the innerHTML of the element.
-         * @param {Number} min (optional) The minumum value to return.
-         * @param {Number} max (optional) The maximum value to return.
-         * @return {Number} The text width in pixels.
-         * @member Ext.core.Element
-         */
-        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);
-        }
-    });
-});
-
-/**
- * @class Ext.layout.container.boxOverflow.Scroller
- * @extends Ext.layout.container.boxOverflow.None
- * @private
- */
-Ext.define('Ext.layout.container.boxOverflow.Scroller', {
-
-    /* Begin Definitions */
-
-    extend: 'Ext.layout.container.boxOverflow.None',
-    requires: ['Ext.util.ClickRepeater', 'Ext.core.Element'],
-    alternateClassName: 'Ext.layout.boxOverflow.Scroller',
-    mixins: {
-        observable: 'Ext.util.Observable'
+    handleEvent: function(map, event, handler){
+        return handler.call(this, event);
     },
     
-    /* End Definitions */
-
     /**
-     * @cfg {Boolean} animateScroll
-     * True to animate the scrolling of items within the layout (defaults to true, ignored if enableScroll is false)
+     * @cfg {Boolean} disabled
+     * True to disable this KeyNav instance.
      */
-    animateScroll: false,
-
+    disabled: false,
+    
     /**
-     * @cfg {Number} scrollIncrement
-     * The number of pixels to scroll by on scroller click (defaults to 24)
+     * @cfg {String} defaultEventAction
+     * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key.  Valid values are
+     * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
+     * {@link Ext.EventObject#stopPropagation}.
      */
-    scrollIncrement: 20,
-
+    defaultEventAction: "stopEvent",
+    
     /**
-     * @cfg {Number} wheelIncrement
-     * The number of pixels to increment on mouse wheel scrolling (defaults to <tt>3</tt>).
+     * @cfg {Boolean} forceKeyDown
+     * Handle the keydown event instead of keypress.  KeyNav automatically does this for IE since
+     * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
+     * handle keydown instead of keypress.
      */
-    wheelIncrement: 10,
-
+    forceKeyDown: false,
+    
     /**
-     * @cfg {Number} scrollRepeatInterval
-     * Number of milliseconds between each scroll while a scroller button is held down (defaults to 20)
+     * Destroy this KeyNav (this is the same as calling disable).
+     * @param {Boolean} removeEl True to remove the element associated with this KeyNav.
      */
-    scrollRepeatInterval: 60,
+    destroy: function(removeEl){
+        this.map.destroy(removeEl);
+        delete this.map;
+    },
 
     /**
-     * @cfg {Number} scrollDuration
-     * Number of milliseconds that each scroll animation lasts (defaults to 400)
+     * Enable this KeyNav
      */
-    scrollDuration: 400,
+    enable: function() {
+        this.map.enable();
+        this.disabled = false;
+    },
 
     /**
-     * @cfg {String} beforeCtCls
-     * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
-     * which must always be present at the leftmost edge of the Container
+     * Disable this KeyNav
      */
-
+    disable: function() {
+        this.map.disable();
+        this.disabled = true;
+    },
+    
     /**
-     * @cfg {String} afterCtCls
-     * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
-     * which must always be present at the rightmost edge of the Container
+     * Convenience function for setting disabled/enabled by boolean.
+     * @param {Boolean} disabled
      */
-
+    setDisabled : function(disabled){
+        this.map.setDisabled(disabled);
+        this.disabled = disabled;
+    },
+    
     /**
-     * @cfg {String} scrollerCls
-     * CSS class added to both scroller elements if enableScroll is used
+     * Determines the event to bind to listen for keys. Depends on the {@link #forceKeyDown} setting,
+     * as well as the useKeyDown option on the EventManager.
+     * @return {String} The type of event to listen for.
      */
-    scrollerCls: Ext.baseCSSPrefix + 'box-scroller',
+    getKeyEvent: function(forceKeyDown){
+        return (forceKeyDown || Ext.EventManager.useKeyDown) ? 'keydown' : 'keypress';
+    }
+});
 
-    /**
-     * @cfg {String} beforeScrollerCls
-     * CSS class added to the left scroller element if enableScroll is used
-     */
+/**
+ * @class Ext.fx.Queue
+ * Animation Queue mixin to handle chaining and queueing by target.
+ * @private
+ */
 
-    /**
-     * @cfg {String} afterScrollerCls
-     * CSS class added to the right scroller element if enableScroll is used
-     */
-    
-    constructor: function(layout, config) {
-        this.layout = layout;
-        Ext.apply(this, config || {});
-        
-        this.addEvents(
-            /**
-             * @event scroll
-             * @param {Ext.layout.container.boxOverflow.Scroller} scroller The layout scroller
-             * @param {Number} newPosition The new position of the scroller
-             * @param {Boolean/Object} animate If animating or not. If true, it will be a animation configuration, else it will be false
-             */
-            'scroll'
-        );
+Ext.define('Ext.fx.Queue', {
+
+    requires: ['Ext.util.HashMap'],
+
+    constructor: function() {
+        this.targets = Ext.create('Ext.util.HashMap');
+        this.fxQueue = {};
     },
-    
-    initCSSClasses: function() {
-        var me = this,
-        layout = me.layout;
 
-        if (!me.CSSinitialized) {
-            me.beforeCtCls = me.beforeCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelBefore;
-            me.afterCtCls  = me.afterCtCls  || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelAfter;
-            me.beforeScrollerCls = me.beforeScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelBefore;
-            me.afterScrollerCls  = me.afterScrollerCls  || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelAfter;
-            me.CSSinitializes = true;
+    // @private
+    getFxDefaults: function(targetId) {
+        var target = this.targets.get(targetId);
+        if (target) {
+            return target.fxDefaults;
         }
+        return {};
     },
 
-    handleOverflow: function(calculations, targetSize) {
-        var me = this,
-            layout = me.layout,
-            methodName = 'get' + layout.parallelPrefixCap,
-            newSize = {};
-
-        me.initCSSClasses();
-        me.callParent(arguments);
-        this.createInnerElements();
-        this.showScrollers();
-        newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
-        newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - (me.beforeCt[methodName]() + me.afterCt[methodName]());
-        return { targetSize: newSize };
+    // @private
+    setFxDefaults: function(targetId, obj) {
+        var target = this.targets.get(targetId);
+        if (target) {
+            target.fxDefaults = Ext.apply(target.fxDefaults || {}, obj);
+        }
     },
 
-    /**
-     * @private
-     * Creates the beforeCt and afterCt elements if they have not already been created
-     */
-    createInnerElements: function() {
+    // @private
+    stopAnimation: function(targetId) {
         var me = this,
-            target = me.layout.getRenderTarget();
-
-        //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
-        //special items such as scrollers or dropdown menu triggers
-        if (!me.beforeCt) {
-            target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
-            me.beforeCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls}, 'before');
-            me.afterCt  = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls},  'after');
-            me.createWheelListener();
+            queue = me.getFxQueue(targetId),
+            ln = queue.length;
+        while (ln) {
+            queue[ln - 1].end();
+            ln--;
         }
     },
 
     /**
      * @private
-     * Sets up an listener to scroll on the layout's innerCt mousewheel event
+     * Returns current animation object if the element has any effects actively running or queued, else returns false.
      */
-    createWheelListener: function() {
-        this.layout.innerCt.on({
-            scope     : this,
-            mousewheel: function(e) {
-                e.stopEvent();
-
-                this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
-            }
-        });
+    getActiveAnimation: function(targetId) {
+        var queue = this.getFxQueue(targetId);
+        return (queue && !!queue.length) ? queue[0] : false;
     },
 
-    /**
-     * @private
-     */
-    clearOverflow: function() {
-        this.hideScrollers();
+    // @private
+    hasFxBlock: function(targetId) {
+        var queue = this.getFxQueue(targetId);
+        return queue && queue[0] && queue[0].block;
     },
 
-    /**
-     * @private
-     * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
-     * present. 
-     */
-    showScrollers: function() {
-        this.createScrollers();
-        this.beforeScroller.show();
-        this.afterScroller.show();
-        this.updateScrollButtons();
-        
-        this.layout.owner.addClsWithUI('scroller');
-    },
+    // @private get fx queue for passed target, create if needed.
+    getFxQueue: function(targetId) {
+        if (!targetId) {
+            return false;
+        }
+        var me = this,
+            queue = me.fxQueue[targetId],
+            target = me.targets.get(targetId);
 
-    /**
-     * @private
-     * Hides the scroller elements in the beforeCt and afterCt
-     */
-    hideScrollers: function() {
-        if (this.beforeScroller != undefined) {
-            this.beforeScroller.hide();
-            this.afterScroller.hide();
-            
-            this.layout.owner.removeClsWithUI('scroller');
+        if (!target) {
+            return false;
+        }
+
+        if (!queue) {
+            me.fxQueue[targetId] = [];
+            // GarbageCollector will need to clean up Elements since they aren't currently observable
+            if (target.type != 'element') {
+                target.target.on('destroy', function() {
+                    me.fxQueue[targetId] = [];
+                });
+            }
         }
+        return me.fxQueue[targetId];
     },
 
-    /**
-     * @private
-     * Creates the clickable scroller elements and places them into the beforeCt and afterCt
-     */
-    createScrollers: function() {
-        if (!this.beforeScroller && !this.afterScroller) {
-            var before = this.beforeCt.createChild({
-                cls: Ext.String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls)
-            });
+    // @private
+    queueFx: function(anim) {
+        var me = this,
+            target = anim.target,
+            queue, ln;
 
-            var after = this.afterCt.createChild({
-                cls: Ext.String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls)
-            });
+        if (!target) {
+            return;
+        }
 
-            before.addClsOnOver(this.beforeScrollerCls + '-hover');
-            after.addClsOnOver(this.afterScrollerCls + '-hover');
+        queue = me.getFxQueue(target.getId());
+        ln = queue.length;
 
-            before.setVisibilityMode(Ext.core.Element.DISPLAY);
-            after.setVisibilityMode(Ext.core.Element.DISPLAY);
+        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);
+    }
+});
+/**
+ * @class Ext.fx.target.Target
 
-            this.beforeRepeater = Ext.create('Ext.util.ClickRepeater', before, {
-                interval: this.scrollRepeatInterval,
-                handler : this.scrollLeft,
-                scope   : this
-            });
+This class specifies a generic target for an animation. It provides a wrapper around a
+series of different types of objects to allow for a generic animation API.
+A target can be a single object or a Composite object containing other objects that are 
+to be animated. This class and it's subclasses are generally not created directly, the 
+underlying animation will create the appropriate Ext.fx.target.Target object by passing 
+the instance to be animated.
 
-            this.afterRepeater = Ext.create('Ext.util.ClickRepeater', after, {
-                interval: this.scrollRepeatInterval,
-                handler : this.scrollRight,
-                scope   : this
-            });
+The following types of objects can be animated:
 
-            /**
-             * @property beforeScroller
-             * @type Ext.core.Element
-             * The left scroller element. Only created when needed.
-             */
-            this.beforeScroller = before;
+- {@link Ext.fx.target.Component Components}
+- {@link Ext.fx.target.Element Elements}
+- {@link Ext.fx.target.Sprite Sprites}
 
-            /**
-             * @property afterScroller
-             * @type Ext.core.Element
-             * The left scroller element. Only created when needed.
-             */
-            this.afterScroller = after;
-        }
-    },
+ * @markdown
+ * @abstract
+ */
+Ext.define('Ext.fx.target.Target', {
 
-    /**
-     * @private
-     */
-    destroy: function() {
-        Ext.destroy(this.beforeRepeater, this.afterRepeater, this.beforeScroller, this.afterScroller, this.beforeCt, this.afterCt);
-    },
+    isAnimTarget: true,
 
     /**
-     * @private
-     * Scrolls left or right by the number of pixels specified
-     * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
+     * Creates new Target.
+     * @param {Ext.Component/Ext.Element/Ext.draw.Sprite} target The object to be animated
      */
-    scrollBy: function(delta, animate) {
-        this.scrollTo(this.getScrollPosition() + delta, animate);
+    constructor: function(target) {
+        this.target = target;
+        this.id = this.getId();
     },
+    
+    getId: function() {
+        return this.target.id;
+    }
+});
 
-    /**
-     * @private
-     * @return {Object} Object passed to scrollTo when scrolling
-     */
-    getScrollAnim: function() {
-        return {
-            duration: this.scrollDuration, 
-            callback: this.updateScrollButtons, 
-            scope   : this
-        };
-    },
+/**
+ * @class Ext.fx.target.Sprite
+ * @extends Ext.fx.target.Target
 
-    /**
-     * @private
-     * Enables or disables each scroller button based on the current scroll position
-     */
-    updateScrollButtons: function() {
-        if (this.beforeScroller == undefined || this.afterScroller == undefined) {
-            return;
-        }
+This class represents a animation target for a {@link Ext.draw.Sprite}. In general this class will not be
+created directly, the {@link Ext.draw.Sprite} will be passed to the animation and
+and the appropriate target will be created.
 
-        var beforeMeth = this.atExtremeBefore()  ? 'addCls' : 'removeCls',
-            afterMeth  = this.atExtremeAfter() ? 'addCls' : 'removeCls',
-            beforeCls  = this.beforeScrollerCls + '-disabled',
-            afterCls   = this.afterScrollerCls  + '-disabled';
-        
-        this.beforeScroller[beforeMeth](beforeCls);
-        this.afterScroller[afterMeth](afterCls);
-        this.scrolling = false;
-    },
+ * @markdown
+ */
 
-    /**
-     * @private
-     * Returns true if the innerCt scroll is already at its left-most point
-     * @return {Boolean} True if already at furthest left point
-     */
-    atExtremeBefore: function() {
-        return this.getScrollPosition() === 0;
-    },
+Ext.define('Ext.fx.target.Sprite', {
 
-    /**
-     * @private
-     * Scrolls to the left by the configured amount
-     */
-    scrollLeft: function() {
-        this.scrollBy(-this.scrollIncrement, false);
+    /* Begin Definitions */
+
+    extend: 'Ext.fx.target.Target',
+
+    /* End Definitions */
+
+    type: 'draw',
+
+    getFromPrim: function(sprite, attr) {
+        var o;
+        if (attr == 'translate') {
+            o = {
+                x: sprite.attr.translation.x || 0,
+                y: sprite.attr.translation.y || 0
+            };
+        }
+        else if (attr == 'rotate') {
+            o = {
+                degrees: sprite.attr.rotation.degrees || 0,
+                x: sprite.attr.rotation.x,
+                y: sprite.attr.rotation.y
+            };
+        }
+        else {
+            o = sprite.attr[attr];
+        }
+        return o;
     },
 
-    /**
-     * @private
-     * Scrolls to the right by the configured amount
-     */
-    scrollRight: function() {
-        this.scrollBy(this.scrollIncrement, false);
+    getAttr: function(attr, val) {
+        return [[this.target, val != undefined ? val : this.getFromPrim(this.target, attr)]];
     },
 
-    /**
-     * Returns the current scroll position of the innerCt element
-     * @return {Number} The current scroll position
-     */
-    getScrollPosition: function(){
-        var layout = this.layout;
-        return parseInt(layout.innerCt.dom['scroll' + layout.parallelBeforeCap], 10) || 0;
+    setAttr: function(targetData) {
+        var ln = targetData.length,
+            spriteArr = [],
+            attrs, attr, attrArr, attPtr, spritePtr, idx, value, i, j, x, y, ln2;
+        for (i = 0; i < ln; i++) {
+            attrs = targetData[i].attrs;
+            for (attr in attrs) {
+                attrArr = attrs[attr];
+                ln2 = attrArr.length;
+                for (j = 0; j < ln2; j++) {
+                    spritePtr = attrArr[j][0];
+                    attPtr = attrArr[j][1];
+                    if (attr === 'translate') {
+                        value = {
+                            x: attPtr.x,
+                            y: attPtr.y
+                        };
+                    }
+                    else if (attr === 'rotate') {
+                        x = attPtr.x;
+                        if (isNaN(x)) {
+                            x = null;
+                        }
+                        y = attPtr.y;
+                        if (isNaN(y)) {
+                            y = null;
+                        }
+                        value = {
+                            degrees: attPtr.degrees,
+                            x: x,
+                            y: y
+                        };
+                    }
+                    else if (attr === 'width' || attr === 'height' || attr === 'x' || attr === 'y') {
+                        value = parseFloat(attPtr);
+                    }
+                    else {
+                        value = attPtr;
+                    }
+                    idx = Ext.Array.indexOf(spriteArr, spritePtr);
+                    if (idx == -1) {
+                        spriteArr.push([spritePtr, {}]);
+                        idx = spriteArr.length - 1;
+                    }
+                    spriteArr[idx][1][attr] = value;
+                }
+            }
+        }
+        ln = spriteArr.length;
+        for (i = 0; i < ln; i++) {
+            spritePtr = spriteArr[i];
+            spritePtr[0].setAttributes(spritePtr[1]);
+        }
+        this.target.redraw();
+    }
+});
+
+/**
+ * @class Ext.fx.target.CompositeSprite
+ * @extends Ext.fx.target.Sprite
+
+This class represents a animation target for a {@link Ext.draw.CompositeSprite}. It allows
+each {@link Ext.draw.Sprite} in the group to be animated as a whole. In general this class will not be
+created directly, the {@link Ext.draw.CompositeSprite} will be passed to the animation and
+and the appropriate target will be created.
+
+ * @markdown
+ */
+
+Ext.define('Ext.fx.target.CompositeSprite', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.fx.target.Sprite',
+
+    /* End Definitions */
+
+    getAttr: function(attr, val) {
+        var out = [],
+            target = this.target;
+        target.each(function(sprite) {
+            out.push([sprite, val != undefined ? val : this.getFromPrim(sprite, attr)]);
+        }, this);
+        return out;
+    }
+});
+
+/**
+ * @class Ext.fx.target.Component
+ * @extends Ext.fx.target.Target
+ * 
+ * This class represents a animation target for a {@link Ext.Component}. In general this class will not be
+ * created directly, the {@link Ext.Component} will be passed to the animation and
+ * and the appropriate target will be created.
+ */
+Ext.define('Ext.fx.target.Component', {
+
+    /* Begin Definitions */
+   
+    extend: 'Ext.fx.target.Target',
+    
+    /* End Definitions */
+
+    type: 'component',
+
+    // Methods to call to retrieve unspecified "from" values from a target 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');
+        }
     },
 
-    /**
-     * @private
-     * Returns the maximum value we can scrollTo
-     * @return {Number} The max scroll value
-     */
-    getMaxScrollPosition: function() {
-        var layout = this.layout;
-        return layout.innerCt.dom['scroll' + layout.parallelPrefixCap] - this.layout.innerCt['get' + layout.parallelPrefixCap]();
+    compMethod: {
+        top: 'setPosition',
+        left: 'setPosition',
+        x: 'setPagePosition',
+        y: 'setPagePosition',
+        height: 'setSize',
+        width: 'setSize',
+        opacity: 'setOpacity'
     },
 
-    /**
-     * @private
-     * Returns true if the innerCt scroll is already at its right-most point
-     * @return {Boolean} True if already at furthest right point
-     */
-    atExtremeAfter: function() {
-        return this.getScrollPosition() >= this.getMaxScrollPosition();
+    // Read the named attribute from the target Component. Use the defined getter for the attribute
+    getAttr: function(attr, val) {
+        return [[this.target, val !== undefined ? val : this.getPropMethod[attr].call(this.target)]];
     },
 
-    /**
-     * @private
-     * Scrolls to the given position. Performs bounds checking.
-     * @param {Number} position The position to scroll to. This is constrained.
-     * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
-     */
-    scrollTo: function(position, animate) {
+    setAttr: function(targetData, isFirstFrame, isLastFrame) {
         var me = this,
-            layout = me.layout,
-            oldPosition = me.getScrollPosition(),
-            newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition());
+            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];
+                    // We REALLY want a single function call, so push these down to merge them: eg
+                    // meth.setPagePosition.target = <targetComponent>
+                    // meth.setPagePosition['x'] = 100
+                    // meth.setPagePosition['y'] = 100
+                    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 : parseInt(o.left, 10);
+                    top = (o.top === undefined) ? undefined : parseInt(o.top, 10);
+                    o.target.setPosition(left, top);
+                }
+                if (meth.setPagePosition.target) {
+                    o = meth.setPagePosition;
+                    o.target.setPagePosition(o.x, o.y);
+                }
+                if (meth.setSize.target && meth.setSize.target.el) {
+                    o = meth.setSize;
+                    // Dimensions not being animated MUST NOT be autosized. They must remain at current value.
+                    w = (o.width === undefined) ? o.target.getWidth() : parseInt(o.width, 10);
+                    h = (o.height === undefined) ? o.target.getHeight() : parseInt(o.height, 10);
 
-        if (newPosition != oldPosition && !me.scrolling) {
-            if (animate == undefined) {
-                animate = me.animateScroll;
-            }
+                    // Only set the size of the Component on the last frame, or if the animation was
+                    // configured with dynamic: true.
+                    // In other cases, we just set the target element size.
+                    // This will result in either clipping if animating a reduction in size, or the revealing of
+                    // the inner elements of the Component if animating an increase in size.
+                    // Component's animate function initially resizes to the larger size before resizing the
+                    // outer element to clip the contents.
+                    if (isLastFrame || me.dynamic) {
+                        o.target.componentLayout.childrenChanged = true;
 
-            layout.innerCt.scrollTo(layout.parallelBefore, newPosition, animate ? me.getScrollAnim() : false);
-            if (animate) {
-                me.scrolling = true;
-            } else {
-                me.scrolling = false;
-                me.updateScrollButtons();
+                        // Flag if we are being called by an animating layout: use setCalculatedSize
+                        if (me.layoutAnimation) {
+                            o.target.setCalculatedSize(w, h);
+                        } else {
+                            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);
+                }
             }
-            
-            me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false);
         }
-    },
+    }
+});
 
-    /**
-     * Scrolls to the given component.
-     * @param {String|Number|Ext.Component} item The item to scroll to. Can be a numerical index, component id 
-     * or a reference to the component itself.
-     * @param {Boolean} animate True to animate the scrolling
-     */
-    scrollToItem: function(item, animate) {
-        var me = this,
-            layout = me.layout,
-            visibility,
-            box,
-            newPos;
+/**
+ * @class Ext.fx.CubicBezier
+ * @ignore
+ */
+Ext.define('Ext.fx.CubicBezier', {
 
-        item = me.getItem(item);
-        if (item != undefined) {
-            visibility = this.getItemVisibility(item);
-            if (!visibility.fullyVisible) {
-                box  = item.getBox(true, true);
-                newPos = box[layout.parallelPosition];
-                if (visibility.hiddenEnd) {
-                    newPos -= (this.layout.innerCt['get' + layout.parallelPrefixCap]() - box[layout.parallelPrefix]);
+    /* Begin Definitions */
+
+    singleton: true,
+
+    /* End Definitions */
+
+    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;
                 }
-                this.scrollTo(newPos, animate);
+                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));
     },
 
-    /**
-     * @private
-     * For a given item in the container, return an object with information on whether the item is visible
-     * with the current innerCt scroll value.
-     * @param {Ext.Component} item The item
-     * @return {Object} Values for fullyVisible, hiddenStart and hiddenEnd
-     */
-    getItemVisibility: function(item) {
-        var me          = this,
-            box         = me.getItem(item).getBox(true, true),
-            layout      = me.layout,
-            itemStart   = box[layout.parallelPosition],
-            itemEnd     = itemStart + box[layout.parallelPrefix],
-            scrollStart = me.getScrollPosition(),
-            scrollEnd   = scrollStart + layout.innerCt['get' + layout.parallelPrefixCap]();
-
-        return {
-            hiddenStart : itemStart < scrollStart,
-            hiddenEnd   : itemEnd > scrollEnd,
-            fullyVisible: itemStart > scrollStart && itemEnd < scrollEnd
+    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;
     }
 });
 /**
- * @class Ext.util.Offset
- * @ignore
+ * Represents an RGB color and provides helper functions get
+ * color components in HSL color space.
  */
-Ext.define('Ext.util.Offset', {
+Ext.define('Ext.draw.Color', {
 
     /* Begin Definitions */
 
-    statics: {
-        fromObject: function(obj) {
-            return new this(obj.x, obj.y);
-        }
-    },
-
     /* End Definitions */
 
-    constructor: function(x, y) {
-        this.x = (x != null && !isNaN(x)) ? x : 0;
-        this.y = (y != null && !isNaN(y)) ? y : 0;
+    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*/,
 
-        return this;
-    },
+    /**
+     * @cfg {Number} lightnessFactor
+     *
+     * The default factor to compute the lighter or darker color. Defaults to 0.2.
+     */
+    lightnessFactor: 0.2,
 
-    copy: function() {
-        return new Ext.util.Offset(this.x, this.y);
+    /**
+     * Creates new Color.
+     * @param {Number} red Red component (0..255)
+     * @param {Number} green Green component (0..255)
+     * @param {Number} blue Blue component (0..255)
+     */
+    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);
     },
 
-    copyFrom: function(p) {
-        this.x = p.x;
-        this.y = p.y;
+    /**
+     * Get the red component of the color, in the range 0..255.
+     * @return {Number}
+     */
+    getRed: function() {
+        return this.r;
     },
 
-    toString: function() {
-        return "Offset[" + this.x + "," + this.y + "]";
+    /**
+     * Get the green component of the color, in the range 0..255.
+     * @return {Number}
+     */
+    getGreen: function() {
+        return this.g;
     },
 
-    equals: function(offset) {
-        //<debug>
-        if(!(offset instanceof this.statics())) {
-            Ext.Error.raise('Offset must be an instance of Ext.util.Offset');
-        }
-        //</debug>
-
-        return (this.x == offset.x && this.y == offset.y);
+    /**
+     * Get the blue component of the color, in the range 0..255.
+     * @return {Number}
+     */
+    getBlue: function() {
+        return this.b;
     },
 
-    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);
-        }
+    /**
+     * Get the RGB values.
+     * @return {Number[]}
+     */
+    getRGB: function() {
+        var me = this;
+        return [me.r, me.g, me.b];
     },
 
-    isZero: function() {
-        return this.x == 0 && this.y == 0;
-    }
-});
+    /**
+     * Get the equivalent HSL components of the color.
+     * @return {Number[]}
+     */
+    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);
 
-/**
- * @class Ext.util.KeyNav
- * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
- * navigation keys to function calls that will get called when the keys are pressed, providing an easy
- * way to implement custom navigation schemes for any UI component.</p>
- * <p>The following are all of the possible keys that can be implemented: enter, space, left, right, up, down, tab, esc,
- * pageUp, pageDown, del, backspace, home, end.  Usage:</p>
- <pre><code>
-var nav = new Ext.util.KeyNav("my-element", {
-    "left" : function(e){
-        this.moveLeft(e.ctrlKey);
-    },
-    "right" : function(e){
-        this.moveRight(e.ctrlKey);
+        // min==max means achromatic (hue is undefined)
+        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];
     },
-    "enter" : function(e){
-        this.save();
+
+    /**
+     * Return a new color that is lighter than this color.
+     * @param {Number} factor Lighter factor (0..1), default to 0.2
+     * @return Ext.draw.Color
+     */
+    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]);
     },
-    scope : this
-});
-</code></pre>
- */
-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
-        }
+
+    /**
+     * Return a new color that is darker than this color.
+     * @param {Number} factor Darker factor (0..1), default to 0.2
+     * @return Ext.draw.Color
+     */
+    getDarker: function(factor) {
+        factor = factor || this.lightnessFactor;
+        return this.getLighter(-factor);
     },
 
     /**
-     * Creates new KeyNav.
-     * @param {Mixed} el The element to bind to
-     * @param {Object} config The config
+     * Return the color in the hex format, i.e. '#rrggbb'.
+     * @return {String}
      */
-    constructor: function(el, config){
-        this.setConfig(el, config || {});
+    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('');
     },
-    
+
     /**
-     * Sets up a configuration for the KeyNav.
-     * @private
-     * @param {Mixed} el The element to bind to
-     * @param {Object}A configuration object as specified in the constructor.
+     * Convert a color to hexadecimal format.
+     *
+     * **Note:** This method is both static and instance.
+     *
+     * @param {String/String[]} color The color value (i.e 'rgb(255, 255, 255)', 'color: #ffffff').
+     * Can also be an Array, in this case the function handles the first member.
+     * @returns {String} The color in hexadecimal format.
+     * @static
      */
-    setConfig: function(el, config) {
-        if (this.map) {
-            this.map.destroy();
+    toHex: function(color) {
+        if (Ext.isArray(color)) {
+            color = color[0];
         }
-        
-        var map = Ext.create('Ext.util.KeyMap', el, null, this.getKeyEvent('forceKeyDown' in config ? config.forceKeyDown : this.forceKeyDown)),
-            keys = Ext.util.KeyNav.keyOptions,
-            scope = config.scope || this,
-            key;
-        
-        this.map = map;
-        for (key in keys) {
-            if (keys.hasOwnProperty(key)) {
-                if (config[key]) {
-                    map.addBinding({
-                        scope: scope,
-                        key: keys[key],
-                        handler: Ext.Function.bind(this.handleEvent, scope, [config[key]], true),
-                        defaultEventAction: config.defaultEventAction || this.defaultEventAction
-                    });
+        if (!Ext.isString(color)) {
+            return '';
+        }
+        if (color.substr(0, 1) === '#') {
+            return color;
+        }
+        var digits = this.colorToHexRe.exec(color);
+
+        if (Ext.isArray(digits)) {
+            var 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 '';
+        }
+    },
+
+    /**
+     * Parse the string and create a new color.
+     *
+     * Supported formats: '#rrggbb', '#rgb', and 'rgb(r,g,b)'.
+     *
+     * If the string is not recognized, an undefined will be returned instead.
+     *
+     * **Note:** This method is both static and instance.
+     *
+     * @param {String} str Color in string.
+     * @returns Ext.draw.Color
+     * @static
+     */
+    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);
                 }
             }
         }
-        
-        map.disable();
-        if (!config.disabled) {
-            map.enable();
+        else {
+            values = str.match(this.rgbRe);
+            if (values) {
+                r = values[1];
+                g = values[2];
+                b = values[3];
+            }
         }
+
+        return (typeof r == 'undefined') ? undefined : Ext.create('Ext.draw.Color', r, g, b);
     },
-    
+
     /**
-     * Method for filtering out the map argument
-     * @private
-     * @param {Ext.util.KeyMap} map
-     * @param {Ext.EventObject} event
-     * @param {Object} options Contains the handler to call
+     * Returns the gray value (0 to 255) of the color.
+     *
+     * The gray value is calculated using the formula r*0.3 + g*0.59 + b*0.11.
+     *
+     * @returns {Number}
      */
-    handleEvent: function(map, event, handler){
-        return handler.call(this, event);
+    getGrayscale: function() {
+        // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
+        return this.r * 0.3 + this.g * 0.59 + this.b * 0.11;
     },
-    
+
     /**
-     * @cfg {Boolean} disabled
-     * True to disable this KeyNav instance (defaults to false)
+     * Create a new color based on the specified HSL values.
+     *
+     * **Note:** This method is both static and instance.
+     *
+     * @param {Number} h Hue component (0..359)
+     * @param {Number} s Saturation component (0..1)
+     * @param {Number} l Lightness component (0..1)
+     * @returns Ext.draw.Color
+     * @static
      */
-    disabled: false,
-    
+    fromHSL: function(h, s, l) {
+        var C, X, m, i, rgb = [],
+            abs = Math.abs,
+            floor = Math.floor;
+
+        if (s == 0 || h == null) {
+            // achromatic
+            rgb = [l, l, l];
+        }
+        else {
+            // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL
+            // C is the chroma
+            // X is the second largest component
+            // m is the lightness adjustment
+            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 Ext.create('Ext.draw.Color', rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
+    }
+}, function() {
+    var prototype = this.prototype;
+
+    //These functions are both static and instance. TODO: find a more elegant way of copying them
+    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);
+        }
+    });
+});
+
+/**
+ * @class Ext.dd.StatusProxy
+ * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair.  This is the
+ * default drag proxy used by all Ext.dd components.
+ */
+Ext.define('Ext.dd.StatusProxy', {
+    animRepair: false,
+
     /**
-     * @cfg {String} defaultEventAction
-     * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key.  Valid values are
-     * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
-     * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent')
+     * Creates new StatusProxy.
+     * @param {Object} config (optional) Config object.
      */
-    defaultEventAction: "stopEvent",
-    
+    constructor: function(config){
+        Ext.apply(this, config);
+        this.id = this.id || Ext.id();
+        this.proxy = Ext.createWidget('component', {
+            floating: true,
+            stateful: false,
+            id: this.id,
+            html: '<div class="' + Ext.baseCSSPrefix + 'dd-drop-icon"></div>' +
+                  '<div class="' + Ext.baseCSSPrefix + 'dd-drag-ghost"></div>',
+            cls: Ext.baseCSSPrefix + 'dd-drag-proxy ' + this.dropNotAllowed,
+            shadow: !config || config.shadow !== false,
+            renderTo: document.body
+        });
+
+        this.el = this.proxy.el;
+        this.el.show();
+        this.el.setVisibilityMode(Ext.Element.VISIBILITY);
+        this.el.hide();
+
+        this.ghost = Ext.get(this.el.dom.childNodes[1]);
+        this.dropStatus = this.dropNotAllowed;
+    },
     /**
-     * @cfg {Boolean} forceKeyDown
-     * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
-     * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
-     * handle keydown instead of keypress.
+     * @cfg {String} [dropAllowed="x-dd-drop-ok"]
+     * The CSS class to apply to the status element when drop is allowed.
      */
-    forceKeyDown: false,
-    
+    dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',
     /**
-     * Destroy this KeyNav (this is the same as calling disable).
-     * @param {Boolean} removeEl True to remove the element associated with this KeyNav.
+     * @cfg {String} [dropNotAllowed="x-dd-drop-nodrop"]
+     * The CSS class to apply to the status element when drop is not allowed.
      */
-    destroy: function(removeEl){
-        this.map.destroy(removeEl);
-        delete this.map;
-    },
+    dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',
 
     /**
-     * Enable this KeyNav
+     * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
+     * over the current target element.
+     * @param {String} cssClass The css class for the new drop status indicator image
      */
-    enable: function() {
-        this.map.enable();
-        this.disabled = false;
+    setStatus : function(cssClass){
+        cssClass = cssClass || this.dropNotAllowed;
+        if(this.dropStatus != cssClass){
+            this.el.replaceCls(this.dropStatus, cssClass);
+            this.dropStatus = cssClass;
+        }
     },
 
     /**
-     * Disable this KeyNav
+     * Resets the status indicator to the default dropNotAllowed value
+     * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
      */
-    disable: function() {
-        this.map.disable();
-        this.disabled = true;
+    reset : function(clearGhost){
+        this.el.dom.className = Ext.baseCSSPrefix + 'dd-drag-proxy ' + this.dropNotAllowed;
+        this.dropStatus = this.dropNotAllowed;
+        if(clearGhost){
+            this.ghost.update("");
+        }
     },
-    
+
     /**
-     * Convenience function for setting disabled/enabled by boolean.
-     * @param {Boolean} disabled
+     * Updates the contents of the ghost element
+     * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a
+     * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).
      */
-    setDisabled : function(disabled){
-        this.map.setDisabled(disabled);
-        this.disabled = disabled;
+    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');
+        }
     },
-    
-    /**
-     * Determines the event to bind to listen for keys. Depends on the {@link #forceKeyDown} setting,
-     * as well as the useKeyDown option on the EventManager.
-     * @return {String} The type of event to listen for.
-     */
-    getKeyEvent: function(forceKeyDown){
-        return (forceKeyDown || Ext.EventManager.useKeyDown) ? 'keydown' : 'keypress';
-    }
-});
 
-/**
- * @class Ext.fx.Queue
- * Animation Queue mixin to handle chaining and queueing by target.
- * @private
- */
-
-Ext.define('Ext.fx.Queue', {
-
-    requires: ['Ext.util.HashMap'],
-
-    constructor: function() {
-        this.targets = Ext.create('Ext.util.HashMap');
-        this.fxQueue = {};
+    /**
+     * Returns the underlying proxy {@link Ext.Layer}
+     * @return {Ext.Layer} el
+    */
+    getEl : function(){
+        return this.el;
     },
 
-    // @private
-    getFxDefaults: function(targetId) {
-        var target = this.targets.get(targetId);
-        if (target) {
-            return target.fxDefaults;
-        }
-        return {};
+    /**
+     * Returns the ghost element
+     * @return {Ext.Element} el
+     */
+    getGhost : function(){
+        return this.ghost;
     },
 
-    // @private
-    setFxDefaults: function(targetId, obj) {
-        var target = this.targets.get(targetId);
-        if (target) {
-            target.fxDefaults = Ext.apply(target.fxDefaults || {}, obj);
+    /**
+     * Hides the proxy
+     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
+     */
+    hide : function(clear) {
+        this.proxy.hide();
+        if (clear) {
+            this.reset(true);
         }
     },
 
-    // @private
-    stopAnimation: function(targetId) {
-        var me = this,
-            queue = me.getFxQueue(targetId),
-            ln = queue.length;
-        while (ln) {
-            queue[ln - 1].end();
-            ln--;
+    /**
+     * Stops the repair animation if it's currently running
+     */
+    stop : function(){
+        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
+            this.anim.stop();
         }
     },
 
     /**
-     * @private
-     * Returns current animation object if the element has any effects actively running or queued, else returns false.
+     * Displays this proxy
      */
-    getActiveAnimation: function(targetId) {
-        var queue = this.getFxQueue(targetId);
-        return (queue && !!queue.length) ? queue[0] : false;
+    show : function() {
+        this.proxy.show();
+        this.proxy.toFront();
     },
 
-    // @private
-    hasFxBlock: function(targetId) {
-        var queue = this.getFxQueue(targetId);
-        return queue && queue[0] && queue[0].block;
+    /**
+     * Force the Layer to sync its shadow and shim positions to the element
+     */
+    sync : function(){
+        this.proxy.el.sync();
     },
 
-    // @private get fx queue for passed target, create if needed.
-    getFxQueue: function(targetId) {
-        if (!targetId) {
-            return false;
+    /**
+     * Causes the proxy to return to its position of origin via an animation.  Should be called after an
+     * invalid drop operation by the item being dragged.
+     * @param {Number[]} xy The XY position of the element ([x, y])
+     * @param {Function} callback The function to call after the repair is complete.
+     * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
+     */
+    repair : function(xy, callback, scope){
+        this.callback = callback;
+        this.scope = scope;
+        if (xy && this.animRepair !== false) {
+            this.el.addCls(Ext.baseCSSPrefix + 'dd-drag-repair');
+            this.el.hideUnders(true);
+            this.anim = this.el.animate({
+                duration: this.repairDuration || 500,
+                easing: 'ease-out',
+                to: {
+                    x: xy[0],
+                    y: xy[1]
+                },
+                stopAnimation: true,
+                callback: this.afterRepair,
+                scope: this
+            });
+        } else {
+            this.afterRepair();
         }
-        var me = this,
-            queue = me.fxQueue[targetId],
-            target = me.targets.get(targetId);
+    },
 
-        if (!target) {
-            return false;
+    // private
+    afterRepair : function(){
+        this.hide(true);
+        if(typeof this.callback == "function"){
+            this.callback.call(this.scope || this);
         }
+        this.callback = null;
+        this.scope = null;
+    },
 
-        if (!queue) {
-            me.fxQueue[targetId] = [];
-            // GarbageCollector will need to clean up Elements since they aren't currently observable
-            if (target.type != 'element') {
-                target.target.on('destroy', function() {
-                    me.fxQueue[targetId] = [];
-                });
-            }
-        }
-        return me.fxQueue[targetId];
-    },
-
-    // @private
-    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);
+    destroy: function(){
+        Ext.destroy(this.ghost, this.proxy, this.el);
     }
 });
 /**
- * @class Ext.fx.target.Target
-
-This class specifies a generic target for an animation. It provides a wrapper around a
-series of different types of objects to allow for a generic animation API.
-A target can be a single object or a Composite object containing other objects that are 
-to be animated. This class and it's subclasses are generally not created directly, the 
-underlying animation will create the appropriate Ext.fx.target.Target object by passing 
-the instance to be animated.
-
-The following types of objects can be animated:
-
-- {@link Ext.fx.target.Component Components}
-- {@link Ext.fx.target.Element Elements}
-- {@link Ext.fx.target.Sprite Sprites}
-
- * @markdown
- * @abstract
+ * A custom drag proxy implementation specific to {@link Ext.panel.Panel}s. This class
+ * is primarily used internally for the Panel's drag drop implementation, and
+ * should never need to be created directly.
+ * @private
  */
-Ext.define('Ext.fx.target.Target', {
+Ext.define('Ext.panel.Proxy', {
 
-    isAnimTarget: true,
+    alternateClassName: 'Ext.dd.PanelProxy',
 
     /**
-     * Creates new Target.
-     * @param {Mixed} target The object to be animated
+     * Creates new panel proxy.
+     * @param {Ext.panel.Panel} panel The {@link Ext.panel.Panel} to proxy for
+     * @param {Object} [config] Config object
      */
-    constructor: function(target) {
-        this.target = target;
-        this.id = this.getId();
+    constructor: function(panel, config){
+        /**
+         * @property panel
+         * @type Ext.panel.Panel
+         */
+        this.panel = panel;
+        this.id = this.panel.id +'-ddproxy';
+        Ext.apply(this, config);
     },
-    
-    getId: function() {
-        return this.target.id;
-    }
-});
-
-/**
- * @class Ext.fx.target.Sprite
- * @extends Ext.fx.target.Target
-
-This class represents a animation target for a {@link Ext.draw.Sprite}. In general this class will not be
-created directly, the {@link Ext.draw.Sprite} will be passed to the animation and
-and the appropriate target will be created.
 
- * @markdown
- */
+    /**
+     * @cfg {Boolean} insertProxy
+     * True to insert a placeholder proxy element while dragging the panel, false to drag with no proxy.
+     * Most Panels are not absolute positioned and therefore we need to reserve this space.
+     */
+    insertProxy: true,
 
-Ext.define('Ext.fx.target.Sprite', {
+    // private overrides
+    setStatus: Ext.emptyFn,
+    reset: Ext.emptyFn,
+    update: Ext.emptyFn,
+    stop: Ext.emptyFn,
+    sync: Ext.emptyFn,
 
-    /* Begin Definitions */
+    /**
+     * Gets the proxy's element
+     * @return {Ext.Element} The proxy's element
+     */
+    getEl: function(){
+        return this.ghost.el;
+    },
 
-    extend: 'Ext.fx.target.Target',
+    /**
+     * Gets the proxy's ghost Panel
+     * @return {Ext.panel.Panel} The proxy's ghost Panel
+     */
+    getGhost: function(){
+        return this.ghost;
+    },
 
-    /* End Definitions */
+    /**
+     * Gets the proxy element. This is the element that represents where the
+     * Panel was before we started the drag operation.
+     * @return {Ext.Element} The proxy's element
+     */
+    getProxy: function(){
+        return this.proxy;
+    },
 
-    type: 'draw',
+    /**
+     * Hides the proxy
+     */
+    hide : function(){
+        if (this.ghost) {
+            if (this.proxy) {
+                this.proxy.remove();
+                delete this.proxy;
+            }
 
-    getFromPrim: function(sprite, attr) {
-        var o;
-        if (attr == 'translate') {
-            o = {
-                x: sprite.attr.translation.x || 0,
-                y: sprite.attr.translation.y || 0
-            };
-        }
-        else if (attr == 'rotate') {
-            o = {
-                degrees: sprite.attr.rotation.degrees || 0,
-                x: sprite.attr.rotation.x,
-                y: sprite.attr.rotation.y
-            };
-        }
-        else {
-            o = sprite.attr[attr];
+            // Unghost the Panel, do not move the Panel to where the ghost was
+            this.panel.unghost(null, false);
+            delete this.ghost;
         }
-        return o;
     },
 
-    getAttr: function(attr, val) {
-        return [[this.target, val != undefined ? val : this.getFromPrim(this.target, attr)]];
+    /**
+     * Shows the proxy
+     */
+    show: function(){
+        if (!this.ghost) {
+            var panelSize = this.panel.getSize();
+            this.panel.el.setVisibilityMode(Ext.Element.DISPLAY);
+            this.ghost = this.panel.ghost();
+            if (this.insertProxy) {
+                // bc Panels aren't absolute positioned we need to take up the space
+                // of where the panel previously was
+                this.proxy = this.panel.el.insertSibling({cls: Ext.baseCSSPrefix + 'panel-dd-spacer'});
+                this.proxy.setSize(panelSize);
+            }
+        }
     },
 
-    setAttr: function(targetData) {
-        var ln = targetData.length,
-            spriteArr = [],
-            attrs, attr, attrArr, attPtr, spritePtr, idx, value, i, j, x, y, ln2;
-        for (i = 0; i < ln; i++) {
-            attrs = targetData[i].attrs;
-            for (attr in attrs) {
-                attrArr = attrs[attr];
-                ln2 = attrArr.length;
-                for (j = 0; j < ln2; j++) {
-                    spritePtr = attrArr[j][0];
-                    attPtr = attrArr[j][1];
-                    if (attr === 'translate') {
-                        value = {
-                            x: attPtr.x,
-                            y: attPtr.y
-                        };
-                    }
-                    else if (attr === 'rotate') {
-                        x = attPtr.x;
-                        if (isNaN(x)) {
-                            x = null;
-                        }
-                        y = attPtr.y;
-                        if (isNaN(y)) {
-                            y = null;
-                        }
-                        value = {
-                            degrees: attPtr.degrees,
-                            x: x,
-                            y: y
-                        };
-                    }
-                    else if (attr === 'width' || attr === 'height' || attr === 'x' || attr === 'y') {
-                        value = parseFloat(attPtr);
-                    }
-                    else {
-                        value = attPtr;
-                    }
-                    idx = Ext.Array.indexOf(spriteArr, spritePtr);
-                    if (idx == -1) {
-                        spriteArr.push([spritePtr, {}]);
-                        idx = spriteArr.length - 1;
-                    }
-                    spriteArr[idx][1][attr] = value;
-                }
-            }
+    // private
+    repair: function(xy, callback, scope) {
+        this.hide();
+        if (typeof callback == "function") {
+            callback.call(scope || this);
         }
-        ln = spriteArr.length;
-        for (i = 0; i < ln; i++) {
-            spritePtr = spriteArr[i];
-            spritePtr[0].setAttributes(spritePtr[1]);
+    },
+
+    /**
+     * Moves the proxy to a different position in the DOM.  This is typically
+     * called while dragging the Panel to keep the proxy sync'd to the Panel's
+     * location.
+     * @param {HTMLElement} parentNode The proxy's parent DOM node
+     * @param {HTMLElement} [before] The sibling node before which the
+     * proxy should be inserted (defaults to the parent's last child if not
+     * specified)
+     */
+    moveProxy : function(parentNode, before){
+        if (this.proxy) {
+            parentNode.insertBefore(this.proxy.dom, before);
         }
-        this.target.redraw();
     }
 });
-
 /**
- * @class Ext.fx.target.CompositeSprite
- * @extends Ext.fx.target.Sprite
-
-This class represents a animation target for a {@link Ext.draw.CompositeSprite}. It allows
-each {@link Ext.draw.Sprite} in the group to be animated as a whole. In general this class will not be
-created directly, the {@link Ext.draw.CompositeSprite} will be passed to the animation and
-and the appropriate target will be created.
-
- * @markdown
+ * @class Ext.layout.component.AbstractDock
+ * @extends Ext.layout.component.Component
+ * @private
+ * This ComponentLayout handles docking for Panels. It takes care of panels that are
+ * part of a ContainerLayout that sets this Panel's size and Panels that are part of
+ * an AutoContainerLayout in which this panel get his height based of the CSS or
+ * or its content.
  */
 
-Ext.define('Ext.fx.target.CompositeSprite', {
+Ext.define('Ext.layout.component.AbstractDock', {
 
     /* Begin Definitions */
 
-    extend: 'Ext.fx.target.Sprite',
+    extend: 'Ext.layout.component.Component',
 
     /* End Definitions */
 
-    getAttr: function(attr, val) {
-        var out = [],
-            target = this.target;
-        target.each(function(sprite) {
-            out.push([sprite, val != undefined ? val : this.getFromPrim(sprite, attr)]);
-        }, this);
-        return out;
-    }
-});
-
-/**
- * @class Ext.fx.target.Component
- * @extends Ext.fx.target.Target
- * 
- * This class represents a animation target for a {@link Ext.Component}. In general this class will not be
- * created directly, the {@link Ext.Component} will be passed to the animation and
- * and the appropriate target will be created.
- */
-Ext.define('Ext.fx.target.Component', {
-
-    /* Begin Definitions */
-   
-    extend: 'Ext.fx.target.Target',
-    
-    /* End Definitions */
+    type: 'dock',
 
-    type: 'component',
+    /**
+     * @private
+     * @property autoSizing
+     * @type Boolean
+     * This flag is set to indicate this layout may have an autoHeight/autoWidth.
+     */
+    autoSizing: true,
 
-    // Methods to call to retrieve unspecified "from" values from a target 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');
+    beforeLayout: function() {
+        var returnValue = this.callParent(arguments);
+        if (returnValue !== false && (!this.initializedBorders || this.childrenChanged) && (!this.owner.border || this.owner.manageBodyBorders)) {
+            this.handleItemBorders();
+            this.initializedBorders = true;
         }
+        return returnValue;
     },
+    
+    handleItemBorders: function() {
+        var owner = this.owner,
+            body = owner.body,
+            docked = this.getLayoutItems(),
+            borders = {
+                top: [],
+                right: [],
+                bottom: [],
+                left: []
+            },
+            oldBorders = this.borders,
+            opposites = {
+                top: 'bottom',
+                right: 'left',
+                bottom: 'top',
+                left: 'right'
+            },
+            i, ln, item, dock, side;
 
-    compMethod: {
-        top: 'setPosition',
-        left: 'setPosition',
-        x: 'setPagePosition',
-        y: 'setPagePosition',
-        height: 'setSize',
-        width: 'setSize',
-        opacity: 'setOpacity'
-    },
-
-    // Read the named attribute from the target Component. Use the defined getter for the attribute
-    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];
-                    // We REALLY want a single function call, so push these down to merge them: eg
-                    // meth.setPagePosition.target = <targetComponent>
-                    // meth.setPagePosition['x'] = 100
-                    // meth.setPagePosition['y'] = 100
-                    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 : parseInt(o.left, 10);
-                    top = (o.top === undefined) ? undefined : parseInt(o.top, 10);
-                    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;
-                    // Dimensions not being animated MUST NOT be autosized. They must remain at current value.
-                    w = (o.width === undefined) ? o.target.getWidth() : parseInt(o.width, 10);
-                    h = (o.height === undefined) ? o.target.getHeight() : parseInt(o.height, 10);
-
-                    // Only set the size of the Component on the last frame, or if the animation was
-                    // configured with dynamic: true.
-                    // In other cases, we just set the target element size.
-                    // This will result in either clipping if animating a reduction in size, or the revealing of
-                    // the inner elements of the Component if animating an increase in size.
-                    // Component's animate function initially resizes to the larger size before resizing the
-                    // outer element to clip the contents.
-                    if (isLastFrame || me.dynamic) {
-                        o.target.componentLayout.childrenChanged = true;
+        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);
+            }
+        }
 
-                        // Flag if we are being called by an animating layout: use setCalculatedSize
-                        if (me.layoutAnimation) {
-                            o.target.setCalculatedSize(w, h);
-                        } else {
-                            o.target.setSize(w, h);
+        if (oldBorders) {
+            for (side in oldBorders) {
+                if (oldBorders.hasOwnProperty(side)) {
+                    ln = oldBorders[side].length;
+                    if (!owner.manageBodyBorders) {
+                        for (i = 0; i < ln; i++) {
+                            oldBorders[side][i].removeCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);
                         }
+                        if (!oldBorders[side].satisfied && !owner.bodyBorder) {
+                            body.removeCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);                   
+                        }                    
                     }
-                    else {
-                        o.target.el.setSize(w, h);
+                    else if (oldBorders[side].satisfied) {
+                        body.setStyle('border-' + side + '-width', '');
                     }
                 }
-                if (meth.setOpacity.target) {
-                    o = meth.setOpacity;
-                    o.target.el.setStyle('opacity', o.opacity);
-                }
             }
         }
-    }
-});
-
-/**
- * @class Ext.fx.CubicBezier
- * @ignore
- */
-Ext.define('Ext.fx.CubicBezier', {
-
-    /* Begin Definitions */
-
-    singleton: true,
-
-    /* End Definitions */
-
-    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;
+                
+        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) {
+                        body.addCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);                   
+                    }                    
                 }
-                d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
-                if (Math.abs(d2) < 1e-6) {
-                    break;
+                else if (borders[side].satisfied) {
+                    body.setStyle('border-' + side + '-width', '1px');
                 }
-                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));
+        
+        this.borders = borders;
     },
+    
+    /**
+     * @protected
+     * @param {Ext.Component} owner The Panel that owns this DockLayout
+     * @param {Ext.Element} target The target in which we are going to render the docked items
+     * @param {Array} args The arguments passed to the ComponentLayout.layout method
+     */
+    onLayout: function(width, height) {
+        if (this.onLayout_running) {
+            return;
+        }
+        this.onLayout_running = true;
+        var me = this,
+            owner = me.owner,
+            body = owner.body,
+            layout = owner.layout,
+            target = me.getTarget(),
+            autoWidth = false,
+            autoHeight = false,
+            padding, border, frameSize;
 
-    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);
+        // We start of by resetting all the layouts info
+        var info = me.info = {
+            boxes: [],
+            size: {
+                width: width,
+                height: height
+            },
+            bodyBox: {}
         };
-        return fn;
-    }
-});
-/**
- * Represents an RGB color and provides helper functions get
- * color components in HSL color space.
- */
-Ext.define('Ext.draw.Color', {
-
-    /* Begin Definitions */
+        // Clear isAutoDock flag
+        delete layout.isAutoDock;
 
-    /* End Definitions */
+        Ext.applyIf(info, me.getTargetInfo());
 
-    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*/,
+        // We need to bind to the ownerCt whenever we do not have a user set height or width.
+        if (owner && owner.ownerCt && owner.ownerCt.layout && owner.ownerCt.layout.isLayout) {
+            if (!Ext.isNumber(owner.height) || !Ext.isNumber(owner.width)) {
+                owner.ownerCt.layout.bindToOwnerCtComponent = true;
+            }
+            else {
+                owner.ownerCt.layout.bindToOwnerCtComponent = false;
+            }
+        }
 
-    /**
-     * @cfg {Number} lightnessFactor
-     *
-     * The default factor to compute the lighter or darker color. Defaults to 0.2.
-     */
-    lightnessFactor: 0.2,
+        // Determine if we have an autoHeight or autoWidth.
+        if (height == null || width == null) {
+            padding = info.padding;
+            border = info.border;
+            frameSize = me.frameSize;
 
-    /**
-     * Creates new Color.
-     * @param {Number} red Red component (0..255)
-     * @param {Number} green Green component (0..255)
-     * @param {Number} blue Blue component (0..255)
-     */
-    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);
-    },
+            // Auto-everything, clear out any style height/width and read from css
+            if ((height == null) && (width == null)) {
+                autoHeight = true;
+                autoWidth = true;
+                me.setTargetSize(null);
+                me.setBodyBox({width: null, height: null});
+            }
+            // Auto-height
+            else if (height == null) {
+                autoHeight = true;
+                // Clear any sizing that we already set in a previous layout
+                me.setTargetSize(width);
+                me.setBodyBox({width: width - padding.left - border.left - padding.right - border.right - frameSize.left - frameSize.right, height: null});
+            // Auto-width
+            }
+            else {
+                autoWidth = true;
+                // Clear any sizing that we already set in a previous layout
+                me.setTargetSize(null, height);
+                me.setBodyBox({width: null, height: height - padding.top - padding.bottom - border.top - border.bottom - frameSize.top - frameSize.bottom});
+            }
 
-    /**
-     * Get the red component of the color, in the range 0..255.
-     * @return {Number}
-     */
-    getRed: function() {
-        return this.r;
-    },
+            // Run the container
+            if (layout && layout.isLayout) {
+                // Auto-Sized so have the container layout notify the component layout.
+                layout.bindToOwnerCtComponent = true;
+                // Set flag so we don't do a redundant container layout
+                layout.isAutoDock = layout.autoSize !== true;
+                layout.layout();
 
-    /**
-     * Get the green component of the color, in the range 0..255.
-     * @return {Number}
-     */
-    getGreen: function() {
-        return this.g;
-    },
+                // If this is an autosized container layout, then we must compensate for a
+                // body that is being autosized.  We do not want to adjust the body's size
+                // to accommodate the dock items, but rather we will want to adjust the
+                // target's size.
+                //
+                // This is necessary because, particularly in a Box layout, all child items
+                // are set with absolute dimensions that are not flexible to the size of its
+                // innerCt/target.  So once they are laid out, they are sized for good. By
+                // shrinking the body box to accommodate dock items, we're merely cutting off
+                // parts of the body.  Not good.  Instead, the target's size should expand
+                // to fit the dock items in.  This is valid because the target container is
+                // suppose to be autosized to fit everything accordingly.
+                info.autoSizedCtLayout = layout.autoSize === true;
+                info.autoHeight = autoHeight;
+                info.autoWidth = autoWidth;
+            }
 
-    /**
-     * Get the blue component of the color, in the range 0..255.
-     * @return {Number}
-     */
-    getBlue: function() {
-        return this.b;
+            // The dockItems method will add all the top and bottom docked items height
+            // to the info.panelSize height. That's why we have to call setSize after
+            // we dock all the items to actually set the panel's width and height.
+            // We have to do this because the panel body and docked items will be position
+            // absolute which doesn't stretch the panel.
+            me.dockItems();
+            me.setTargetSize(info.size.width, info.size.height);
+        }
+        else {
+            me.setTargetSize(width, height);
+            me.dockItems();
+        }
+        me.callParent(arguments);
+        this.onLayout_running = false;
     },
 
     /**
-     * Get the RGB values.
-     * @return {[Number]}
+     * @protected
+     * This method will first update all the information about the docked items,
+     * body dimensions and position, the panel's total size. It will then
+     * set all these values on the docked items and panel body.
+     * @param {Array} items Array containing all the docked items
+     * @param {Boolean} autoBoxes Set this to true if the Panel is part of an
+     * AutoContainerLayout
      */
-    getRGB: function() {
-        var me = this;
-        return [me.r, me.g, me.b];
-    },
+    dockItems : function() {
+        this.calculateDockBoxes();
 
-    /**
-     * Get the equivalent HSL components of the color.
-     * @return {[Number]}
-     */
-    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);
+        // Both calculateAutoBoxes and calculateSizedBoxes are changing the
+        // information about the body, panel size, and boxes for docked items
+        // inside a property called info.
+        var info = this.info,
+            autoWidth = info.autoWidth,
+            autoHeight = info.autoHeight,
+            boxes = info.boxes,
+            ln = boxes.length,
+            dock, i, item;
 
-        // min==max means achromatic (hue is undefined)
-        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;
+        // We are going to loop over all the boxes that were calculated
+        // and set the position of each item the box belongs to.
+        for (i = 0; i < ln; i++) {
+            dock = boxes[i];
+            item = dock.item;
+            item.setPosition(dock.x, dock.y);
+            if ((autoWidth || autoHeight) && item.layout && item.layout.isLayout) {
+                // Auto-Sized so have the container layout notify the component layout.
+                item.layout.bindToOwnerCtComponent = true;
             }
-            if (h < 0) {
-                h += 360;
+        }
+
+        // Don't adjust body width/height if the target is using an auto container layout.
+        // But, we do want to adjust the body size if the container layout is auto sized.
+        if (!info.autoSizedCtLayout) {
+            if (autoWidth) {
+                info.bodyBox.width = null;
             }
-            if (h >= 360) {
-                h -= 360;
+            if (autoHeight) {
+                info.bodyBox.height = null;
             }
         }
-        return [h, s, l];
-    },
-
-    /**
-     * Return a new color that is lighter than this color.
-     * @param {Number} factor Lighter factor (0..1), default to 0.2
-     * @return Ext.draw.Color
-     */
-    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]);
-    },
 
-    /**
-     * Return a new color that is darker than this color.
-     * @param {Number} factor Darker factor (0..1), default to 0.2
-     * @return Ext.draw.Color
-     */
-    getDarker: function(factor) {
-        factor = factor || this.lightnessFactor;
-        return this.getLighter(-factor);
+        // If the bodyBox has been adjusted because of the docked items
+        // we will update the dimensions and position of the panel's body.
+        this.setBodyBox(info.bodyBox);
     },
 
     /**
-     * Return the color in the hex format, i.e. '#rrggbb'.
-     * @return {String}
+     * @protected
+     * This method will set up some initial information about the panel size and bodybox
+     * and then loop over all the items you pass it to take care of stretching, aligning,
+     * dock position and all calculations involved with adjusting the body box.
+     * @param {Array} items Array containing all the docked items we have to layout
      */
-    toString: function() {
+    calculateDockBoxes : function() {
+        if (this.calculateDockBoxes_running) {
+            // [AbstractDock#calculateDockBoxes] attempted to run again while it was already running
+            return;
+        }
+        this.calculateDockBoxes_running = true;
+        // We want to use the Panel's el width, and the Panel's body height as the initial
+        // size we are going to use in calculateDockBoxes. We also want to account for
+        // the border of the panel.
         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('');
-    },
+            target = me.getTarget(),
+            items = me.getLayoutItems(),
+            owner = me.owner,
+            bodyEl = owner.body,
+            info = me.info,
+            autoWidth = info.autoWidth,
+            autoHeight = info.autoHeight,
+            size = info.size,
+            ln = items.length,
+            padding = info.padding,
+            border = info.border,
+            frameSize = me.frameSize,
+            item, i, box, rect;
 
-    /**
-     * Convert a color to hexadecimal format.
-     *
-     * **Note:** This method is both static and instance.
-     *
-     * @param {String/[String]} color The color value (i.e 'rgb(255, 255, 255)', 'color: #ffffff').
-     * Can also be an Array, in this case the function handles the first member.
-     * @returns {String} The color in hexadecimal format.
-     * @static
-     */
-    toHex: function(color) {
-        if (Ext.isArray(color)) {
-            color = color[0];
-        }
-        if (!Ext.isString(color)) {
-            return '';
+        // If this Panel is inside an AutoContainerLayout, we will base all the calculations
+        // around the height of the body and the width of the panel.
+        if (autoHeight) {
+            size.height = bodyEl.getHeight() + padding.top + border.top + padding.bottom + border.bottom + frameSize.top + frameSize.bottom;
         }
-        if (color.substr(0, 1) === '#') {
-            return color;
+        else {
+            size.height = target.getHeight();
         }
-        var digits = this.colorToHexRe.exec(color);
-
-        if (Ext.isArray(digits)) {
-            var 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);
+        if (autoWidth) {
+            size.width = bodyEl.getWidth() + padding.left + border.left + padding.right + border.right + frameSize.left + frameSize.right;
         }
         else {
-            return '';
+            size.width = target.getWidth();
         }
-    },
 
-    /**
-     * Parse the string and create a new color.
-     *
-     * Supported formats: '#rrggbb', '#rgb', and 'rgb(r,g,b)'.
-     *
-     * If the string is not recognized, an undefined will be returned instead.
-     *
-     * **Note:** This method is both static and instance.
-     *
-     * @param {String} str Color in string.
-     * @returns Ext.draw.Color
-     * @static
-     */
-    fromString: function(str) {
-        var values, r, g, b,
-            parse = parseInt;
+        info.bodyBox = {
+            x: padding.left + frameSize.left,
+            y: padding.top + frameSize.top,
+            width: size.width - padding.left - border.left - padding.right - border.right - frameSize.left - frameSize.right,
+            height: size.height - border.top - padding.top - border.bottom - padding.bottom - frameSize.top - frameSize.bottom
+        };
 
-        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);
-                }
+        // Loop over all the docked items
+        for (i = 0; i < ln; i++) {
+            item = items[i];
+            // The initBox method will take care of stretching and alignment
+            // In some cases it will also layout the dock items to be able to
+            // get a width or height measurement
+            box = me.initBox(item);
+
+            if (autoHeight === true) {
+                box = me.adjustAutoBox(box, i);
             }
-        }
-        else {
-            values = str.match(this.rgbRe);
-            if (values) {
-                r = values[1];
-                g = values[2];
-                b = values[3];
+            else {
+                box = me.adjustSizedBox(box, i);
             }
-        }
 
-        return (typeof r == 'undefined') ? undefined : Ext.create('Ext.draw.Color', r, g, b);
+            // Save our box. This allows us to loop over all docked items and do all
+            // calculations first. Then in one loop we will actually size and position
+            // all the docked items that have changed.
+            info.boxes.push(box);
+        }
+        this.calculateDockBoxes_running = false;
     },
 
     /**
-     * Returns the gray value (0 to 255) of the color.
-     *
-     * The gray value is calculated using the formula r*0.3 + g*0.59 + b*0.11.
-     *
-     * @returns {Number}
+     * @protected
+     * This method will adjust the position of the docked item and adjust the body box
+     * accordingly.
+     * @param {Object} box The box containing information about the width and height
+     * of this docked item
+     * @param {Number} index The index position of this docked item
+     * @return {Object} The adjusted box
      */
-    getGrayscale: function() {
-        // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
-        return this.r * 0.3 + this.g * 0.59 + this.b * 0.11;
-    },
+    adjustSizedBox : function(box, index) {
+        var bodyBox = this.info.bodyBox,
+            frameSize = this.frameSize,
+            info = this.info,
+            padding = info.padding,
+            pos = box.type,
+            border = info.border;
 
-    /**
-     * Create a new color based on the specified HSL values.
-     *
-     * **Note:** This method is both static and instance.
-     *
-     * @param {Number} h Hue component (0..359)
-     * @param {Number} s Saturation component (0..1)
-     * @param {Number} l Lightness component (0..1)
-     * @returns Ext.draw.Color
-     * @static
-     */
-    fromHSL: function(h, s, l) {
-        var C, X, m, i, rgb = [],
-            abs = Math.abs,
-            floor = Math.floor;
+        switch (pos) {
+            case 'top':
+                box.y = bodyBox.y;
+                break;
 
-        if (s == 0 || h == null) {
-            // achromatic
-            rgb = [l, l, l];
+            case 'left':
+                box.x = bodyBox.x;
+                break;
+
+            case 'bottom':
+                box.y = (bodyBox.y + bodyBox.height) - box.height;
+                break;
+
+            case 'right':
+                box.x = (bodyBox.x + bodyBox.width) - box.width;
+                break;
         }
-        else {
-            // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL
-            // C is the chroma
-            // X is the second largest component
-            // m is the lightness adjustment
-            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];
+
+        if (box.ignoreFrame) {
+            if (pos == 'bottom') {
+                box.y += (frameSize.bottom + padding.bottom + border.bottom);
+            }
+            else {
+                box.y -= (frameSize.top + padding.top + border.top);
+            }
+            if (pos == 'right') {
+                box.x += (frameSize.right + padding.right + border.right);
+            }
+            else {
+                box.x -= (frameSize.left + padding.left + border.left);
+            }
+        }
+
+        // If this is not an overlaying docked item, we have to adjust the body box
+        if (!box.overlay) {
+            switch (pos) {
+                case 'top':
+                    bodyBox.y += box.height;
+                    bodyBox.height -= box.height;
                     break;
-                case 3:
-                    rgb = [0, X, C];
+
+                case 'left':
+                    bodyBox.x += box.width;
+                    bodyBox.width -= box.width;
                     break;
-                case 4:
-                    rgb = [X, 0, C];
+
+                case 'bottom':
+                    bodyBox.height -= box.height;
                     break;
-                case 5:
-                    rgb = [C, 0, X];
+
+                case 'right':
+                    bodyBox.width -= box.width;
                     break;
             }
-            rgb = [rgb[0] + m, rgb[1] + m, rgb[2] + m];
         }
-        return Ext.create('Ext.draw.Color', rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
-    }
-}, function() {
-    var prototype = this.prototype;
-
-    //These functions are both static and instance. TODO: find a more elegant way of copying them
-    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);
-        }
-    });
-});
-
-/**
- * @class Ext.dd.StatusProxy
- * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair.  This is the
- * default drag proxy used by all Ext.dd components.
- */
-Ext.define('Ext.dd.StatusProxy', {
-    animRepair: false,
+        return box;
+    },
 
     /**
-     * Creates new StatusProxy.
-     * @param {Object} config (optional) Config object.
+     * @protected
+     * This method will adjust the position of the docked item inside an AutoContainerLayout
+     * and adjust the body box accordingly.
+     * @param {Object} box The box containing information about the width and height
+     * of this docked item
+     * @param {Number} index The index position of this docked item
+     * @return {Object} The adjusted box
      */
-    constructor: function(config){
-        Ext.apply(this, config);
-        this.id = this.id || Ext.id();
-        this.proxy = Ext.createWidget('component', {
-            floating: true,
-            id: this.id,
-            html: '<div class="' + Ext.baseCSSPrefix + 'dd-drop-icon"></div>' +
-                  '<div class="' + Ext.baseCSSPrefix + 'dd-drag-ghost"></div>',
-            cls: Ext.baseCSSPrefix + 'dd-drag-proxy ' + this.dropNotAllowed,
-            shadow: !config || config.shadow !== false,
-            renderTo: document.body
-        });
+    adjustAutoBox : function (box, index) {
+        var info = this.info,
+            owner = this.owner,
+            bodyBox = info.bodyBox,
+            size = info.size,
+            boxes = info.boxes,
+            boxesLn = boxes.length,
+            pos = box.type,
+            frameSize = this.frameSize,
+            padding = info.padding,
+            border = info.border,
+            autoSizedCtLayout = info.autoSizedCtLayout,
+            ln = (boxesLn < index) ? boxesLn : index,
+            i, adjustBox;
 
-        this.el = this.proxy.el;
-        this.el.show();
-        this.el.setVisibilityMode(Ext.core.Element.VISIBILITY);
-        this.el.hide();
+        if (pos == 'top' || pos == 'bottom') {
+            // This can affect the previously set left and right and bottom docked items
+            for (i = 0; i < ln; i++) {
+                adjustBox = boxes[i];
+                if (adjustBox.stretched && adjustBox.type == 'left' || adjustBox.type == 'right') {
+                    adjustBox.height += box.height;
+                }
+                else if (adjustBox.type == 'bottom') {
+                    adjustBox.y += box.height;
+                }
+            }
+        }
 
-        this.ghost = Ext.get(this.el.dom.childNodes[1]);
-        this.dropStatus = this.dropNotAllowed;
-    },
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',
-    /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
-     */
-    dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',
+        switch (pos) {
+            case 'top':
+                box.y = bodyBox.y;
+                if (!box.overlay) {
+                    bodyBox.y += box.height;
+                    if (info.autoHeight) {
+                        size.height += box.height;
+                    } else {
+                        bodyBox.height -= box.height;
+                    }
+                }
+                break;
 
-    /**
-     * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
-     * over the current target element.
-     * @param {String} cssClass The css class for the new drop status indicator image
-     */
-    setStatus : function(cssClass){
-        cssClass = cssClass || this.dropNotAllowed;
-        if(this.dropStatus != cssClass){
-            this.el.replaceCls(this.dropStatus, cssClass);
-            this.dropStatus = cssClass;
+            case 'bottom':
+                if (!box.overlay) {
+                    if (info.autoHeight) {
+                        size.height += box.height;
+                    } else {
+                        bodyBox.height -= box.height;
+                    }
+                }
+                box.y = (bodyBox.y + bodyBox.height);
+                break;
+
+            case 'left':
+                box.x = bodyBox.x;
+                if (!box.overlay) {
+                    bodyBox.x += box.width;
+                    if (info.autoWidth) {
+                        size.width += box.width;
+                    } else {
+                        bodyBox.width -= box.width;
+                    }
+                }
+                break;
+
+            case 'right':
+                if (!box.overlay) {
+                    if (info.autoWidth) {
+                        size.width += box.width;
+                    } else {
+                        bodyBox.width -= box.width;
+                    }
+                }
+                box.x = (bodyBox.x + bodyBox.width);
+                break;
         }
-    },
 
-    /**
-     * Resets the status indicator to the default dropNotAllowed value
-     * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
-     */
-    reset : function(clearGhost){
-        this.el.dom.className = Ext.baseCSSPrefix + 'dd-drag-proxy ' + this.dropNotAllowed;
-        this.dropStatus = this.dropNotAllowed;
-        if(clearGhost){
-            this.ghost.update("");
+        if (box.ignoreFrame) {
+            if (pos == 'bottom') {
+                box.y += (frameSize.bottom + padding.bottom + border.bottom);
+            }
+            else {
+                box.y -= (frameSize.top + padding.top + border.top);
+            }
+            if (pos == 'right') {
+                box.x += (frameSize.right + padding.right + border.right);
+            }
+            else {
+                box.x -= (frameSize.left + padding.left + border.left);
+            }
         }
+        return box;
     },
 
     /**
-     * Updates the contents of the ghost element
-     * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a
-     * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).
+     * @protected
+     * This method will create a box object, with a reference to the item, the type of dock
+     * (top, left, bottom, right). It will also take care of stretching and aligning of the
+     * docked items.
+     * @param {Ext.Component} item The docked item we want to initialize the box for
+     * @return {Object} The initial box containing width and height and other useful information
      */
-    update : function(html){
-        if(typeof html == "string"){
-            this.ghost.update(html);
-        }else{
-            this.ghost.update("");
-            html.style.margin = "0";
-            this.ghost.dom.appendChild(html);
+    initBox : function(item) {
+        var me = this,
+            bodyBox = me.info.bodyBox,
+            horizontal = (item.dock == 'top' || item.dock == 'bottom'),
+            owner = me.owner,
+            frameSize = me.frameSize,
+            info = me.info,
+            padding = info.padding,
+            border = info.border,
+            box = {
+                item: item,
+                overlay: item.overlay,
+                type: item.dock,
+                offsets: Ext.Element.parseBox(item.offsets || {}),
+                ignoreFrame: item.ignoreParentFrame
+            };
+        // First we are going to take care of stretch and align properties for all four dock scenarios.
+        if (item.stretch !== false) {
+            box.stretched = true;
+            if (horizontal) {
+                box.x = bodyBox.x + box.offsets.left;
+                box.width = bodyBox.width - (box.offsets.left + box.offsets.right);
+                if (box.ignoreFrame) {
+                    box.width += (frameSize.left + frameSize.right + border.left + border.right + padding.left + padding.right);
+                }
+                item.setCalculatedSize(box.width - item.el.getMargin('lr'), undefined, owner);
+            }
+            else {
+                box.y = bodyBox.y + box.offsets.top;
+                box.height = bodyBox.height - (box.offsets.bottom + box.offsets.top);
+                if (box.ignoreFrame) {
+                    box.height += (frameSize.top + frameSize.bottom + border.top + border.bottom + padding.top + padding.bottom);
+                }
+                item.setCalculatedSize(undefined, box.height - item.el.getMargin('tb'), owner);
+
+                // At this point IE will report the left/right-docked toolbar as having a width equal to the
+                // container's full width. Forcing a repaint kicks it into shape so it reports the correct width.
+                if (!Ext.supports.ComputedStyle) {
+                    item.el.repaint();
+                }
+            }
         }
-        var el = this.ghost.dom.firstChild; 
-        if(el){
-            Ext.fly(el).setStyle('float', 'none');
+        else {
+            item.doComponentLayout();
+            box.width = item.getWidth() - (box.offsets.left + box.offsets.right);
+            box.height = item.getHeight() - (box.offsets.bottom + box.offsets.top);
+            box.y += box.offsets.top;
+            if (horizontal) {
+                box.x = (item.align == 'right') ? bodyBox.width - box.width : bodyBox.x;
+                box.x += box.offsets.left;
+            }
         }
-    },
 
-    /**
-     * Returns the underlying proxy {@link Ext.Layer}
-     * @return {Ext.Layer} el
-    */
-    getEl : function(){
-        return this.el;
-    },
+        // If we haven't calculated the width or height of the docked item yet
+        // do so, since we need this for our upcoming calculations
+        if (box.width === undefined) {
+            box.width = item.getWidth() + item.el.getMargin('lr');
+        }
+        if (box.height === undefined) {
+            box.height = item.getHeight() + item.el.getMargin('tb');
+        }
 
-    /**
-     * Returns the ghost element
-     * @return {Ext.core.Element} el
-     */
-    getGhost : function(){
-        return this.ghost;
+        return box;
     },
 
     /**
-     * Hides the proxy
-     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
+     * @protected
+     * Returns an array containing all the <b>visible</b> docked items inside this layout's owner Panel
+     * @return {Array} An array containing all the <b>visible</b> docked items of the Panel
      */
-    hide : function(clear) {
-        this.proxy.hide();
-        if (clear) {
-            this.reset(true);
+    getLayoutItems : function() {
+        var it = this.owner.getDockedItems(),
+            ln = it.length,
+            i = 0,
+            result = [];
+        for (; i < ln; i++) {
+            if (it[i].isVisible(true)) {
+                result.push(it[i]);
+            }
         }
+        return result;
     },
 
     /**
-     * Stops the repair animation if it's currently running
+     * @protected
+     * Render the top and left docked items before any existing DOM nodes in our render target,
+     * and then render the right and bottom docked items after. This is important, for such things
+     * as tab stops and ARIA readers, that the DOM nodes are in a meaningful order.
+     * Our collection of docked items will already be ordered via Panel.getDockedItems().
      */
-    stop : function(){
-        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
-            this.anim.stop();
+    renderItems: function(items, target) {
+        var cns = target.dom.childNodes,
+            cnsLn = cns.length,
+            ln = items.length,
+            domLn = 0,
+            i, j, cn, item;
+
+        // Calculate the number of DOM nodes in our target that are not our docked items
+        for (i = 0; i < cnsLn; i++) {
+            cn = Ext.get(cns[i]);
+            for (j = 0; j < ln; j++) {
+                item = items[j];
+                if (item.rendered && (cn.id == item.el.id || cn.contains(item.el.id))) {
+                    break;
+                }
+            }
+
+            if (j === ln) {
+                domLn++;
+            }
         }
-    },
 
-    /**
-     * Displays this proxy
-     */
-    show : function() {
-        this.proxy.show();
-        this.proxy.toFront();
+        // Now we go through our docked items and render/move them
+        for (i = 0, j = 0; i < ln; i++, j++) {
+            item = items[i];
+
+            // If we're now at the right/bottom docked item, we jump ahead in our
+            // DOM position, just past the existing DOM nodes.
+            //
+            // TODO: This is affected if users provide custom weight values to their
+            // docked items, which puts it out of (t,l,r,b) order. Avoiding a second
+            // sort operation here, for now, in the name of performance. getDockedItems()
+            // needs the sort operation not just for this layout-time rendering, but
+            // also for getRefItems() to return a logical ordering (FocusManager, CQ, et al).
+            if (i === j && (item.dock === 'right' || item.dock === 'bottom')) {
+                j += domLn;
+            }
+
+            // Same logic as Layout.renderItems()
+            if (item && !item.rendered) {
+                this.renderItem(item, target, j);
+            }
+            else if (!this.isValidParent(item, target, j)) {
+                this.moveItem(item, target, j);
+            }
+        }
     },
 
     /**
-     * Force the Layer to sync its shadow and shim positions to the element
+     * @protected
+     * This function will be called by the dockItems method. Since the body is positioned absolute,
+     * we need to give it dimensions and a position so that it is in the middle surrounded by
+     * docked items
+     * @param {Object} box An object containing new x, y, width and height values for the
+     * Panel's body
      */
-    sync : function(){
-        this.proxy.el.sync();
+    setBodyBox : function(box) {
+        var me = this,
+            owner = me.owner,
+            body = owner.body,
+            info = me.info,
+            bodyMargin = info.bodyMargin,
+            padding = info.padding,
+            border = info.border,
+            frameSize = me.frameSize;
+        
+        // Panel collapse effectively hides the Panel's body, so this is a no-op.
+        if (owner.collapsed) {
+            return;
+        }
+        
+        if (Ext.isNumber(box.width)) {
+            box.width -= bodyMargin.left + bodyMargin.right;
+        }
+        
+        if (Ext.isNumber(box.height)) {
+            box.height -= bodyMargin.top + bodyMargin.bottom;
+        }
+        
+        me.setElementSize(body, box.width, box.height);
+        if (Ext.isNumber(box.x)) {
+            body.setLeft(box.x - padding.left - frameSize.left);
+        }
+        if (Ext.isNumber(box.y)) {
+            body.setTop(box.y - padding.top - frameSize.top);
+        }
     },
 
     /**
-     * Causes the proxy to return to its position of origin via an animation.  Should be called after an
-     * invalid drop operation by the item being dragged.
-     * @param {Array} xy The XY position of the element ([x, y])
-     * @param {Function} callback The function to call after the repair is complete.
-     * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
+     * @protected
+     * We are overriding the Ext.layout.Layout configureItem method to also add a class that
+     * indicates the position of the docked item. We use the itemCls (x-docked) as a prefix.
+     * An example of a class added to a dock: right item is x-docked-right
+     * @param {Ext.Component} item The item we are configuring
      */
-    repair : function(xy, callback, scope){
-        this.callback = callback;
-        this.scope = scope;
-        if (xy && this.animRepair !== false) {
-            this.el.addCls(Ext.baseCSSPrefix + 'dd-drag-repair');
-            this.el.hideUnders(true);
-            this.anim = this.el.animate({
-                duration: this.repairDuration || 500,
-                easing: 'ease-out',
-                to: {
-                    x: xy[0],
-                    y: xy[1]
-                },
-                stopAnimation: true,
-                callback: this.afterRepair,
-                scope: this
-            });
+    configureItem : function(item, pos) {
+        this.callParent(arguments);
+        if (item.dock == 'top' || item.dock == 'bottom') {
+            item.layoutManagedWidth = 1;
+            item.layoutManagedHeight = 2;
         } else {
-            this.afterRepair();
+            item.layoutManagedWidth = 2;
+            item.layoutManagedHeight = 1;
         }
+        
+        item.addCls(Ext.baseCSSPrefix + 'docked');
+        item.addClsWithUI('docked-' + item.dock);
     },
 
-    // private
-    afterRepair : function(){
-        this.hide(true);
-        if(typeof this.callback == "function"){
-            this.callback.call(this.scope || this);
+    afterRemove : function(item) {
+        this.callParent(arguments);
+        if (this.itemCls) {
+            item.el.removeCls(this.itemCls + '-' + item.dock);
         }
-        this.callback = null;
-        this.scope = null;
-    },
+        var dom = item.el.dom;
 
-    destroy: function(){
-        Ext.destroy(this.ghost, this.proxy, this.el);
+        if (!item.destroying && dom) {
+            dom.parentNode.removeChild(dom);
+        }
+        this.childrenChanged = true;
     }
 });
 /**
- * @class Ext.panel.Proxy
- * @extends Object
- * A custom drag proxy implementation specific to {@link Ext.panel.Panel}s. This class
- * is primarily used internally for the Panel's drag drop implementation, and
- * should never need to be created directly.
+ * @class Ext.util.Memento
+ * This class manages a set of captured properties from an object. These captured properties
+ * can later be restored to an object.
  */
-Ext.define('Ext.panel.Proxy', {
-    
-    alternateClassName: 'Ext.dd.PanelProxy',
-
-    /**
-     * Creates new panel proxy.
-     * @param {Ext.panel.Panel} panel The {@link Ext.panel.Panel} to proxy for
-     * @param {Object} config (optional) Config object
-     */
-    constructor: function(panel, config){
-        /**
-         * @property panel
-         * @type Ext.panel.Panel
-         */
-        this.panel = panel;
-        this.id = this.panel.id +'-ddproxy';
-        Ext.apply(this, config);
-    },
-
-    /**
-     * @cfg {Boolean} insertProxy True to insert a placeholder proxy element
-     * while dragging the panel, false to drag with no proxy (defaults to true).
-     * Most Panels are not absolute positioned and therefore we need to reserve
-     * this space.
-     */
-    insertProxy: true,
+Ext.define('Ext.util.Memento', function () {
 
-    // private overrides
-    setStatus: Ext.emptyFn,
-    reset: Ext.emptyFn,
-    update: Ext.emptyFn,
-    stop: Ext.emptyFn,
-    sync: Ext.emptyFn,
+    function captureOne (src, target, prop) {
+        src[prop] = target[prop];
+    }
 
-    /**
-     * Gets the proxy's element
-     * @return {Element} The proxy's element
-     */
-    getEl: function(){
-        return this.ghost.el;
-    },
+    function removeOne (src, target, prop) {
+        delete src[prop];
+    }
 
-    /**
-     * Gets the proxy's ghost Panel
-     * @return {Panel} The proxy's ghost Panel
-     */
-    getGhost: function(){
-        return this.ghost;
-    },
+    function restoreOne (src, target, prop) {
+        var value = src[prop];
+        if (value || src.hasOwnProperty(prop)) {
+            restoreValue(target, prop, value);
+        }
+    }
 
-    /**
-     * Gets the proxy element. This is the element that represents where the
-     * Panel was before we started the drag operation.
-     * @return {Element} The proxy's element
-     */
-    getProxy: function(){
-        return this.proxy;
-    },
+    function restoreValue (target, prop, value) {
+        if (Ext.isDefined(value)) {
+            target[prop] = value;
+        } else {
+            delete target[prop];
+        }
+    }
 
-    /**
-     * Hides the proxy
-     */
-    hide : function(){
-        if (this.ghost) {
-            if (this.proxy) {
-                this.proxy.remove();
-                delete this.proxy;
+    function doMany (doOne, src, target, props) {
+        if (src) {
+            if (Ext.isArray(props)) {
+                Ext.each(props, function (prop) {
+                    doOne(src, target, prop);
+                });
+            } else {
+                doOne(src, target, props);
             }
-
-            // Unghost the Panel, do not move the Panel to where the ghost was
-            this.panel.unghost(null, false);
-            delete this.ghost;
         }
-    },
-
-    /**
-     * Shows the proxy
-     */
-    show: function(){
-        if (!this.ghost) {
-            var panelSize = this.panel.getSize();
-            this.panel.el.setVisibilityMode(Ext.core.Element.DISPLAY);
-            this.ghost = this.panel.ghost();
-            if (this.insertProxy) {
-                // bc Panels aren't absolute positioned we need to take up the space
-                // of where the panel previously was
-                this.proxy = this.panel.el.insertSibling({cls: Ext.baseCSSPrefix + 'panel-dd-spacer'});
-                this.proxy.setSize(panelSize);
-            }
-        }
-    },
+    }
 
-    // private
-    repair: function(xy, callback, scope) {
-        this.hide();
-        if (typeof callback == "function") {
-            callback.call(scope || this);
-        }
-    },
+    return {
+        /**
+         * @property data
+         * The collection of captured properties.
+         * @private
+         */
+        data: null,
 
-    /**
-     * Moves the proxy to a different position in the DOM.  This is typically
-     * called while dragging the Panel to keep the proxy sync'd to the Panel's
-     * location.
-     * @param {HTMLElement} parentNode The proxy's parent DOM node
-     * @param {HTMLElement} before (optional) The sibling node before which the
-     * proxy should be inserted (defaults to the parent's last child if not
-     * specified)
-     */
-    moveProxy : function(parentNode, before){
-        if (this.proxy) {
-            parentNode.insertBefore(this.proxy.dom, before);
-        }
-    }
-});
-/**
- * @class Ext.layout.component.AbstractDock
- * @extends Ext.layout.component.Component
- * @private
- * This ComponentLayout handles docking for Panels. It takes care of panels that are
- * part of a ContainerLayout that sets this Panel's size and Panels that are part of
- * an AutoContainerLayout in which this panel get his height based of the CSS or
- * or its content.
- */
+        /**
+         * @property target
+         * The default target object for capture/restore (passed to the constructor).
+         */
+        target: null,
 
-Ext.define('Ext.layout.component.AbstractDock', {
+        /**
+         * Creates a new memento and optionally captures properties from the target object.
+         * @param {Object} target The target from which to capture properties. If specified in the
+         * constructor, this target becomes the default target for all other operations.
+         * @param {String/String[]} props The property or array of properties to capture.
+         */
+        constructor: function (target, props) {
+            if (target) {
+                this.target = target;
+                if (props) {
+                    this.capture(props);
+                }
+            }
+        },
 
-    /* Begin Definitions */
+        /**
+         * Captures the specified properties from the target object in this memento.
+         * @param {String/String[]} props The property or array of properties to capture.
+         * @param {Object} target The object from which to capture properties.
+         */
+        capture: function (props, target) {
+            doMany(captureOne, this.data || (this.data = {}), target || this.target, props);
+        },
 
-    extend: 'Ext.layout.component.Component',
+        /**
+         * Removes the specified properties from this memento. These properties will not be
+         * restored later without re-capturing their values.
+         * @param {String/String[]} props The property or array of properties to remove.
+         */
+        remove: function (props) {
+            doMany(removeOne, this.data, null, props);
+        },
 
-    /* End Definitions */
+        /**
+         * Restores the specified properties from this memento to the target object.
+         * @param {String/String[]} props The property or array of properties to restore.
+         * @param {Boolean} clear True to remove the restored properties from this memento or
+         * false to keep them (default is true).
+         * @param {Object} target The object to which to restore properties.
+         */
+        restore: function (props, clear, target) {
+            doMany(restoreOne, this.data, target || this.target, props);
+            if (clear !== false) {
+                this.remove(props);
+            }
+        },
 
-    type: 'dock',
+        /**
+         * Restores all captured properties in this memento to the target object.
+         * @param {Boolean} clear True to remove the restored properties from this memento or
+         * false to keep them (default is true).
+         * @param {Object} target The object to which to restore properties.
+         */
+        restoreAll: function (clear, target) {
+            var me = this,
+                t = target || this.target;
 
-    /**
-     * @private
-     * @property autoSizing
-     * @type boolean
-     * This flag is set to indicate this layout may have an autoHeight/autoWidth.
-     */
-    autoSizing: true,
+            Ext.Object.each(me.data, function (prop, value) {
+                restoreValue(t, prop, value);
+            });
 
-    beforeLayout: function() {
-        var returnValue = this.callParent(arguments);
-        if (returnValue !== false && (!this.initializedBorders || this.childrenChanged) && (!this.owner.border || this.owner.manageBodyBorders)) {
-            this.handleItemBorders();
-            this.initializedBorders = true;
+            if (clear !== false) {
+                delete me.data;
+            }
         }
-        return returnValue;
+    };
+}());
+
+/**
+ * @class Ext.app.EventBus
+ * @private
+ */
+Ext.define('Ext.app.EventBus', {
+    requires: [
+        'Ext.util.Event'
+    ],
+    mixins: {
+        observable: 'Ext.util.Observable'
     },
-    
-    handleItemBorders: function() {
-        var owner = this.owner,
-            body = owner.body,
-            docked = this.getLayoutItems(),
-            borders = {
-                top: [],
-                right: [],
-                bottom: [],
-                left: []
-            },
-            oldBorders = this.borders,
-            opposites = {
-                top: 'bottom',
-                right: 'left',
-                bottom: 'top',
-                left: 'right'
-            },
-            i, ln, item, dock, side;
 
-        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);
-            }
-        }
+    constructor: function() {
+        this.mixins.observable.constructor.call(this);
 
-        if (oldBorders) {
-            for (side in oldBorders) {
-                if (oldBorders.hasOwnProperty(side)) {
-                    ln = oldBorders[side].length;
-                    if (!owner.manageBodyBorders) {
-                        for (i = 0; i < ln; i++) {
-                            oldBorders[side][i].removeCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);
-                        }
-                        if (!oldBorders[side].satisfied && !owner.bodyBorder) {
-                            body.removeCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);                   
-                        }                    
-                    }
-                    else if (oldBorders[side].satisfied) {
-                        body.setStyle('border-' + side + '-width', '');
-                    }
+        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;
             }
-        }
-                
-        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);
+        });
+    },
+
+    dispatch: function(ev, target, args) {
+        var bus = this.bus,
+            selectors = bus[ev],
+            selector, controllers, id, events, event, i, ln;
+
+        if (selectors) {
+            // Loop over all the selectors that are bound to this event
+            for (selector in selectors) {
+                // Check if the target matches the selector
+                if (target.is(selector)) {
+                    // Loop over all the controllers that are bound to this selector
+                    controllers = selectors[selector];
+                    for (id in controllers) {
+                        // Loop over all the events that are bound to this selector on this controller
+                        events = controllers[id];
+                        for (i = 0, ln = events.length; i < ln; i++) {
+                            event = events[i];
+                            // Fire the event!
+                            if (event.fire.apply(event, Array.prototype.slice.call(args, 1)) === false) {
+                                return false;
+                            };
+                        }
                     }
-                    if ((!borders[side].satisfied && !owner.bodyBorder) || owner.bodyBorder === false) {
-                        body.addCls(Ext.baseCSSPrefix + 'docked-noborder-' + side);                   
-                    }                    
-                }
-                else if (borders[side].satisfied) {
-                    body.setStyle('border-' + side + '-width', '1px');
                 }
             }
         }
-        
-        this.borders = borders;
     },
-    
-    /**
-     * @protected
-     * @param {Ext.Component} owner The Panel that owns this DockLayout
-     * @param {Ext.core.Element} target The target in which we are going to render the docked items
-     * @param {Array} args The arguments passed to the ComponentLayout.layout method
-     */
-    onLayout: function(width, height) {
-        var me = this,
-            owner = me.owner,
-            body = owner.body,
-            layout = owner.layout,
-            target = me.getTarget(),
-            autoWidth = false,
-            autoHeight = false,
-            padding, border, frameSize;
-
-        // We start of by resetting all the layouts info
-        var info = me.info = {
-            boxes: [],
-            size: {
-                width: width,
-                height: height
-            },
-            bodyBox: {}
-        };
-        // Clear isAutoDock flag
-        delete layout.isAutoDock;
 
-        Ext.applyIf(info, me.getTargetInfo());
+    control: function(selectors, listeners, controller) {
+        var bus = this.bus,
+            selector, fn;
 
-        // We need to bind to the ownerCt whenever we do not have a user set height or width.
-        if (owner && owner.ownerCt && owner.ownerCt.layout && owner.ownerCt.layout.isLayout) {
-            if (!Ext.isNumber(owner.height) || !Ext.isNumber(owner.width)) {
-                owner.ownerCt.layout.bindToOwnerCtComponent = true;
-            }
-            else {
-                owner.ownerCt.layout.bindToOwnerCtComponent = false;
-            }
+        if (Ext.isString(selectors)) {
+            selector = selectors;
+            selectors = {};
+            selectors[selector] = listeners;
+            this.control(selectors, null, controller);
+            return;
         }
 
-        // Determine if we have an autoHeight or autoWidth.
-        if (height === undefined || height === null || width === undefined || width === null) {
-            padding = info.padding;
-            border = info.border;
-            frameSize = me.frameSize;
+        Ext.Object.each(selectors, function(selector, listeners) {
+            Ext.Object.each(listeners, function(ev, listener) {
+                var options = {},
+                    scope = controller,
+                    event = Ext.create('Ext.util.Event', controller, ev);
 
-            // Auto-everything, clear out any style height/width and read from css
-            if ((height === undefined || height === null) && (width === undefined || width === null)) {
-                autoHeight = true;
-                autoWidth = true;
-                me.setTargetSize(null);
-                me.setBodyBox({width: null, height: null});
-            }
-            // Auto-height
-            else if (height === undefined || height === null) {
-                autoHeight = true;
-                // Clear any sizing that we already set in a previous layout
-                me.setTargetSize(width);
-                me.setBodyBox({width: width - padding.left - border.left - padding.right - border.right - frameSize.left - frameSize.right, height: null});
-            // Auto-width
-            }
-            else {
-                autoWidth = true;
-                // Clear any sizing that we already set in a previous layout
-                me.setTargetSize(null, height);
-                me.setBodyBox({width: null, height: height - padding.top - padding.bottom - border.top - border.bottom - frameSize.top - frameSize.bottom});
-            }
+                // Normalize the listener
+                if (Ext.isObject(listener)) {
+                    options = listener;
+                    listener = options.fn;
+                    scope = options.scope || controller;
+                    delete options.fn;
+                    delete options.scope;
+                }
 
-            // Run the container
-            if (layout && layout.isLayout) {
-                // Auto-Sized so have the container layout notify the component layout.
-                layout.bindToOwnerCtComponent = true;
-                // Set flag so we don't do a redundant container layout
-                layout.isAutoDock = layout.autoSize !== true;
-                layout.layout();
+                event.addListener(listener, scope, options);
 
-                // If this is an autosized container layout, then we must compensate for a
-                // body that is being autosized.  We do not want to adjust the body's size
-                // to accommodate the dock items, but rather we will want to adjust the
-                // target's size.
-                //
-                // This is necessary because, particularly in a Box layout, all child items
-                // are set with absolute dimensions that are not flexible to the size of its
-                // innerCt/target.  So once they are laid out, they are sized for good. By
-                // shrinking the body box to accommodate dock items, we're merely cutting off
-                // parts of the body.  Not good.  Instead, the target's size should expand
-                // to fit the dock items in.  This is valid because the target container is
-                // suppose to be autosized to fit everything accordingly.
-                info.autoSizedCtLayout = layout.autoSize === true;
-            }
+                // Create the bus tree if it is not there yet
+                bus[ev] = bus[ev] || {};
+                bus[ev][selector] = bus[ev][selector] || {};
+                bus[ev][selector][controller.id] = bus[ev][selector][controller.id] || [];
 
-            // The dockItems method will add all the top and bottom docked items height
-            // to the info.panelSize height. That's why we have to call setSize after
-            // we dock all the items to actually set the panel's width and height.
-            // We have to do this because the panel body and docked items will be position
-            // absolute which doesn't stretch the panel.
-            me.dockItems(autoWidth, autoHeight);
-            me.setTargetSize(info.size.width, info.size.height);
-        }
-        else {
-            me.setTargetSize(width, height);
-            me.dockItems();
-        }
-        me.callParent(arguments);
+                // Push our listener in our bus
+                bus[ev][selector][controller.id].push(event);
+            });
+        });
+    }
+});
+/**
+ * @class Ext.data.Types
+ * <p>This is a static class containing the system-supplied data types which may be given to a {@link Ext.data.Field Field}.<p/>
+ * <p>The properties in this class are used as type indicators in the {@link Ext.data.Field Field} class, so to
+ * test whether a Field is of a certain type, compare the {@link Ext.data.Field#type type} property against properties
+ * of this class.</p>
+ * <p>Developers may add their own application-specific data types to this class. Definition names must be UPPERCASE.
+ * each type definition must contain three properties:</p>
+ * <div class="mdetail-params"><ul>
+ * <li><code>convert</code> : <i>Function</i><div class="sub-desc">A function to convert raw data values from a data block into the data
+ * to be stored in the Field. The function is passed the collowing parameters:
+ * <div class="mdetail-params"><ul>
+ * <li><b>v</b> : Mixed<div class="sub-desc">The data value as read by the Reader, if undefined will use
+ * the configured <tt>{@link Ext.data.Field#defaultValue defaultValue}</tt>.</div></li>
+ * <li><b>rec</b> : Mixed<div class="sub-desc">The data object containing the row as read by the Reader.
+ * Depending on the Reader type, this could be an Array ({@link Ext.data.reader.Array ArrayReader}), an object
+ * ({@link Ext.data.reader.Json JsonReader}), or an XML element.</div></li>
+ * </ul></div></div></li>
+ * <li><code>sortType</code> : <i>Function</i> <div class="sub-desc">A function to convert the stored data into comparable form, as defined by {@link Ext.data.SortTypes}.</div></li>
+ * <li><code>type</code> : <i>String</i> <div class="sub-desc">A textual data type name.</div></li>
+ * </ul></div>
+ * <p>For example, to create a VELatLong field (See the Microsoft Bing Mapping API) containing the latitude/longitude value of a datapoint on a map from a JsonReader data block
+ * which contained the properties <code>lat</code> and <code>long</code>, you would define a new data type like this:</p>
+ *<pre><code>
+// Add a new Field data type which stores a VELatLong object in the Record.
+Ext.data.Types.VELATLONG = {
+    convert: function(v, data) {
+        return new VELatLong(data.lat, data.long);
     },
+    sortType: function(v) {
+        return v.Latitude;  // When sorting, order by latitude
+    },
+    type: 'VELatLong'
+};
+</code></pre>
+ * <p>Then, when declaring a Model, use: <pre><code>
+var types = Ext.data.Types; // allow shorthand type access
+Ext.define('Unit',
+    extend: 'Ext.data.Model',
+    fields: [
+        { name: 'unitName', mapping: 'UnitName' },
+        { name: 'curSpeed', mapping: 'CurSpeed', type: types.INT },
+        { name: 'latitude', mapping: 'lat', type: types.FLOAT },
+        { name: 'longitude', mapping: 'long', type: types.FLOAT },
+        { name: 'position', type: types.VELATLONG }
+    ]
+});
+</code></pre>
+ * @singleton
+ */
+Ext.define('Ext.data.Types', {
+    singleton: true,
+    requires: ['Ext.data.SortTypes']
+}, function() {
+    var st = Ext.data.SortTypes;
 
-    /**
-     * @protected
-     * This method will first update all the information about the docked items,
-     * body dimensions and position, the panel's total size. It will then
-     * set all these values on the docked items and panel body.
-     * @param {Array} items Array containing all the docked items
-     * @param {Boolean} autoBoxes Set this to true if the Panel is part of an
-     * AutoContainerLayout
-     */
-    dockItems : function(autoWidth, autoHeight) {
-        this.calculateDockBoxes(autoWidth, autoHeight);
-
-        // Both calculateAutoBoxes and calculateSizedBoxes are changing the
-        // information about the body, panel size, and boxes for docked items
-        // inside a property called info.
-        var info = this.info,
-            boxes = info.boxes,
-            ln = boxes.length,
-            dock, i;
+    Ext.apply(Ext.data.Types, {
+        /**
+         * @property {RegExp} stripRe
+         * A regular expression for stripping non-numeric characters from a numeric value. Defaults to <tt>/[\$,%]/g</tt>.
+         * This should be overridden for localization.
+         */
+        stripRe: /[\$,%]/g,
 
-        // We are going to loop over all the boxes that were calculated
-        // and set the position of each item the box belongs to.
-        for (i = 0; i < ln; i++) {
-            dock = boxes[i];
-            dock.item.setPosition(dock.x, dock.y);
-            if ((autoWidth || autoHeight) && dock.layout && dock.layout.isLayout) {
-                // Auto-Sized so have the container layout notify the component layout.
-                dock.layout.bindToOwnerCtComponent = true;
-            }
-        }
+        /**
+         * @property {Object} AUTO
+         * This data type means that no conversion is applied to the raw data before it is placed into a Record.
+         */
+        AUTO: {
+            convert: function(v) {
+                return v;
+            },
+            sortType: st.none,
+            type: 'auto'
+        },
 
-        // Don't adjust body width/height if the target is using an auto container layout.
-        // But, we do want to adjust the body size if the container layout is auto sized.
-        if (!info.autoSizedCtLayout) {
-            if (autoWidth) {
-                info.bodyBox.width = null;
-            }
-            if (autoHeight) {
-                info.bodyBox.height = null;
-            }
-        }
+        /**
+         * @property {Object} STRING
+         * This data type means that the raw data is converted into a String before it is placed into a Record.
+         */
+        STRING: {
+            convert: function(v) {
+                var defaultValue = this.useNull ? null : '';
+                return (v === undefined || v === null) ? defaultValue : String(v);
+            },
+            sortType: st.asUCString,
+            type: 'string'
+        },
 
-        // If the bodyBox has been adjusted because of the docked items
-        // we will update the dimensions and position of the panel's body.
-        this.setBodyBox(info.bodyBox);
-    },
+        /**
+         * @property {Object} INT
+         * This data type means that the raw data is converted into an integer before it is placed into a Record.
+         * <p>The synonym <code>INTEGER</code> is equivalent.</p>
+         */
+        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'
+        },
 
-    /**
-     * @protected
-     * This method will set up some initial information about the panel size and bodybox
-     * and then loop over all the items you pass it to take care of stretching, aligning,
-     * dock position and all calculations involved with adjusting the body box.
-     * @param {Array} items Array containing all the docked items we have to layout
-     */
-    calculateDockBoxes : function(autoWidth, autoHeight) {
-        // We want to use the Panel's el width, and the Panel's body height as the initial
-        // size we are going to use in calculateDockBoxes. We also want to account for
-        // the border of the panel.
-        var me = this,
-            target = me.getTarget(),
-            items = me.getLayoutItems(),
-            owner = me.owner,
-            bodyEl = owner.body,
-            info = me.info,
-            size = info.size,
-            ln = items.length,
-            padding = info.padding,
-            border = info.border,
-            frameSize = me.frameSize,
-            item, i, box, rect;
+        /**
+         * @property {Object} FLOAT
+         * This data type means that the raw data is converted into a number before it is placed into a Record.
+         * <p>The synonym <code>NUMBER</code> is equivalent.</p>
+         */
+        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'
+        },
 
-        // If this Panel is inside an AutoContainerLayout, we will base all the calculations
-        // around the height of the body and the width of the panel.
-        if (autoHeight) {
-            size.height = bodyEl.getHeight() + padding.top + border.top + padding.bottom + border.bottom + frameSize.top + frameSize.bottom;
-        }
-        else {
-            size.height = target.getHeight();
-        }
-        if (autoWidth) {
-            size.width = bodyEl.getWidth() + padding.left + border.left + padding.right + border.right + frameSize.left + frameSize.right;
-        }
-        else {
-            size.width = target.getWidth();
+        /**
+         * @property {Object} BOOL
+         * <p>This data type means that the raw data is converted into a boolean before it is placed into
+         * a Record. The string "true" and the number 1 are converted to boolean <code>true</code>.</p>
+         * <p>The synonym <code>BOOLEAN</code> is equivalent.</p>
+         */
+        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'
+        },
+
+        /**
+         * @property {Object} DATE
+         * This data type means that the raw data is converted into a Date before it is placed into a Record.
+         * The date format is specified in the constructor of the {@link Ext.data.Field} to which this type is
+         * being applied.
+         */
+        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'
         }
+    });
 
-        info.bodyBox = {
-            x: padding.left + frameSize.left,
-            y: padding.top + frameSize.top,
-            width: size.width - padding.left - border.left - padding.right - border.right - frameSize.left - frameSize.right,
-            height: size.height - border.top - padding.top - border.bottom - padding.bottom - frameSize.top - frameSize.bottom
-        };
+    Ext.apply(Ext.data.Types, {
+        /**
+         * @property {Object} BOOLEAN
+         * <p>This data type means that the raw data is converted into a boolean before it is placed into
+         * a Record. The string "true" and the number 1 are converted to boolean <code>true</code>.</p>
+         * <p>The synonym <code>BOOL</code> is equivalent.</p>
+         */
+        BOOLEAN: this.BOOL,
 
-        // Loop over all the docked items
-        for (i = 0; i < ln; i++) {
-            item = items[i];
-            // The initBox method will take care of stretching and alignment
-            // In some cases it will also layout the dock items to be able to
-            // get a width or height measurement
-            box = me.initBox(item);
+        /**
+         * @property {Object} INTEGER
+         * This data type means that the raw data is converted into an integer before it is placed into a Record.
+         * <p>The synonym <code>INT</code> is equivalent.</p>
+         */
+        INTEGER: this.INT,
 
-            if (autoHeight === true) {
-                box = me.adjustAutoBox(box, i);
-            }
-            else {
-                box = me.adjustSizedBox(box, i);
+        /**
+         * @property {Object} NUMBER
+         * This data type means that the raw data is converted into a number before it is placed into a Record.
+         * <p>The synonym <code>FLOAT</code> is equivalent.</p>
+         */
+        NUMBER: this.FLOAT
+    });
+});
+
+/**
+ * @author Ed Spencer
+ *
+ * Fields are used to define what a Model is. They aren't instantiated directly - instead, when we create a class that
+ * extends {@link Ext.data.Model}, it will automatically create a Field instance for each field configured in a {@link
+ * Ext.data.Model Model}. For example, we might set up a model like this:
+ *
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             'name', 'email',
+ *             {name: 'age', type: 'int'},
+ *             {name: 'gender', type: 'string', defaultValue: 'Unknown'}
+ *         ]
+ *     });
+ *
+ * Four fields will have been created for the User Model - name, email, age and gender. Note that we specified a couple
+ * of different formats here; if we only pass in the string name of the field (as with name and email), the field is set
+ * up with the 'auto' type. It's as if we'd done this instead:
+ *
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             {name: 'name', type: 'auto'},
+ *             {name: 'email', type: 'auto'},
+ *             {name: 'age', type: 'int'},
+ *             {name: 'gender', type: 'string', defaultValue: 'Unknown'}
+ *         ]
+ *     });
+ *
+ * # Types and conversion
+ *
+ * The {@link #type} is important - it's used to automatically convert data passed to the field into the correct format.
+ * In our example above, the name and email fields used the 'auto' type and will just accept anything that is passed
+ * into them. The 'age' field had an 'int' type however, so if we passed 25.4 this would be rounded to 25.
+ *
+ * Sometimes a simple type isn't enough, or we want to perform some processing when we load a Field's data. We can do
+ * this using a {@link #convert} function. Here, we're going to create a new field based on another:
+ *
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             'name', 'email',
+ *             {name: 'age', type: 'int'},
+ *             {name: 'gender', type: 'string', defaultValue: 'Unknown'},
+ *
+ *             {
+ *                 name: 'firstName',
+ *                 convert: function(value, record) {
+ *                     var fullName  = record.get('name'),
+ *                         splits    = fullName.split(" "),
+ *                         firstName = splits[0];
+ *
+ *                     return firstName;
+ *                 }
+ *             }
+ *         ]
+ *     });
+ *
+ * Now when we create a new User, the firstName is populated automatically based on the name:
+ *
+ *     var ed = Ext.create('User', {name: 'Ed Spencer'});
+ *
+ *     console.log(ed.get('firstName')); //logs 'Ed', based on our convert function
+ *
+ * In fact, if we log out all of the data inside ed, we'll see this:
+ *
+ *     console.log(ed.data);
+ *
+ *     //outputs this:
+ *     {
+ *         age: 0,
+ *         email: "",
+ *         firstName: "Ed",
+ *         gender: "Unknown",
+ *         name: "Ed Spencer"
+ *     }
+ *
+ * The age field has been given a default of zero because we made it an int type. As an auto field, email has defaulted
+ * to an empty string. When we registered the User model we set gender's {@link #defaultValue} to 'Unknown' so we see
+ * that now. Let's correct that and satisfy ourselves that the types work as we expect:
+ *
+ *     ed.set('gender', 'Male');
+ *     ed.get('gender'); //returns 'Male'
+ *
+ *     ed.set('age', 25.4);
+ *     ed.get('age'); //returns 25 - we wanted an int, not a float, so no decimal places allowed
+ */
+Ext.define('Ext.data.Field', {
+    requires: ['Ext.data.Types', 'Ext.data.SortTypes'],
+    alias: 'data.field',
+    
+    constructor : function(config) {
+        if (Ext.isString(config)) {
+            config = {name: config};
+        }
+        Ext.apply(this, config);
+        
+        var types = Ext.data.Types,
+            st = this.sortType,
+            t;
+
+        if (this.type) {
+            if (Ext.isString(this.type)) {
+                this.type = types[this.type.toUpperCase()] || types.AUTO;
             }
+        } else {
+            this.type = types.AUTO;
+        }
 
-            // Save our box. This allows us to loop over all docked items and do all
-            // calculations first. Then in one loop we will actually size and position
-            // all the docked items that have changed.
-            info.boxes.push(box);
+        // named sortTypes are supported, here we look them up
+        if (Ext.isString(st)) {
+            this.sortType = Ext.data.SortTypes[st];
+        } else if(Ext.isEmpty(st)) {
+            this.sortType = this.type.sortType;
+        }
+
+        if (!this.convert) {
+            this.convert = this.type.convert;
         }
     },
+    
+    /**
+     * @cfg {String} name
+     *
+     * The name by which the field is referenced within the Model. This is referenced by, for example, the `dataIndex`
+     * property in column definition objects passed to {@link Ext.grid.property.HeaderContainer}.
+     *
+     * Note: In the simplest case, if no properties other than `name` are required, a field definition may consist of
+     * just a String for the field name.
+     */
+    
+    /**
+     * @cfg {String/Object} type
+     *
+     * The data type for automatic conversion from received data to the *stored* value if
+     * `{@link Ext.data.Field#convert convert}` has not been specified. This may be specified as a string value.
+     * Possible values are
+     *
+     * - auto (Default, implies no conversion)
+     * - string
+     * - int
+     * - float
+     * - boolean
+     * - date
+     *
+     * This may also be specified by referencing a member of the {@link Ext.data.Types} class.
+     *
+     * Developers may create their own application-specific data types by defining new members of the {@link
+     * Ext.data.Types} class.
+     */
+    
+    /**
+     * @cfg {Function} convert
+     *
+     * A function which converts the value provided by the Reader into an object that will be stored in the Model.
+     * It is passed the following parameters:
+     *
+     * - **v** : Mixed
+     *
+     *   The data value as read by the Reader, if undefined will use the configured `{@link Ext.data.Field#defaultValue
+     *   defaultValue}`.
+     *
+     * - **rec** : Ext.data.Model
+     *
+     *   The data object containing the Model as read so far by the Reader. Note that the Model may not be fully populated
+     *   at this point as the fields are read in the order that they are defined in your
+     *   {@link Ext.data.Model#fields fields} array.
+     *
+     * Example of convert functions:
+     *
+     *     function fullName(v, record){
+     *         return record.name.last + ', ' + record.name.first;
+     *     }
+     *
+     *     function location(v, record){
+     *         return !record.city ? '' : (record.city + ', ' + record.state);
+     *     }
+     *
+     *     Ext.define('Dude', {
+     *         extend: 'Ext.data.Model',
+     *         fields: [
+     *             {name: 'fullname',  convert: fullName},
+     *             {name: 'firstname', mapping: 'name.first'},
+     *             {name: 'lastname',  mapping: 'name.last'},
+     *             {name: 'city', defaultValue: 'homeless'},
+     *             'state',
+     *             {name: 'location',  convert: location}
+     *         ]
+     *     });
+     *
+     *     // create the data store
+     *     var store = Ext.create('Ext.data.Store', {
+     *         reader: {
+     *             type: 'json',
+     *             model: 'Dude',
+     *             idProperty: 'key',
+     *             root: 'daRoot',
+     *             totalProperty: 'total'
+     *         }
+     *     });
+     *
+     *     var myData = [
+     *         { key: 1,
+     *           name: { first: 'Fat',    last:  'Albert' }
+     *           // notice no city, state provided in data object
+     *         },
+     *         { key: 2,
+     *           name: { first: 'Barney', last:  'Rubble' },
+     *           city: 'Bedrock', state: 'Stoneridge'
+     *         },
+     *         { key: 3,
+     *           name: { first: 'Cliff',  last:  'Claven' },
+     *           city: 'Boston',  state: 'MA'
+     *         }
+     *     ];
+     */
 
     /**
-     * @protected
-     * This method will adjust the position of the docked item and adjust the body box
-     * accordingly.
-     * @param {Object} box The box containing information about the width and height
-     * of this docked item
-     * @param {Number} index The index position of this docked item
-     * @return {Object} The adjusted box
+     * @cfg {String} dateFormat
+     *
+     * Used when converting received data into a Date when the {@link #type} is specified as `"date"`.
+     *
+     * A format string for the {@link Ext.Date#parse Ext.Date.parse} function, or "timestamp" if the value provided by
+     * the Reader is a UNIX timestamp, or "time" if the value provided by the Reader is a javascript millisecond
+     * timestamp. See {@link Ext.Date}.
      */
-    adjustSizedBox : function(box, index) {
-        var bodyBox = this.info.bodyBox,
-            frameSize = this.frameSize,
-            info = this.info,
-            padding = info.padding,
-            pos = box.type,
-            border = info.border;
+    dateFormat: null,
+    
+    /**
+     * @cfg {Boolean} useNull
+     *
+     * Use when converting received data into a Number type (either int or float). If the value cannot be
+     * parsed, null will be used if useNull is true, otherwise the value will be 0. Defaults to false.
+     */
+    useNull: false,
+    
+    /**
+     * @cfg {Object} defaultValue
+     *
+     * The default value used **when a Model is being created by a {@link Ext.data.reader.Reader Reader}**
+     * when the item referenced by the `{@link Ext.data.Field#mapping mapping}` does not exist in the data object
+     * (i.e. undefined). Defaults to "".
+     */
+    defaultValue: "",
 
-        switch (pos) {
-            case 'top':
-                box.y = bodyBox.y;
-                break;
+    /**
+     * @cfg {String/Number} mapping
+     *
+     * (Optional) A path expression for use by the {@link Ext.data.reader.Reader} implementation that is creating the
+     * {@link Ext.data.Model Model} to extract the Field value from the data object. If the path expression is the same
+     * as the field name, the mapping may be omitted.
+     *
+     * The form of the mapping expression depends on the Reader being used.
+     *
+     * - {@link Ext.data.reader.Json}
+     *
+     *   The mapping is a string containing the javascript expression to reference the data from an element of the data
+     *   item's {@link Ext.data.reader.Json#root root} Array. Defaults to the field name.
+     *
+     * - {@link Ext.data.reader.Xml}
+     *
+     *   The mapping is an {@link Ext.DomQuery} path to the data item relative to the DOM element that represents the
+     *   {@link Ext.data.reader.Xml#record record}. Defaults to the field name.
+     *
+     * - {@link Ext.data.reader.Array}
+     *
+     *   The mapping is a number indicating the Array index of the field's value. Defaults to the field specification's
+     *   Array position.
+     *
+     * If a more complex value extraction strategy is required, then configure the Field with a {@link #convert}
+     * function. This is passed the whole row object, and may interrogate it in whatever way is necessary in order to
+     * return the desired data.
+     */
+    mapping: null,
 
-            case 'left':
-                box.x = bodyBox.x;
-                break;
+    /**
+     * @cfg {Function} sortType
+     *
+     * A function which converts a Field's value to a comparable value in order to ensure correct sort ordering.
+     * Predefined functions are provided in {@link Ext.data.SortTypes}. A custom sort example:
+     *
+     *     // current sort     after sort we want
+     *     // +-+------+          +-+------+
+     *     // |1|First |          |1|First |
+     *     // |2|Last  |          |3|Second|
+     *     // |3|Second|          |2|Last  |
+     *     // +-+------+          +-+------+
+     *
+     *     sortType: function(value) {
+     *        switch (value.toLowerCase()) // native toLowerCase():
+     *        {
+     *           case 'first': return 1;
+     *           case 'second': return 2;
+     *           default: return 3;
+     *        }
+     *     }
+     */
+    sortType : null,
 
-            case 'bottom':
-                box.y = (bodyBox.y + bodyBox.height) - box.height;
-                break;
+    /**
+     * @cfg {String} sortDir
+     *
+     * Initial direction to sort (`"ASC"` or `"DESC"`). Defaults to `"ASC"`.
+     */
+    sortDir : "ASC",
 
-            case 'right':
-                box.x = (bodyBox.x + bodyBox.width) - box.width;
-                break;
-        }
+    /**
+     * @cfg {Boolean} allowBlank
+     * @private
+     *
+     * Used for validating a {@link Ext.data.Model model}. Defaults to true. An empty value here will cause
+     * {@link Ext.data.Model}.{@link Ext.data.Model#isValid isValid} to evaluate to false.
+     */
+    allowBlank : true,
 
-        if (box.ignoreFrame) {
-            if (pos == 'bottom') {
-                box.y += (frameSize.bottom + padding.bottom + border.bottom);
-            }
-            else {
-                box.y -= (frameSize.top + padding.top + border.top);
-            }
-            if (pos == 'right') {
-                box.x += (frameSize.right + padding.right + border.right);
-            }
-            else {
-                box.x -= (frameSize.left + padding.left + border.left);
-            }
-        }
+    /**
+     * @cfg {Boolean} persist
+     *
+     * False to exclude this field from the {@link Ext.data.Model#modified} fields in a model. This will also exclude
+     * the field from being written using a {@link Ext.data.writer.Writer}. This option is useful when model fields are
+     * used to keep state on the client but do not need to be persisted to the server. Defaults to true.
+     */
+    persist: true
+});
 
-        // If this is not an overlaying docked item, we have to adjust the body box
-        if (!box.overlay) {
-            switch (pos) {
-                case 'top':
-                    bodyBox.y += box.height;
-                    bodyBox.height -= box.height;
-                    break;
+/**
+ * @class Ext.util.AbstractMixedCollection
+ * @private
+ */
+Ext.define('Ext.util.AbstractMixedCollection', {
+    requires: ['Ext.util.Filter'],
 
-                case 'left':
-                    bodyBox.x += box.width;
-                    bodyBox.width -= box.width;
-                    break;
+    mixins: {
+        observable: 'Ext.util.Observable'
+    },
 
-                case 'bottom':
-                    bodyBox.height -= box.height;
-                    break;
+    constructor: function(allowFunctions, keyFn) {
+        var me = this;
 
-                case 'right':
-                    bodyBox.width -= box.width;
-                    break;
-            }
-        }
-        return box;
-    },
+        me.items = [];
+        me.map = {};
+        me.keys = [];
+        me.length = 0;
 
-    /**
-     * @protected
-     * This method will adjust the position of the docked item inside an AutoContainerLayout
-     * and adjust the body box accordingly.
-     * @param {Object} box The box containing information about the width and height
-     * of this docked item
-     * @param {Number} index The index position of this docked item
-     * @return {Object} The adjusted box
-     */
-    adjustAutoBox : function (box, index) {
-        var info = this.info,
-            owner = this.owner,
-            bodyBox = info.bodyBox,
-            size = info.size,
-            boxes = info.boxes,
-            boxesLn = boxes.length,
-            pos = box.type,
-            frameSize = this.frameSize,
-            padding = info.padding,
-            border = info.border,
-            autoSizedCtLayout = info.autoSizedCtLayout,
-            ln = (boxesLn < index) ? boxesLn : index,
-            i, adjustBox;
+        me.addEvents(
+            /**
+             * @event clear
+             * Fires when the collection is cleared.
+             */
+            'clear',
 
-        if (pos == 'top' || pos == 'bottom') {
-            // This can affect the previously set left and right and bottom docked items
-            for (i = 0; i < ln; i++) {
-                adjustBox = boxes[i];
-                if (adjustBox.stretched && adjustBox.type == 'left' || adjustBox.type == 'right') {
-                    adjustBox.height += box.height;
-                }
-                else if (adjustBox.type == 'bottom') {
-                    adjustBox.y += box.height;
-                }
-            }
-        }
+            /**
+             * @event add
+             * Fires when an item is added to the collection.
+             * @param {Number} index The index at which the item was added.
+             * @param {Object} o The item added.
+             * @param {String} key The key associated with the added item.
+             */
+            'add',
 
-        switch (pos) {
-            case 'top':
-                box.y = bodyBox.y;
-                if (!box.overlay) {
-                    bodyBox.y += box.height;
-                    if (owner.isFixedHeight()) {
-                        bodyBox.height -= box.height;
-                    } else {
-                        size.height += box.height;
-                    }
-                }
-                break;
+            /**
+             * @event replace
+             * Fires when an item is replaced in the collection.
+             * @param {String} key he key associated with the new added.
+             * @param {Object} old The item being replaced.
+             * @param {Object} new The new item.
+             */
+            'replace',
 
-            case 'bottom':
-                if (!box.overlay) {
-                    if (owner.isFixedHeight()) {
-                        bodyBox.height -= box.height;
-                    } else {
-                        size.height += box.height;
-                    }
-                }
-                box.y = (bodyBox.y + bodyBox.height);
-                break;
+            /**
+             * @event remove
+             * Fires when an item is removed from the collection.
+             * @param {Object} o The item being removed.
+             * @param {String} key (optional) The key associated with the removed item.
+             */
+            'remove'
+        );
 
-            case 'left':
-                box.x = bodyBox.x;
-                if (!box.overlay) {
-                    bodyBox.x += box.width;
-                    if (owner.isFixedWidth()) {
-                        bodyBox.width -= box.width;
-                    } else {
-                        size.width += box.width;
-                    }
-                }
-                break;
+        me.allowFunctions = allowFunctions === true;
 
-            case 'right':
-                if (!box.overlay) {
-                    if (owner.isFixedWidth()) {
-                        bodyBox.width -= box.width;
-                    } else {
-                        size.width += box.width;
-                    }
-                }
-                box.x = (bodyBox.x + bodyBox.width);
-                break;
+        if (keyFn) {
+            me.getKey = keyFn;
         }
 
-        if (box.ignoreFrame) {
-            if (pos == 'bottom') {
-                box.y += (frameSize.bottom + padding.bottom + border.bottom);
-            }
-            else {
-                box.y -= (frameSize.top + padding.top + border.top);
-            }
-            if (pos == 'right') {
-                box.x += (frameSize.right + padding.right + border.right);
-            }
-            else {
-                box.x -= (frameSize.left + padding.left + border.left);
-            }
-        }
-        return box;
+        me.mixins.observable.constructor.call(me);
     },
 
     /**
-     * @protected
-     * This method will create a box object, with a reference to the item, the type of dock
-     * (top, left, bottom, right). It will also take care of stretching and aligning of the
-     * docked items.
-     * @param {Ext.Component} item The docked item we want to initialize the box for
-     * @return {Object} The initial box containing width and height and other useful information
+     * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
+     * function should add function references to the collection. Defaults to
+     * <tt>false</tt>.
      */
-    initBox : function(item) {
+    allowFunctions : false,
+
+    /**
+     * Adds an item to the collection. Fires the {@link #add} event when complete.
+     * @param {String} key <p>The key to associate with the item, or the new item.</p>
+     * <p>If a {@link #getKey} implementation was specified for this MixedCollection,
+     * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
+     * the MixedCollection will be able to <i>derive</i> the key for the new item.
+     * In this case just pass the new item in this parameter.</p>
+     * @param {Object} o The item to add.
+     * @return {Object} The item added.
+     */
+    add : function(key, obj){
         var me = this,
-            bodyBox = me.info.bodyBox,
-            horizontal = (item.dock == 'top' || item.dock == 'bottom'),
-            owner = me.owner,
-            frameSize = me.frameSize,
-            info = me.info,
-            padding = info.padding,
-            border = info.border,
-            box = {
-                item: item,
-                overlay: item.overlay,
-                type: item.dock,
-                offsets: Ext.core.Element.parseBox(item.offsets || {}),
-                ignoreFrame: item.ignoreParentFrame
-            };
-        // First we are going to take care of stretch and align properties for all four dock scenarios.
-        if (item.stretch !== false) {
-            box.stretched = true;
-            if (horizontal) {
-                box.x = bodyBox.x + box.offsets.left;
-                box.width = bodyBox.width - (box.offsets.left + box.offsets.right);
-                if (box.ignoreFrame) {
-                    box.width += (frameSize.left + frameSize.right + border.left + border.right + padding.left + padding.right);
-                }
-                item.setCalculatedSize(box.width - item.el.getMargin('lr'), undefined, owner);
-            }
-            else {
-                box.y = bodyBox.y + box.offsets.top;
-                box.height = bodyBox.height - (box.offsets.bottom + box.offsets.top);
-                if (box.ignoreFrame) {
-                    box.height += (frameSize.top + frameSize.bottom + border.top + border.bottom + padding.top + padding.bottom);
-                }
-                item.setCalculatedSize(undefined, box.height - item.el.getMargin('tb'), owner);
+            myObj = obj,
+            myKey = key,
+            old;
 
-                // At this point IE will report the left/right-docked toolbar as having a width equal to the
-                // container's full width. Forcing a repaint kicks it into shape so it reports the correct width.
-                if (!Ext.supports.ComputedStyle) {
-                    item.el.repaint();
-                }
-            }
+        if (arguments.length == 1) {
+            myObj = myKey;
+            myKey = me.getKey(myObj);
         }
-        else {
-            item.doComponentLayout();
-            box.width = item.getWidth() - (box.offsets.left + box.offsets.right);
-            box.height = item.getHeight() - (box.offsets.bottom + box.offsets.top);
-            box.y += box.offsets.top;
-            if (horizontal) {
-                box.x = (item.align == 'right') ? bodyBox.width - box.width : bodyBox.x;
-                box.x += box.offsets.left;
+        if (typeof myKey != 'undefined' && myKey !== null) {
+            old = me.map[myKey];
+            if (typeof old != 'undefined') {
+                return me.replace(myKey, myObj);
             }
+            me.map[myKey] = myObj;
         }
+        me.length++;
+        me.items.push(myObj);
+        me.keys.push(myKey);
+        me.fireEvent('add', me.length - 1, myObj, myKey);
+        return myObj;
+    },
 
-        // If we haven't calculated the width or height of the docked item yet
-        // do so, since we need this for our upcoming calculations
-        if (box.width == undefined) {
-            box.width = item.getWidth() + item.el.getMargin('lr');
+    /**
+      * MixedCollection has a generic way to fetch keys if you implement getKey.  The default implementation
+      * simply returns <b><code>item.id</code></b> but you can provide your own implementation
+      * to return a different value as in the following examples:<pre><code>
+// normal way
+var mc = new Ext.util.MixedCollection();
+mc.add(someEl.dom.id, someEl);
+mc.add(otherEl.dom.id, otherEl);
+//and so on
+
+// using getKey
+var mc = new Ext.util.MixedCollection();
+mc.getKey = function(el){
+   return el.dom.id;
+};
+mc.add(someEl);
+mc.add(otherEl);
+
+// or via the constructor
+var mc = new Ext.util.MixedCollection(false, function(el){
+   return el.dom.id;
+});
+mc.add(someEl);
+mc.add(otherEl);
+     * </code></pre>
+     * @param {Object} item The item for which to find the key.
+     * @return {Object} The key for the passed item.
+     */
+    getKey : function(o){
+         return o.id;
+    },
+
+    /**
+     * Replaces an item in the collection. Fires the {@link #replace} event when complete.
+     * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>
+     * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
+     * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
+     * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item
+     * with one having the same key value, then just pass the replacement item in this parameter.</p>
+     * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate
+     * with that key.
+     * @return {Object}  The new item.
+     */
+    replace : function(key, o){
+        var me = this,
+            old,
+            index;
+
+        if (arguments.length == 1) {
+            o = arguments[0];
+            key = me.getKey(o);
         }
-        if (box.height == undefined) {
-            box.height = item.getHeight() + item.el.getMargin('tb');
+        old = me.map[key];
+        if (typeof key == 'undefined' || key === null || typeof old == 'undefined') {
+             return me.add(key, o);
         }
-
-        return box;
+        index = me.indexOfKey(key);
+        me.items[index] = o;
+        me.map[key] = o;
+        me.fireEvent('replace', key, old, o);
+        return o;
     },
 
     /**
-     * @protected
-     * Returns an array containing all the <b>visible</b> docked items inside this layout's owner Panel
-     * @return {Array} An array containing all the <b>visible</b> docked items of the Panel
+     * Adds all elements of an Array or an Object to the collection.
+     * @param {Object/Array} objs An Object containing properties which will be added
+     * to the collection, or an Array of values, each of which are added to the collection.
+     * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>
+     * has been set to <tt>true</tt>.
      */
-    getLayoutItems : function() {
-        var it = this.owner.getDockedItems(),
-            ln = it.length,
+    addAll : function(objs){
+        var me = this,
             i = 0,
-            result = [];
-        for (; i < ln; i++) {
-            if (it[i].isVisible(true)) {
-                result.push(it[i]);
+            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]);
+                    }
+                }
             }
         }
-        return result;
     },
 
     /**
-     * @protected
-     * Render the top and left docked items before any existing DOM nodes in our render target,
-     * and then render the right and bottom docked items after. This is important, for such things
-     * as tab stops and ARIA readers, that the DOM nodes are in a meaningful order.
-     * Our collection of docked items will already be ordered via Panel.getDockedItems().
+     * Executes the specified function once for every item in the collection, passing the following arguments:
+     * <div class="mdetail-params"><ul>
+     * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>
+     * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>
+     * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
+     * </ul></div>
+     * The function should return a boolean value. Returning false from the function will stop the iteration.
+     * @param {Function} fn The function to execute for each item.
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current item in the iteration.
      */
-    renderItems: function(items, target) {
-        var cns = target.dom.childNodes,
-            cnsLn = cns.length,
-            ln = items.length,
-            domLn = 0,
-            i, j, cn, item;
+    each : function(fn, scope){
+        var items = [].concat(this.items), // each safe for removal
+            i = 0,
+            len = items.length,
+            item;
 
-        // Calculate the number of DOM nodes in our target that are not our docked items
-        for (i = 0; i < cnsLn; i++) {
-            cn = Ext.get(cns[i]);
-            for (j = 0; j < ln; j++) {
-                item = items[j];
-                if (item.rendered && (cn.id == item.el.id || cn.down('#' + item.el.id))) {
-                    break;
-                }
+        for (; i < len; i++) {
+            item = items[i];
+            if (fn.call(scope || item, item, i, len) === false) {
+                break;
             }
+        }
+    },
 
-            if (j === ln) {
-                domLn++;
-            }
+    /**
+     * Executes the specified function once for every key in the collection, passing each
+     * key, and its associated item as the first two parameters.
+     * @param {Function} fn The function to execute for each item.
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
+     */
+    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);
         }
+    },
 
-        // Now we go through our docked items and render/move them
-        for (i = 0, j = 0; i < ln; i++, j++) {
-            item = items[i];
+    /**
+     * Returns the first item in the collection which elicits a true return value from the
+     * passed selection function.
+     * @param {Function} fn The selection function to execute for each item.
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
+     * @return {Object} The first item in the collection which returned true from the selection function, or null if none was found
+     */
+    findBy : function(fn, scope) {
+        var keys = this.keys,
+            items = this.items,
+            i = 0,
+            len = items.length;
 
-            // If we're now at the right/bottom docked item, we jump ahead in our
-            // DOM position, just past the existing DOM nodes.
-            //
-            // TODO: This is affected if users provide custom weight values to their
-            // docked items, which puts it out of (t,l,r,b) order. Avoiding a second
-            // sort operation here, for now, in the name of performance. getDockedItems()
-            // needs the sort operation not just for this layout-time rendering, but
-            // also for getRefItems() to return a logical ordering (FocusManager, CQ, et al).
-            if (i === j && (item.dock === 'right' || item.dock === 'bottom')) {
-                j += domLn;
+        for (; i < len; i++) {
+            if (fn.call(scope || window, items[i], keys[i])) {
+                return items[i];
             }
+        }
+        return null;
+    },
 
-            // Same logic as Layout.renderItems()
-            if (item && !item.rendered) {
-                this.renderItem(item, target, j);
-            }
-            else if (!this.isValidParent(item, target, j)) {
-                this.moveItem(item, target, j);
-            }
+    //<deprecated since="0.99">
+    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);
     },
+    //</deprecated>
 
     /**
-     * @protected
-     * This function will be called by the dockItems method. Since the body is positioned absolute,
-     * we need to give it dimensions and a position so that it is in the middle surrounded by
-     * docked items
-     * @param {Object} box An object containing new x, y, width and height values for the
-     * Panel's body
+     * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.
+     * @param {Number} index The index to insert the item at.
+     * @param {String} key The key to associate with the new item, or the item itself.
+     * @param {Object} o (optional) If the second parameter was a key, the new item.
+     * @return {Object} The item inserted.
      */
-    setBodyBox : function(box) {
+    insert : function(index, key, obj){
         var me = this,
-            owner = me.owner,
-            body = owner.body,
-            info = me.info,
-            bodyMargin = info.bodyMargin,
-            padding = info.padding,
-            border = info.border,
-            frameSize = me.frameSize;
-        
-        // Panel collapse effectively hides the Panel's body, so this is a no-op.
-        if (owner.collapsed) {
-            return;
-        }
-        
-        if (Ext.isNumber(box.width)) {
-            box.width -= bodyMargin.left + bodyMargin.right;
+            myKey = key,
+            myObj = obj;
+
+        if (arguments.length == 2) {
+            myObj = myKey;
+            myKey = me.getKey(myObj);
         }
-        
-        if (Ext.isNumber(box.height)) {
-            box.height -= bodyMargin.top + bodyMargin.bottom;
+        if (me.containsKey(myKey)) {
+            me.suspendEvents();
+            me.removeAtKey(myKey);
+            me.resumeEvents();
         }
-        
-        me.setElementSize(body, box.width, box.height);
-        if (Ext.isNumber(box.x)) {
-            body.setLeft(box.x - padding.left - frameSize.left);
+        if (index >= me.length) {
+            return me.add(myKey, myObj);
         }
-        if (Ext.isNumber(box.y)) {
-            body.setTop(box.y - padding.top - frameSize.top);
+        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);
+        me.fireEvent('add', index, myObj, myKey);
+        return myObj;
     },
 
     /**
-     * @protected
-     * We are overriding the Ext.layout.Layout configureItem method to also add a class that
-     * indicates the position of the docked item. We use the itemCls (x-docked) as a prefix.
-     * An example of a class added to a dock: right item is x-docked-right
-     * @param {Ext.Component} item The item we are configuring
+     * Remove an item from the collection.
+     * @param {Object} o The item to remove.
+     * @return {Object} The item removed or false if no item was removed.
      */
-    configureItem : function(item, pos) {
-        this.callParent(arguments);
-        if (item.dock == 'top' || item.dock == 'bottom') {
-            item.layoutManagedWidth = 1;
-            item.layoutManagedHeight = 2;
-        } else {
-            item.layoutManagedWidth = 2;
-            item.layoutManagedHeight = 1;
-        }
-        
-        item.addCls(Ext.baseCSSPrefix + 'docked');
-        item.addClsWithUI('docked-' + item.dock);
+    remove : function(o){
+        return this.removeAt(this.indexOf(o));
     },
 
-    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;
-    }
-});
-/**
- * @class Ext.util.Memento
- * This class manages a set of captured properties from an object. These captured properties
- * can later be restored to an object.
- */
-Ext.define('Ext.util.Memento', function () {
-
-    function captureOne (src, target, prop) {
-        src[prop] = target[prop];
-    }
-
-    function removeOne (src, target, prop) {
-        delete src[prop];
-    }
+    /**
+     * Remove all items in the passed array from the collection.
+     * @param {Array} items An array of items to be removed.
+     * @return {Ext.util.MixedCollection} this object
+     */
+    removeAll : function(items){
+        Ext.each(items || [], function(item) {
+            this.remove(item);
+        }, this);
 
-    function restoreOne (src, target, prop) {
-        var value = src[prop];
-        if (value || src.hasOwnProperty(prop)) {
-            restoreValue(target, prop, value);
-        }
-    }
+        return this;
+    },
 
-    function restoreValue (target, prop, value) {
-        if (Ext.isDefined(value)) {
-            target[prop] = value;
-        } else {
-            delete target[prop];
-        }
-    }
+    /**
+     * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.
+     * @param {Number} index The index within the collection of the item to remove.
+     * @return {Object} The item removed or false if no item was removed.
+     */
+    removeAt : function(index){
+        var me = this,
+            o,
+            key;
 
-    function doMany (doOne, src, target, props) {
-        if (src) {
-            if (Ext.isArray(props)) {
-                Ext.each(props, function (prop) {
-                    doOne(src, target, prop);
-                });
-            } else {
-                doOne(src, target, props);
+        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);
+            me.fireEvent('remove', o, key);
+            return o;
         }
-    }
-
-    return {
-        /**
-         * @property data
-         * The collection of captured properties.
-         * @private
-         */
-        data: null,
+        return false;
+    },
 
-        /**
-         * @property target
-         * The default target object for capture/restore (passed to the constructor).
-         */
-        target: null,
+    /**
+     * Removed an item associated with the passed key fom the collection.
+     * @param {String} key The key of the item to remove.
+     * @return {Object} The item removed or false if no item was removed.
+     */
+    removeAtKey : function(key){
+        return this.removeAt(this.indexOfKey(key));
+    },
 
-        /**
-         * Creates a new memento and optionally captures properties from the target object.
-         * @param {Object} target The target from which to capture properties. If specified in the
-         * constructor, this target becomes the default target for all other operations.
-         * @param {String|Array} props The property or array of properties to capture.
-         */
-        constructor: function (target, props) {
-            if (target) {
-                this.target = target;
-                if (props) {
-                    this.capture(props);
-                }
-            }
-        },
+    /**
+     * Returns the number of items in the collection.
+     * @return {Number} the number of items in the collection.
+     */
+    getCount : function(){
+        return this.length;
+    },
 
-        /**
-         * Captures the specified properties from the target object in this memento.
-         * @param {String|Array} props The property or array of properties to capture.
-         * @param {Object} target The object from which to capture properties.
-         */
-        capture: function (props, target) {
-            doMany(captureOne, this.data || (this.data = {}), target || this.target, props);
-        },
+    /**
+     * Returns index within the collection of the passed Object.
+     * @param {Object} o The item to find the index of.
+     * @return {Number} index of the item. Returns -1 if not found.
+     */
+    indexOf : function(o){
+        return Ext.Array.indexOf(this.items, o);
+    },
 
-        /**
-         * Removes the specified properties from this memento. These properties will not be
-         * restored later without re-capturing their values.
-         * @param {String|Array} props The property or array of properties to remove.
-         */
-        remove: function (props) {
-            doMany(removeOne, this.data, null, props);
-        },
+    /**
+     * Returns index within the collection of the passed key.
+     * @param {String} key The key to find the index of.
+     * @return {Number} index of the key.
+     */
+    indexOfKey : function(key){
+        return Ext.Array.indexOf(this.keys, key);
+    },
 
-        /**
-         * Restores the specified properties from this memento to the target object.
-         * @param {String|Array} props The property or array of properties to restore.
-         * @param {Boolean} clear True to remove the restored properties from this memento or
-         * false to keep them (default is true).
-         * @param {Object} target The object to which to restore properties.
-         */
-        restore: function (props, clear, target) {
-            doMany(restoreOne, this.data, target || this.target, props);
-            if (clear !== false) {
-                this.remove(props);
-            }
-        },
+    /**
+     * Returns the item associated with the passed key OR index.
+     * Key has priority over index.  This is the equivalent
+     * of calling {@link #getByKey} first, then if nothing matched calling {@link #getAt}.
+     * @param {String/Number} key The key or index of the item.
+     * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.
+     * If an item was found, but is a Class, returns <tt>null</tt>.
+     */
+    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; // for prototype!
+    },
 
-        /**
-         * Restores all captured properties in this memento to the target object.
-         * @param {Boolean} clear True to remove the restored properties from this memento or
-         * false to keep them (default is true).
-         * @param {Object} target The object to which to restore properties.
-         */
-        restoreAll: function (clear, target) {
-            var me = this,
-                t = target || this.target;
+    /**
+     * Returns the item at the specified index.
+     * @param {Number} index The index of the item.
+     * @return {Object} The item at the specified index.
+     */
+    getAt : function(index) {
+        return this.items[index];
+    },
 
-            Ext.Object.each(me.data, function (prop, value) {
-                restoreValue(t, prop, value);
-            });
+    /**
+     * Returns the item associated with the passed key.
+     * @param {String/Number} key The key of the item.
+     * @return {Object} The item associated with the passed key.
+     */
+    getByKey : function(key) {
+        return this.map[key];
+    },
 
-            if (clear !== false) {
-                delete me.data;
-            }
-        }
-    };
-}());
+    /**
+     * Returns true if the collection contains the passed Object as an item.
+     * @param {Object} o  The Object to look for in the collection.
+     * @return {Boolean} True if the collection contains the Object as an item.
+     */
+    contains : function(o){
+        return Ext.Array.contains(this.items, o);
+    },
 
-/**
- * @class Ext.app.EventBus
- * @private
- *
- * Class documentation for the MVC classes will be present before 4.0 final, in the mean time please refer to the MVC
- * guide
- */
-Ext.define('Ext.app.EventBus', {
-    requires: [
-        'Ext.util.Event'
-    ],
-    mixins: {
-        observable: 'Ext.util.Observable'
+    /**
+     * Returns true if the collection contains the passed Object as a key.
+     * @param {String} key The key to look for in the collection.
+     * @return {Boolean} True if the collection contains the Object as a key.
+     */
+    containsKey : function(key){
+        return typeof this.map[key] != 'undefined';
     },
-    
-    constructor: function() {
-        this.mixins.observable.constructor.call(this);
-        
-        this.bus = {};
-        
+
+    /**
+     * Removes all items from the collection.  Fires the {@link #clear} event when complete.
+     */
+    clear : function(){
         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) {
-            // Loop over all the selectors that are bound to this event
-            for (selector in selectors) {
-                // Check if the target matches the selector
-                if (target.is(selector)) {
-                    // Loop over all the controllers that are bound to this selector   
-                    controllers = selectors[selector];
-                    for (id in controllers) {
-                        // Loop over all the events that are bound to this selector on this controller
-                        events = controllers[id];
-                        for (i = 0, ln = events.length; i < ln; i++) {
-                            event = events[i];
-                            // Fire the event!
-                            if (event.fire.apply(event, Array.prototype.slice.call(args, 1)) === false) {
-                                return false;
-                            };
-                        }
-                    }
-                }
-            }
-        }
+        me.length = 0;
+        me.items = [];
+        me.keys = [];
+        me.map = {};
+        me.fireEvent('clear');
     },
-    
-    control: function(selectors, listeners, controller) {
-        var bus = this.bus,
-            selector, fn;
-        
-        if (Ext.isString(selectors)) {
-            selector = selectors;
-            selectors = {};
-            selectors[selector] = listeners;
-            this.control(selectors, null, controller);
-            return;
-        }
-    
-        Ext.Object.each(selectors, function(selector, listeners) {
-            Ext.Object.each(listeners, function(ev, listener) {
-                var options = {},   
-                    scope = controller,
-                    event = Ext.create('Ext.util.Event', controller, ev);
-                
-                // Normalize the listener                
-                if (Ext.isObject(listener)) {
-                    options = listener;
-                    listener = options.fn;
-                    scope = options.scope || controller;
-                    delete options.fn;
-                    delete options.scope;
-                }
-                
-                event.addListener(listener, scope, options);
 
-                // Create the bus tree if it is not there yet
-                bus[ev] = bus[ev] || {};
-                bus[ev][selector] = bus[ev][selector] || {};
-                bus[ev][selector][controller.id] = bus[ev][selector][controller.id] || [];            
-                
-                // Push our listener in our bus
-                bus[ev][selector][controller.id].push(event);
-            });
-        });
-    }
-});
-/**
- * @class Ext.data.Types
- * <p>This is s static class containing the system-supplied data types which may be given to a {@link Ext.data.Field Field}.<p/>
- * <p>The properties in this class are used as type indicators in the {@link Ext.data.Field Field} class, so to
- * test whether a Field is of a certain type, compare the {@link Ext.data.Field#type type} property against properties
- * of this class.</p>
- * <p>Developers may add their own application-specific data types to this class. Definition names must be UPPERCASE.
- * each type definition must contain three properties:</p>
- * <div class="mdetail-params"><ul>
- * <li><code>convert</code> : <i>Function</i><div class="sub-desc">A function to convert raw data values from a data block into the data
- * to be stored in the Field. The function is passed the collowing parameters:
- * <div class="mdetail-params"><ul>
- * <li><b>v</b> : Mixed<div class="sub-desc">The data value as read by the Reader, if undefined will use
- * the configured <tt>{@link Ext.data.Field#defaultValue defaultValue}</tt>.</div></li>
- * <li><b>rec</b> : Mixed<div class="sub-desc">The data object containing the row as read by the Reader.
- * Depending on the Reader type, this could be an Array ({@link Ext.data.reader.Array ArrayReader}), an object
- * ({@link Ext.data.reader.Json JsonReader}), or an XML element.</div></li>
- * </ul></div></div></li>
- * <li><code>sortType</code> : <i>Function</i> <div class="sub-desc">A function to convert the stored data into comparable form, as defined by {@link Ext.data.SortTypes}.</div></li>
- * <li><code>type</code> : <i>String</i> <div class="sub-desc">A textual data type name.</div></li>
- * </ul></div>
- * <p>For example, to create a VELatLong field (See the Microsoft Bing Mapping API) containing the latitude/longitude value of a datapoint on a map from a JsonReader data block
- * which contained the properties <code>lat</code> and <code>long</code>, you would define a new data type like this:</p>
- *<pre><code>
-// Add a new Field data type which stores a VELatLong object in the Record.
-Ext.data.Types.VELATLONG = {
-    convert: function(v, data) {
-        return new VELatLong(data.lat, data.long);
-    },
-    sortType: function(v) {
-        return v.Latitude;  // When sorting, order by latitude
+    /**
+     * Returns the first item in the collection.
+     * @return {Object} the first item in the collection..
+     */
+    first : function() {
+        return this.items[0];
     },
-    type: 'VELatLong'
-};
-</code></pre>
- * <p>Then, when declaring a Model, use <pre><code>
-var types = Ext.data.Types; // allow shorthand type access
-Ext.define('Unit',
-    extend: 'Ext.data.Model', 
-    fields: [
-        { name: 'unitName', mapping: 'UnitName' },
-        { name: 'curSpeed', mapping: 'CurSpeed', type: types.INT },
-        { name: 'latitude', mapping: 'lat', type: types.FLOAT },
-        { name: 'latitude', mapping: 'lat', type: types.FLOAT },
-        { name: 'position', type: types.VELATLONG }
-    ]
-});
-</code></pre>
- * @singleton
- */
-Ext.define('Ext.data.Types', {
-    singleton: true,
-    requires: ['Ext.data.SortTypes']
-}, function() {
-    var st = Ext.data.SortTypes;
-    
-    Ext.apply(Ext.data.Types, {
-        /**
-         * @type Regexp
-         * @property stripRe
-         * A regular expression for stripping non-numeric characters from a numeric value. Defaults to <tt>/[\$,%]/g</tt>.
-         * This should be overridden for localization.
-         */
-        stripRe: /[\$,%]/g,
-        
-        /**
-         * @type Object.
-         * @property AUTO
-         * This data type means that no conversion is applied to the raw data before it is placed into a Record.
-         */
-        AUTO: {
-            convert: function(v) {
-                return v;
-            },
-            sortType: st.none,
-            type: 'auto'
-        },
-
-        /**
-         * @type Object.
-         * @property STRING
-         * This data type means that the raw data is converted into a String before it is placed into a Record.
-         */
-        STRING: {
-            convert: function(v) {
-                var defaultValue = this.useNull ? null : '';
-                return (v === undefined || v === null) ? defaultValue : String(v);
-            },
-            sortType: st.asUCString,
-            type: 'string'
-        },
 
-        /**
-         * @type Object.
-         * @property INT
-         * This data type means that the raw data is converted into an integer before it is placed into a Record.
-         * <p>The synonym <code>INTEGER</code> is equivalent.</p>
-         */
-        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'
-        },
-        
-        /**
-         * @type Object.
-         * @property FLOAT
-         * This data type means that the raw data is converted into a number before it is placed into a Record.
-         * <p>The synonym <code>NUMBER</code> is equivalent.</p>
-         */
-        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'
-        },
-        
-        /**
-         * @type Object.
-         * @property BOOL
-         * <p>This data type means that the raw data is converted into a boolean before it is placed into
-         * a Record. The string "true" and the number 1 are converted to boolean <code>true</code>.</p>
-         * <p>The synonym <code>BOOLEAN</code> is equivalent.</p>
-         */
-        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'
-        },
-        
-        /**
-         * @type Object.
-         * @property DATE
-         * This data type means that the raw data is converted into a Date before it is placed into a Record.
-         * The date format is specified in the constructor of the {@link Ext.data.Field} to which this type is
-         * being applied.
-         */
-        DATE: {
-            convert: function(v) {
-                var df = this.dateFormat;
-                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);
-                }
-                
-                var parsed = Date.parse(v);
-                return parsed ? new Date(parsed) : null;
-            },
-            sortType: st.asDate,
-            type: 'date'
-        }
-    });
-    
-    Ext.apply(Ext.data.Types, {
-        /**
-         * @type Object.
-         * @property BOOLEAN
-         * <p>This data type means that the raw data is converted into a boolean before it is placed into
-         * a Record. The string "true" and the number 1 are converted to boolean <code>true</code>.</p>
-         * <p>The synonym <code>BOOL</code> is equivalent.</p>
-         */
-        BOOLEAN: this.BOOL,
-        
-        /**
-         * @type Object.
-         * @property INTEGER
-         * This data type means that the raw data is converted into an integer before it is placed into a Record.
-         * <p>The synonym <code>INT</code> is equivalent.</p>
-         */
-        INTEGER: this.INT,
-        
-        /**
-         * @type Object.
-         * @property NUMBER
-         * This data type means that the raw data is converted into a number before it is placed into a Record.
-         * <p>The synonym <code>FLOAT</code> is equivalent.</p>
-         */
-        NUMBER: this.FLOAT    
-    });
-});
+    /**
+     * Returns the last item in the collection.
+     * @return {Object} the last item in the collection..
+     */
+    last : function() {
+        return this.items[this.length - 1];
+    },
 
-/**
- * @author Ed Spencer
- * @class Ext.data.Field
- * @extends Object
- * 
- * <p>Fields are used to define what a Model is. They aren't instantiated directly - instead, when we create a class 
- * that extends {@link Ext.data.Model}, it will automatically create a Field instance for each field configured in a 
- * {@link Ext.data.Model Model}. For example, we might set up a model like this:</p>
- * 
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: [
-        'name', 'email',
-        {name: 'age', type: 'int'},
-        {name: 'gender', type: 'string', defaultValue: 'Unknown'}
-    ]
-});
-</code></pre>
- * 
- * <p>Four fields will have been created for the User Model - name, email, age and gender. Note that we specified a
- * couple of different formats here; if we only pass in the string name of the field (as with name and email), the
- * field is set up with the 'auto' type. It's as if we'd done this instead:</p>
- * 
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'name', type: 'auto'},
-        {name: 'email', type: 'auto'},
-        {name: 'age', type: 'int'},
-        {name: 'gender', type: 'string', defaultValue: 'Unknown'}
-    ]
-});
-</code></pre>
- * 
- * <p><u>Types and conversion</u></p>
- * 
- * <p>The {@link #type} is important - it's used to automatically convert data passed to the field into the correct
- * format. In our example above, the name and email fields used the 'auto' type and will just accept anything that is
- * passed into them. The 'age' field had an 'int' type however, so if we passed 25.4 this would be rounded to 25.</p>
- * 
- * <p>Sometimes a simple type isn't enough, or we want to perform some processing when we load a Field's data. We can
- * do this using a {@link #convert} function. Here, we're going to create a new field based on another:</p>
- * 
-<code><pre>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: [
-        'name', 'email',
-        {name: 'age', type: 'int'},
-        {name: 'gender', type: 'string', defaultValue: 'Unknown'},
+    /**
+     * Collects all of the values of the given property and returns their sum
+     * @param {String} property The property to sum by
+     * @param {String} [root] 'root' property to extract the first argument from. This is used mainly when
+     * summing fields in records, where the fields are all stored inside the 'data' object
+     * @param {Number} [start=0] The record index to start at
+     * @param {Number} [end=-1] The record index to end at
+     * @return {Number} The total
+     */
+    sum: function(property, root, start, end) {
+        var values = this.extractValues(property, root),
+            length = values.length,
+            sum    = 0,
+            i;
 
-        {
-            name: 'firstName',
-            convert: function(value, record) {
-                var fullName  = record.get('name'),
-                    splits    = fullName.split(" "),
-                    firstName = splits[0];
+        start = start || 0;
+        end   = (end || end === 0) ? end : length - 1;
 
-                return firstName;
-            }
+        for (i = start; i <= end; i++) {
+            sum += values[i];
         }
-    ]
-});
-</code></pre>
- * 
- * <p>Now when we create a new User, the firstName is populated automatically based on the name:</p>
- * 
-<code><pre>
-var ed = Ext.ModelManager.create({name: 'Ed Spencer'}, 'User');
 
-console.log(ed.get('firstName')); //logs 'Ed', based on our convert function
-</code></pre>
- * 
- * <p>In fact, if we log out all of the data inside ed, we'll see this:</p>
- * 
-<code><pre>
-console.log(ed.data);
+        return sum;
+    },
 
-//outputs this:
-{
-    age: 0,
-    email: "",
-    firstName: "Ed",
-    gender: "Unknown",
-    name: "Ed Spencer"
-}
-</code></pre>
- * 
- * <p>The age field has been given a default of zero because we made it an int type. As an auto field, email has
- * defaulted to an empty string. When we registered the User model we set gender's {@link #defaultValue} to 'Unknown'
- * so we see that now. Let's correct that and satisfy ourselves that the types work as we expect:</p>
- * 
-<code><pre>
-ed.set('gender', 'Male');
-ed.get('gender'); //returns 'Male'
+    /**
+     * Collects unique values of a particular property in this MixedCollection
+     * @param {String} property The property to collect on
+     * @param {String} root (optional) 'root' property to extract the first argument from. This is used mainly when
+     * summing fields in records, where the fields are all stored inside the 'data' object
+     * @param {Boolean} allowBlank (optional) Pass true to allow null, undefined or empty string values
+     * @return {Array} The unique values
+     */
+    collect: function(property, root, allowNull) {
+        var values = this.extractValues(property, root),
+            length = values.length,
+            hits   = {},
+            unique = [],
+            value, strValue, i;
 
-ed.set('age', 25.4);
-ed.get('age'); //returns 25 - we wanted an int, not a float, so no decimal places allowed
-</code></pre>
- * 
- */
-Ext.define('Ext.data.Field', {
-    requires: ['Ext.data.Types', 'Ext.data.SortTypes'],
-    alias: 'data.field',
-    
-    constructor : function(config) {
-        if (Ext.isString(config)) {
-            config = {name: config};
-        }
-        Ext.apply(this, config);
-        
-        var types = Ext.data.Types,
-            st = this.sortType,
-            t;
+        for (i = 0; i < length; i++) {
+            value = values[i];
+            strValue = String(value);
 
-        if (this.type) {
-            if (Ext.isString(this.type)) {
-                this.type = types[this.type.toUpperCase()] || types.AUTO;
+            if ((allowNull || !Ext.isEmpty(value)) && !hits[strValue]) {
+                hits[strValue] = true;
+                unique.push(value);
             }
-        } else {
-            this.type = types.AUTO;
-        }
-
-        // named sortTypes are supported, here we look them up
-        if (Ext.isString(st)) {
-            this.sortType = Ext.data.SortTypes[st];
-        } else if(Ext.isEmpty(st)) {
-            this.sortType = this.type.sortType;
         }
 
-        if (!this.convert) {
-            this.convert = this.type.convert;
-        }
+        return unique;
     },
-    
-    /**
-     * @cfg {String} name
-     * The name by which the field is referenced within the Model. This is referenced by, for example,
-     * the <code>dataIndex</code> property in column definition objects passed to {@link Ext.grid.property.HeaderContainer}.
-     * <p>Note: In the simplest case, if no properties other than <code>name</code> are required, a field
-     * definition may consist of just a String for the field name.</p>
-     */
-    
+
     /**
-     * @cfg {Mixed} type
-     * (Optional) The data type for automatic conversion from received data to the <i>stored</i> value if <code>{@link Ext.data.Field#convert convert}</code>
-     * has not been specified. This may be specified as a string value. Possible values are
-     * <div class="mdetail-params"><ul>
-     * <li>auto (Default, implies no conversion)</li>
-     * <li>string</li>
-     * <li>int</li>
-     * <li>float</li>
-     * <li>boolean</li>
-     * <li>date</li></ul></div>
-     * <p>This may also be specified by referencing a member of the {@link Ext.data.Types} class.</p>
-     * <p>Developers may create their own application-specific data types by defining new members of the
-     * {@link Ext.data.Types} class.</p>
+     * @private
+     * Extracts all of the given property values from the items in the MC. Mainly used as a supporting method for
+     * functions like sum and collect.
+     * @param {String} property The property to extract
+     * @param {String} root (optional) 'root' property to extract the first argument from. This is used mainly when
+     * extracting field data from Model instances, where the fields are stored inside the 'data' object
+     * @return {Array} The extracted values
      */
-    
-    /**
-     * @cfg {Function} convert
-     * (Optional) A function which converts the value provided by the Reader into an object that will be stored
-     * in the Model. It is passed the following parameters:<div class="mdetail-params"><ul>
-     * <li><b>v</b> : Mixed<div class="sub-desc">The data value as read by the Reader, if undefined will use
-     * the configured <code>{@link Ext.data.Field#defaultValue defaultValue}</code>.</div></li>
-     * <li><b>rec</b> : Ext.data.Model<div class="sub-desc">The data object containing the Model as read so far by the 
-     * Reader. Note that the Model may not be fully populated at this point as the fields are read in the order that 
-     * they are defined in your {@link #fields} array.</div></li>
-     * </ul></div>
-     * <pre><code>
-// example of convert function
-function fullName(v, record){
-    return record.name.last + ', ' + record.name.first;
-}
-
-function location(v, record){
-    return !record.city ? '' : (record.city + ', ' + record.state);
-}
-
-Ext.define('Dude', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'fullname',  convert: fullName},
-        {name: 'firstname', mapping: 'name.first'},
-        {name: 'lastname',  mapping: 'name.last'},
-        {name: 'city', defaultValue: 'homeless'},
-        'state',
-        {name: 'location',  convert: location}
-    ]
-});
+    extractValues: function(property, root) {
+        var values = this.items;
 
-// create the data store
-var store = new Ext.data.Store({
-    reader: {
-        type: 'json',
-        model: 'Dude',
-        idProperty: 'key',
-        root: 'daRoot',
-        totalProperty: 'total'
-    }
-});
+        if (root) {
+            values = Ext.Array.pluck(values, root);
+        }
 
-var myData = [
-    { key: 1,
-      name: { first: 'Fat',    last:  'Albert' }
-      // notice no city, state provided in data object
-    },
-    { key: 2,
-      name: { first: 'Barney', last:  'Rubble' },
-      city: 'Bedrock', state: 'Stoneridge'
+        return Ext.Array.pluck(values, property);
     },
-    { key: 3,
-      name: { first: 'Cliff',  last:  'Claven' },
-      city: 'Boston',  state: 'MA'
-    }
-];
-     * </code></pre>
-     */
+
     /**
-     * @cfg {String} dateFormat
-     * <p>(Optional) Used when converting received data into a Date when the {@link #type} is specified as <code>"date"</code>.</p>
-     * <p>A format string for the {@link Ext.Date#parse Ext.Date.parse} function, or "timestamp" if the
-     * value provided by the Reader is a UNIX timestamp, or "time" if the value provided by the Reader is a
-     * javascript millisecond timestamp. See {@link Ext.Date}</p>
+     * Returns a range of items in this collection
+     * @param {Number} startIndex (optional) The starting index. Defaults to 0.
+     * @param {Number} endIndex (optional) The ending index. Defaults to the last item.
+     * @return {Array} An array of items
      */
-    dateFormat: null,
-    
+    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;
+    },
+
     /**
-     * @cfg {Boolean} useNull
-     * <p>(Optional) Use when converting received data into a Number type (either int or float). If the value cannot be parsed,
-     * null will be used if useNull is true, otherwise the value will be 0. Defaults to <tt>false</tt>
-     */
-    useNull: false,
-    
-    /**
-     * @cfg {Mixed} defaultValue
-     * (Optional) The default value used <b>when a Model is being created by a {@link Ext.data.reader.Reader Reader}</b>
-     * when the item referenced by the <code>{@link Ext.data.Field#mapping mapping}</code> does not exist in the data
-     * object (i.e. undefined). (defaults to "")
-     */
-    defaultValue: "",
-    /**
-     * @cfg {String/Number} mapping
-     * <p>(Optional) A path expression for use by the {@link Ext.data.reader.Reader} implementation
-     * that is creating the {@link Ext.data.Model Model} to extract the Field value from the data object.
-     * If the path expression is the same as the field name, the mapping may be omitted.</p>
-     * <p>The form of the mapping expression depends on the Reader being used.</p>
-     * <div class="mdetail-params"><ul>
-     * <li>{@link Ext.data.reader.Json}<div class="sub-desc">The mapping is a string containing the javascript
-     * expression to reference the data from an element of the data item's {@link Ext.data.reader.Json#root root} Array. Defaults to the field name.</div></li>
-     * <li>{@link Ext.data.reader.Xml}<div class="sub-desc">The mapping is an {@link Ext.DomQuery} path to the data
-     * item relative to the DOM element that represents the {@link Ext.data.reader.Xml#record record}. Defaults to the field name.</div></li>
-     * <li>{@link Ext.data.reader.Array}<div class="sub-desc">The mapping is a number indicating the Array index
-     * of the field's value. Defaults to the field specification's Array position.</div></li>
-     * </ul></div>
-     * <p>If a more complex value extraction strategy is required, then configure the Field with a {@link #convert}
-     * function. This is passed the whole row object, and may interrogate it in whatever way is necessary in order to
-     * return the desired data.</p>
-     */
-    mapping: null,
-    /**
-     * @cfg {Function} sortType
-     * (Optional) A function which converts a Field's value to a comparable value in order to ensure
-     * correct sort ordering. Predefined functions are provided in {@link Ext.data.SortTypes}. A custom
-     * sort example:<pre><code>
-// current sort     after sort we want
-// +-+------+          +-+------+
-// |1|First |          |1|First |
-// |2|Last  |          |3|Second|
-// |3|Second|          |2|Last  |
-// +-+------+          +-+------+
-
-sortType: function(value) {
-   switch (value.toLowerCase()) // native toLowerCase():
-   {
-      case 'first': return 1;
-      case 'second': return 2;
-      default: return 3;
-   }
-}
-     * </code></pre>
-     */
-    sortType : null,
-    /**
-     * @cfg {String} sortDir
-     * (Optional) Initial direction to sort (<code>"ASC"</code> or  <code>"DESC"</code>).  Defaults to
-     * <code>"ASC"</code>.
-     */
-    sortDir : "ASC",
-    /**
-     * @cfg {Boolean} allowBlank
-     * @private
-     * (Optional) Used for validating a {@link Ext.data.Model model}, defaults to <code>true</code>.
-     * An empty value here will cause {@link Ext.data.Model}.{@link Ext.data.Model#isValid isValid}
-     * to evaluate to <code>false</code>.
-     */
-    allowBlank : true,
-    
-    /**
-     * @cfg {Boolean} persist
-     * False to exclude this field from the {@link Ext.data.Model#modified} fields in a model. This 
-     * will also exclude the field from being written using a {@link Ext.data.writer.Writer}. This option
-     * is useful when model fields are used to keep state on the client but do not need to be persisted
-     * to the server. Defaults to <tt>true</tt>.
-     */
-    persist: true
-});
-
-/**
- * @author Ed Spencer
- * @class Ext.data.reader.Reader
- * @extends Object
- * 
- * <p>Readers are used to interpret data to be loaded into a {@link Ext.data.Model Model} instance or a {@link Ext.data.Store Store}
- * - usually in response to an AJAX request. This is normally handled transparently by passing some configuration to either the 
- * {@link Ext.data.Model Model} or the {@link Ext.data.Store Store} in question - see their documentation for further details.</p>
- * 
- * <p><u>Loading Nested Data</u></p>
- * 
- * <p>Readers have the ability to automatically load deeply-nested data objects based on the {@link Ext.data.Association associations}
- * configured on each Model. Below is an example demonstrating the flexibility of these associations in a fictional CRM system which
- * manages a User, their Orders, OrderItems and Products. First we'll define the models:
- * 
+     * <p>Filters the objects in this collection by a set of {@link Ext.util.Filter Filter}s, or by a single
+     * property/value pair with optional parameters for substring matching and case sensitivity. See
+     * {@link Ext.util.Filter Filter} for an example of using Filter objects (preferred). Alternatively,
+     * MixedCollection can be easily filtered by property like this:</p>
 <pre><code>
-Ext.define("User", {
-    extend: 'Ext.data.Model',
-    fields: [
-        'id', 'name'
-    ],
+//create a simple store with a few people defined
+var people = new Ext.util.MixedCollection();
+people.addAll([
+    {id: 1, age: 25, name: 'Ed'},
+    {id: 2, age: 24, name: 'Tommy'},
+    {id: 3, age: 24, name: 'Arne'},
+    {id: 4, age: 26, name: 'Aaron'}
+]);
 
-    hasMany: {model: 'Order', name: 'orders'},
+//a new MixedCollection containing only the items where age == 24
+var middleAged = people.filter('age', 24);
+</code></pre>
+     *
+     *
+     * @param {Ext.util.Filter[]/String} property A property on your objects, or an array of {@link Ext.util.Filter Filter} objects
+     * @param {String/RegExp} value Either string that the property values
+     * should start with or a RegExp to test against the property
+     * @param {Boolean} [anyMatch=false] True to match any part of the string, not just the beginning
+     * @param {Boolean} [caseSensitive=false] True for case sensitive comparison.
+     * @return {Ext.util.MixedCollection} The new filtered collection
+     */
+    filter : function(property, value, anyMatch, caseSensitive) {
+        var filters = [],
+            filterFn;
 
-    proxy: {
-        type: 'rest',
-        url : 'users.json',
-        reader: {
-            type: 'json',
-            root: 'users'
+        //support for the simple case of filtering by property/value
+        if (Ext.isString(property)) {
+            filters.push(Ext.create('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);
         }
-    }
-});
-
-Ext.define("Order", {
-    extend: 'Ext.data.Model',
-    fields: [
-        'id', 'total'
-    ],
 
-    hasMany  : {model: 'OrderItem', name: 'orderItems', associationKey: 'order_items'},
-    belongsTo: 'User'
-});
+        //at this point we have an array of zero or more Ext.util.Filter objects to filter with,
+        //so here we construct a function that combines these filters by ANDing them together
+        filterFn = function(record) {
+            var isMatch = true,
+                length = filters.length,
+                i;
 
-Ext.define("OrderItem", {
-    extend: 'Ext.data.Model',
-    fields: [
-        'id', 'price', 'quantity', 'order_id', 'product_id'
-    ],
+            for (i = 0; i < length; i++) {
+                var filter = filters[i],
+                    fn     = filter.filterFn,
+                    scope  = filter.scope;
 
-    belongsTo: ['Order', {model: 'Product', associationKey: 'product'}]
-});
+                isMatch = isMatch && fn.call(scope, record);
+            }
 
-Ext.define("Product", {
-    extend: 'Ext.data.Model',
-    fields: [
-        'id', 'name'
-    ],
+            return isMatch;
+        };
 
-    hasMany: 'OrderItem'
-});
-</code></pre>
- * 
- * <p>This may be a lot to take in - basically a User has many Orders, each of which is composed of several OrderItems. Finally,
- * each OrderItem has a single Product. This allows us to consume data like this:</p>
- * 
-<pre><code>
-{
-    "users": [
-        {
-            "id": 123,
-            "name": "Ed",
-            "orders": [
-                {
-                    "id": 50,
-                    "total": 100,
-                    "order_items": [
-                        {
-                            "id"      : 20,
-                            "price"   : 40,
-                            "quantity": 2,
-                            "product" : {
-                                "id": 1000,
-                                "name": "MacBook Pro"
-                            }
-                        },
-                        {
-                            "id"      : 21,
-                            "price"   : 20,
-                            "quantity": 3,
-                            "product" : {
-                                "id": 1001,
-                                "name": "iPhone"
-                            }
-                        }
-                    ]
-                }
-            ]
-        }
-    ]
-}
-</code></pre>
- * 
- * <p>The JSON response is deeply nested - it returns all Users (in this case just 1 for simplicity's sake), all of the Orders
- * for each User (again just 1 in this case), all of the OrderItems for each Order (2 order items in this case), and finally
- * the Product associated with each OrderItem. Now we can read the data and use it as follows:
- * 
-<pre><code>
-var store = new Ext.data.Store({
-    model: "User"
-});
+        return this.filterBy(filterFn);
+    },
 
-store.load({
-    callback: function() {
-        //the user that was loaded
-        var user = store.first();
+    /**
+     * Filter by a function. Returns a <i>new</i> collection that has been filtered.
+     * The passed function will be called with each object in the collection.
+     * If the function returns true, the value is included otherwise it is filtered.
+     * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
+     * @return {Ext.util.MixedCollection} The new filtered collection
+     */
+    filterBy : function(fn, scope) {
+        var me = this,
+            newMC  = new this.self(),
+            keys   = me.keys,
+            items  = me.items,
+            length = items.length,
+            i;
 
-        console.log("Orders for " + user.get('name') + ":")
+        newMC.getKey = me.getKey;
 
-        //iterate over the Orders for each User
-        user.orders().each(function(order) {
-            console.log("Order ID: " + order.getId() + ", which contains items:");
+        for (i = 0; i < length; i++) {
+            if (fn.call(scope || me, items[i], keys[i])) {
+                newMC.add(keys[i], items[i]);
+            }
+        }
 
-            //iterate over the OrderItems for each Order
-            order.orderItems().each(function(orderItem) {
-                //we know that the Product data is already loaded, so we can use the synchronous getProduct
-                //usually, we would use the asynchronous version (see {@link Ext.data.BelongsToAssociation})
-                var product = orderItem.getProduct();
+        return newMC;
+    },
 
-                console.log(orderItem.get('quantity') + ' orders of ' + product.get('name'));
-            });
-        });
-    }
-});
-</code></pre>
- * 
- * <p>Running the code above results in the following:</p>
- * 
-<pre><code>
-Orders for Ed:
-Order ID: 50, which contains items:
-2 orders of MacBook Pro
-3 orders of iPhone
-</code></pre>
- * 
- */
-Ext.define('Ext.data.reader.Reader', {
-    requires: ['Ext.data.ResultSet'],
-    alternateClassName: ['Ext.data.Reader', 'Ext.data.DataReader'],
-    
     /**
-     * @cfg {String} idProperty Name of the property within a row object
-     * that contains a record identifier value.  Defaults to <tt>The id of the model</tt>.
-     * If an idProperty is explicitly specified it will override that of the one specified
-     * on the model
+     * Finds the index of the first matching object in this collection by a specific property/value.
+     * @param {String} property The name of a property on your objects.
+     * @param {String/RegExp} value A string that the property values
+     * should start with or a RegExp to test against the property.
+     * @param {Number} [start=0] The index to start searching at.
+     * @param {Boolean} [anyMatch=false] True to match any part of the string, not just the beginning.
+     * @param {Boolean} [caseSensitive=false] True for case sensitive comparison.
+     * @return {Number} The matched index or -1
      */
+    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);
+    },
 
     /**
-     * @cfg {String} totalProperty Name of the property from which to
-     * retrieve the total number of records in the dataset. This is only needed
-     * if the whole dataset is not passed in one go, but is being paged from
-     * the remote server.  Defaults to <tt>total</tt>.
+     * Find the index of the first matching object in this collection by a function.
+     * If the function returns <i>true</i> it is considered a match.
+     * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).
+     * @param {Object} [scope] The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
+     * @param {Number} [start=0] The index to start searching at.
+     * @return {Number} The matched index or -1
      */
-    totalProperty: 'total',
+    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;
+    },
 
     /**
-     * @cfg {String} successProperty Name of the property from which to
-     * retrieve the success attribute. Defaults to <tt>success</tt>.  See
-     * {@link Ext.data.proxy.Proxy}.{@link Ext.data.proxy.Proxy#exception exception}
-     * for additional information.
+     * Returns a regular expression based on the given value and matching options. This is used internally for finding and filtering,
+     * and by Ext.data.Store#filter
+     * @private
+     * @param {String} value The value to create the regex for. This is escaped using Ext.escapeRe
+     * @param {Boolean} anyMatch True to allow any match - no regex start/end line anchors will be added. Defaults to false
+     * @param {Boolean} caseSensitive True to make the regex case sensitive (adds 'i' switch to regex). Defaults to false.
+     * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false. Ignored if anyMatch is true.
      */
-    successProperty: 'success',
+    createValueMatcher : function(value, anyMatch, caseSensitive, exactMatch) {
+        if (!value.exec) { // not a regex
+            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;
+    },
 
     /**
-     * @cfg {String} root <b>Required</b>.  The name of the property
-     * which contains the Array of row objects.  Defaults to <tt>undefined</tt>.
-     * An exception will be thrown if the root property is undefined. The data
-     * packet value for this property should be an empty array to clear the data
-     * or show no data.
+     * Creates a shallow copy of this collection
+     * @return {Ext.util.MixedCollection}
      */
-    root: '',
-    
+    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;
+    }
+});
+
+/**
+ * @docauthor Tommy Maintz <tommy@sencha.com>
+ *
+ * A mixin which allows a data component to be sorted. This is used by e.g. {@link Ext.data.Store} and {@link Ext.data.TreeStore}.
+ *
+ * **NOTE**: This mixin is mainly for internal use and most users should not need to use it directly. It
+ * is more likely you will want to use one of the component classes that import this mixin, such as
+ * {@link Ext.data.Store} or {@link Ext.data.TreeStore}.
+ */
+Ext.define("Ext.util.Sortable", {
     /**
-     * @cfg {String} messageProperty The name of the property which contains a response message.
-     * This property is optional.
+     * @property {Boolean} isSortable
+     * Flag denoting that this object is sortable. Always true.
      */
-    
+    isSortable: true,
+
     /**
-     * @cfg {Boolean} implicitIncludes True to automatically parse models nested within other models in a response
-     * object. See the Ext.data.reader.Reader intro docs for full explanation. Defaults to true.
+     * @property {String} defaultSortDirection
+     * The default sort direction to use if one is not specified.
      */
-    implicitIncludes: true,
-    
-    isReader: true,
-    
+    defaultSortDirection: "ASC",
+
+    requires: [
+        'Ext.util.Sorter'
+    ],
+
     /**
-     * Creates new Reader.
-     * @param {Object} config (optional) Config object.
+     * @property {String} sortRoot
+     * The property in each item that contains the data to sort.
      */
-    constructor: function(config) {
-        var me = this;
-        
-        Ext.apply(me, config || {});
-        me.fieldCount = 0;
-        me.model = Ext.ModelManager.getModel(config.model);
-        if (me.model) {
-            me.buildExtractors();
-        }
-    },
 
     /**
-     * Sets a new model for the reader.
-     * @private
-     * @param {Object} model The model to set.
-     * @param {Boolean} setOnProxy True to also set on the Proxy, if one is configured
+     * Performs initialization of this mixin. Component classes using this mixin should call this method during their
+     * own initialization.
      */
-    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);
+    initSortable: function() {
+        var me = this,
+            sorters = me.sorters;
+
+        /**
+         * @property {Ext.util.MixedCollection} sorters
+         * The collection of {@link Ext.util.Sorter Sorters} currently applied to this Store
+         */
+        me.sorters = Ext.create('Ext.util.AbstractMixedCollection', false, function(item) {
+            return item.id || item.property;
+        });
+
+        if (sorters) {
+            me.sorters.addAll(me.decodeSorters(sorters));
         }
     },
 
     /**
-     * Reads the given response object. This method normalizes the different types of response object that may be passed
-     * to it, before handing off the reading of records to the {@link #readRecords} function.
-     * @param {Object} response The response object. This may be either an XMLHttpRequest object or a plain JS object
-     * @return {Ext.data.ResultSet} The parsed ResultSet object
+     * Sorts the data in the Store by one or more of its properties. Example usage:
+     *
+     *     //sort by a single field
+     *     myStore.sort('myField', 'DESC');
+     *
+     *     //sorting by multiple fields
+     *     myStore.sort([
+     *         {
+     *             property : 'age',
+     *             direction: 'ASC'
+     *         },
+     *         {
+     *             property : 'name',
+     *             direction: 'DESC'
+     *         }
+     *     ]);
+     *
+     * Internally, Store converts the passed arguments into an array of {@link Ext.util.Sorter} instances, and delegates
+     * the actual sorting to its internal {@link Ext.util.MixedCollection}.
+     *
+     * When passing a single string argument to sort, Store maintains a ASC/DESC toggler per field, so this code:
+     *
+     *     store.sort('myField');
+     *     store.sort('myField');
+     *
+     * Is equivalent to this code, because Store handles the toggling automatically:
+     *
+     *     store.sort('myField', 'ASC');
+     *     store.sort('myField', 'DESC');
+     *
+     * @param {String/Ext.util.Sorter[]} sorters Either a string name of one of the fields in this Store's configured
+     * {@link Ext.data.Model Model}, or an array of sorter configurations.
+     * @param {String} direction The overall direction to sort the data by. Defaults to "ASC".
+     * @return {Ext.util.Sorter[]}
      */
-    read: function(response) {
-        var data = response;
-        
-        if (response && response.responseText) {
-            data = this.getResponseData(response);
+    sort: function(sorters, direction, where, doSort) {
+        var me = this,
+            sorter, sorterFn,
+            newSorters;
+
+        if (Ext.isArray(sorters)) {
+            doSort = where;
+            where = direction;
+            newSorters = sorters;
         }
-        
-        if (data) {
-            return this.readRecords(data);
-        } else {
-            return this.nullResultSet;
+        else if (Ext.isObject(sorters)) {
+            doSort = where;
+            where = direction;
+            newSorters = [sorters];
         }
-    },
+        else if (Ext.isString(sorters)) {
+            sorter = me.sorters.get(sorters);
 
-    /**
-     * Abstracts common functionality used by all Reader subclasses. Each subclass is expected to call
-     * this function before running its own logic and returning the Ext.data.ResultSet instance. For most
-     * Readers additional processing should not be needed.
-     * @param {Mixed} data The raw data object
-     * @return {Ext.data.ResultSet} A ResultSet object
-     */
-    readRecords: function(data) {
-        var me  = this;
-        
-        /*
-         * We check here whether the number of fields has changed since the last read.
-         * This works around an issue when a Model is used for both a Tree and another
-         * source, because the tree decorates the model with extra fields and it causes
-         * issues because the readers aren't notified.
-         */
-        if (me.fieldCount !== me.getFields().length) {
-            me.buildExtractors(true);
+            if (!sorter) {
+                sorter = {
+                    property : sorters,
+                    direction: direction
+                };
+                newSorters = [sorter];
+            }
+            else if (direction === undefined) {
+                sorter.toggle();
+            }
+            else {
+                sorter.setDirection(direction);
+            }
         }
-        
-        /**
-         * The raw data object that was last passed to readRecords. Stored for further processing if needed
-         * @property rawData
-         * @type Mixed
-         */
-        me.rawData = data;
-
-        data = me.getData(data);
 
-        // If we pass an array as the data, we dont use getRoot on the data.
-        // Instead the root equals to the data.
-        var root    = Ext.isArray(data) ? data : me.getRoot(data),
-            success = true,
-            recordCount = 0,
-            total, value, records, message;
-            
-        if (root) {
-            total = root.length;
-        }
+        if (newSorters && newSorters.length) {
+            newSorters = me.decodeSorters(newSorters);
+            if (Ext.isString(where)) {
+                if (where === 'prepend') {
+                    sorters = me.sorters.clone().items;
 
-        if (me.totalProperty) {
-            value = parseInt(me.getTotal(data), 10);
-            if (!isNaN(value)) {
-                total = value;
+                    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 (me.successProperty) {
-            value = me.getSuccess(data);
-            if (value === false || value === 'false') {
-                success = false;
+        if (doSort !== false) {
+            me.onBeforeSort(newSorters);
+            
+            sorters = me.sorters.items;
+            if (sorters.length) {
+                //construct an amalgamated sorter function which combines all of the Sorters passed
+                sorterFn = function(r1, r2) {
+                    var result = sorters[0].sort(r1, r2),
+                        length = sorters.length,
+                        i;
+
+                        //if we have more than one sorter, OR any additional sorter functions together
+                        for (i = 1; i < length; i++) {
+                            result = result || sorters[i].sort.call(this, r1, r2);
+                        }
+
+                    return result;
+                };
+
+                me.doSort(sorterFn);
             }
         }
-        
-        if (me.messageProperty) {
-            message = me.getMessage(data);
-        }
-        
-        if (root) {
-            records = me.extractData(root);
-            recordCount = records.length;
-        } else {
-            recordCount = 0;
-            records = [];
-        }
 
-        return Ext.create('Ext.data.ResultSet', {
-            total  : total || recordCount,
-            count  : recordCount,
-            records: records,
-            success: success,
-            message: message
-        });
+        return sorters;
     },
 
+    onBeforeSort: Ext.emptyFn,
+
     /**
-     * Returns extracted, type-cast rows of data.  Iterates to call #extractValues for each row
-     * @param {Object[]/Object} data-root from server response
      * @private
+     * Normalizes an array of sorter objects, ensuring that they are all Ext.util.Sorter instances
+     * @param {Object[]} sorters The sorters array
+     * @return {Ext.util.Sorter[]} Array of Ext.util.Sorter objects
      */
-    extractData : function(root) {
-        var me = this,
-            values  = [],
-            records = [],
-            Model   = me.model,
-            i       = 0,
-            length  = root.length,
-            idProp  = me.getIdProperty(),
-            node, id, record;
-            
-        if (!root.length && Ext.isObject(root)) {
-            root = [root];
-            length = 1;
+    decodeSorters: function(sorters) {
+        if (!Ext.isArray(sorters)) {
+            if (sorters === undefined) {
+                sorters = [];
+            } else {
+                sorters = [sorters];
+            }
         }
 
-        for (; i < length; i++) {
-            node   = root[i];
-            values = me.extractValues(node);
-            id     = me.getId(node);
+        var length = sorters.length,
+            Sorter = Ext.util.Sorter,
+            fields = this.model ? this.model.prototype.fields : null,
+            field,
+            config, i;
 
-            
-            record = new Model(values, id, node);
-            records.push(record);
-                
-            if (me.implicitIncludes) {
-                me.readAssociated(record, node);
-            }
-        }
+        for (i = 0; i < length; i++) {
+            config = sorters[i];
 
-        return records;
-    },
-    
-    /**
-     * @private
-     * Loads a record's associations from the data object. This prepopulates hasMany and belongsTo associations
-     * on the record provided.
-     * @param {Ext.data.Model} record The record to load associations for
-     * @param {Mixed} data The data object
-     * @return {String} Return value description
-     */
-    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 the associated model has a Reader already, use that, otherwise attempt to create a sensible one
-                    if (proxy) {
-                        reader = proxy.getReader();
-                    } else {
-                        reader = new this.constructor({
-                            model: association.associatedName
-                        });
-                    }
+            if (!(config instanceof Sorter)) {
+                if (Ext.isString(config)) {
+                    config = {
+                        property: config
+                    };
                 }
-                association.read(record, reader, associationData);
-            }  
-        }
-    },
-    
-    /**
-     * @private
-     * Used internally by {@link #readAssociated}. Given a data object (which could be json, xml etc) for a specific
-     * record, this should return the relevant part of that data for the given association name. This is only really
-     * needed to support the XML Reader, which has to do a query to get the associated data object
-     * @param {Mixed} data The raw data object
-     * @param {String} associationName The name of the association to get data for (uses associationKey if present)
-     * @return {Mixed} The root
-     */
-    getAssociatedDataRoot: function(data, associationName) {
-        return data[associationName];
-    },
-    
-    getFields: function() {
-        return this.model.prototype.fields.items;
-    },
 
-    /**
-     * @private
-     * Given an object representing a single model instance's data, iterates over the model's fields and
-     * builds an object with the value for each field.
-     * @param {Object} data The data object to convert
-     * @return {Object} Data object suitable for use with a model constructor
-     */
-    extractValues: function(data) {
-        var fields = this.getFields(),
-            i      = 0,
-            length = fields.length,
-            output = {},
-            field, value;
+                Ext.applyIf(config, {
+                    root     : this.sortRoot,
+                    direction: "ASC"
+                });
 
-        for (; i < length; i++) {
-            field = fields[i];
-            value = this.extractorFunctions[i](data);
+                //support for 3.x style sorters where a function can be defined as 'fn'
+                if (config.fn) {
+                    config.sorterFn = config.fn;
+                }
 
-            output[field.name] = value;
+                //support a function to be passed as a sorter definition
+                if (typeof config == 'function') {
+                    config = {
+                        sorterFn: config
+                    };
+                }
+
+                // ensure sortType gets pushed on if necessary
+                if (fields && !config.transform) {
+                    field = fields.get(config.property);
+                    config.transform = field ? field.sortType : undefined;
+                }
+                sorters[i] = Ext.create('Ext.util.Sorter', config);
+            }
         }
 
-        return output;
+        return sorters;
     },
 
-    /**
-     * @private
-     * By default this function just returns what is passed to it. It can be overridden in a subclass
-     * to return something else. See XmlReader for an example.
-     * @param {Object} data The data object
-     * @return {Object} The normalized data object
-     */
-    getData: function(data) {
-        return data;
+    getSorters: function() {
+        return this.sorters.items;
+    }
+});
+/**
+ * @class Ext.util.MixedCollection
+ * <p>
+ * Represents a collection of a set of key and value pairs. Each key in the MixedCollection
+ * must be unique, the same key cannot exist twice. This collection is ordered, items in the
+ * collection can be accessed by index  or via the key. Newly added items are added to
+ * the end of the collection. This class is similar to {@link Ext.util.HashMap} however it
+ * is heavier and provides more functionality. Sample usage:
+ * <pre><code>
+var coll = new Ext.util.MixedCollection();
+coll.add('key1', 'val1');
+coll.add('key2', 'val2');
+coll.add('key3', 'val3');
+
+console.log(coll.get('key1')); // prints 'val1'
+console.log(coll.indexOfKey('key3')); // prints 2
+ * </code></pre>
+ *
+ * <p>
+ * The MixedCollection also has support for sorting and filtering of the values in the collection.
+ * <pre><code>
+var coll = new Ext.util.MixedCollection();
+coll.add('key1', 100);
+coll.add('key2', -100);
+coll.add('key3', 17);
+coll.add('key4', 0);
+var biggerThanZero = coll.filterBy(function(value){
+    return value > 0;
+});
+console.log(biggerThanZero.getCount()); // prints 2
+ * </code></pre>
+ * </p>
+ */
+Ext.define('Ext.util.MixedCollection', {
+    extend: 'Ext.util.AbstractMixedCollection',
+    mixins: {
+        sortable: 'Ext.util.Sortable'
     },
 
     /**
-     * @private
-     * This will usually need to be implemented in a subclass. Given a generic data object (the type depends on the type
-     * of data we are reading), this function should return the object as configured by the Reader's 'root' meta data config.
-     * See XmlReader's getRoot implementation for an example. By default the same data object will simply be returned.
-     * @param {Mixed} data The data object
-     * @return {Mixed} The same data object
+     * Creates new MixedCollection.
+     * @param {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
+     * function should add function references to the collection. Defaults to
+     * <tt>false</tt>.
+     * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
+     * and return the key value for that item.  This is used when available to look up the key on items that
+     * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
+     * equivalent to providing an implementation for the {@link #getKey} method.
      */
-    getRoot: function(data) {
-        return data;
+    constructor: function() {
+        var me = this;
+        me.callParent(arguments);
+        me.addEvents('sort');
+        me.mixins.sortable.initSortable.call(me);
     },
 
-    /**
-     * Takes a raw response object (as passed to this.read) and returns the useful data segment of it. This must be implemented by each subclass
-     * @param {Object} response The responce object
-     * @return {Object} The useful data from the response
-     */
-    getResponseData: function(response) {
-        //<debug>
-        Ext.Error.raise("getResponseData must be implemented in the Ext.data.reader.Reader subclass");
-        //</debug>
+    doSort: function(sorterFn) {
+        this.sortBy(sorterFn);
     },
 
     /**
      * @private
-     * Reconfigures the meta data tied to this Reader
+     * Performs the actual sorting based on a direction and a sorting function. Internally,
+     * this creates a temporary array of all items in the MixedCollection, sorts it and then writes
+     * the sorted array data back into this.items and this.keys
+     * @param {String} property Property to sort by ('key', 'value', or 'index')
+     * @param {String} dir (optional) Direction to sort 'ASC' or 'DESC'. Defaults to 'ASC'.
+     * @param {Function} fn (optional) Comparison function that defines the sort order.
+     * Defaults to sorting by numeric value.
      */
-    onMetaChange : function(meta) {
-        var fields = meta.fields,
-            newModel;
-        
-        Ext.apply(this, meta);
-        
-        if (fields) {
-            newModel = Ext.define("Ext.data.reader.Json-Model" + Ext.id(), {
-                extend: 'Ext.data.Model',
-                fields: fields
-            });
-            this.setModel(newModel, true);
-        } else {
-            this.buildExtractors(true);
+    _sort : function(property, dir, fn){
+        var me = this,
+            i, len,
+            dsc   = String(dir).toUpperCase() == 'DESC' ? -1 : 1,
+
+            //this is a temporary array used to apply the sorting function
+            c     = [],
+            keys  = me.keys,
+            items = me.items;
+
+        //default to a simple sorter function if one is not provided
+        fn = fn || function(a, b) {
+            return a - b;
+        };
+
+        //copy all the items into a temporary array, which we will sort
+        for(i = 0, len = items.length; i < len; i++){
+            c[c.length] = {
+                key  : keys[i],
+                value: items[i],
+                index: i
+            };
         }
-    },
-    
-    /**
-     * Get the idProperty to use for extracting data
-     * @private
-     * @return {String} The id property
-     */
-    getIdProperty: function(){
-        var prop = this.idProperty;
-        if (Ext.isEmpty(prop)) {
-            prop = this.model.prototype.idProperty;
+
+        //sort the temporary array
+        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;
+        });
+
+        //copy the temporary array back into the main this.items and this.keys objects
+        for(i = 0, len = c.length; i < len; i++){
+            items[i] = c[i].value;
+            keys[i]  = c[i].key;
         }
-        return prop;
+
+        me.fireEvent('sort', me);
     },
 
     /**
-     * @private
-     * This builds optimized functions for retrieving record data and meta data from an object.
-     * Subclasses may need to implement their own getRoot function.
-     * @param {Boolean} force True to automatically remove existing extractor functions first (defaults to false)
+     * Sorts the collection by a single sorter function
+     * @param {Function} sorterFn The function to sort by
      */
-    buildExtractors: function(force) {
-        var me          = this,
-            idProp      = me.getIdProperty(),
-            totalProp   = me.totalProperty,
-            successProp = me.successProperty,
-            messageProp = me.messageProperty,
-            accessor;
-            
-        if (force === true) {
-            delete me.extractorFunctions;
-        }
-        
-        if (me.extractorFunctions) {
-            return;
-        }   
-
-        //build the extractors for all the meta data
-        if (totalProp) {
-            me.getTotal = me.createAccessor(totalProp);
-        }
+    sortBy: function(sorterFn) {
+        var me     = this,
+            items  = me.items,
+            keys   = me.keys,
+            length = items.length,
+            temp   = [],
+            i;
 
-        if (successProp) {
-            me.getSuccess = me.createAccessor(successProp);
+        //first we create a copy of the items array so that we can sort it
+        for (i = 0; i < length; i++) {
+            temp[i] = {
+                key  : keys[i],
+                value: items[i],
+                index: i
+            };
         }
 
-        if (messageProp) {
-            me.getMessage = me.createAccessor(messageProp);
-        }
+        Ext.Array.sort(temp, function(a, b) {
+            var v = sorterFn(a.value, b.value);
+            if (v === 0) {
+                v = (a.index < b.index ? -1 : 1);
+            }
 
-        if (idProp) {
-            accessor = me.createAccessor(idProp);
+            return v;
+        });
 
-            me.getId = function(record) {
-                var id = accessor.call(me, record);
-                return (id === undefined || id === '') ? null : id;
-            };
-        } else {
-            me.getId = function() {
-                return null;
-            };
+        //copy the temporary array back into the main this.items and this.keys objects
+        for (i = 0; i < length; i++) {
+            items[i] = temp[i].value;
+            keys[i]  = temp[i].key;
         }
-        me.buildFieldExtractors();
+        
+        me.fireEvent('sort', me, items, keys);
     },
 
     /**
-     * @private
+     * Reorders each of the items based on a mapping from old index to new index. Internally this
+     * just translates into a sort. The 'sort' event is fired whenever reordering has occured.
+     * @param {Object} mapping Mapping from old item index to new item index
      */
-    buildFieldExtractors: function() {
-        //now build the extractors for all the fields
+    reorder: function(mapping) {
         var me = this,
-            fields = me.getFields(),
-            ln = fields.length,
-            i  = 0,
-            extractorFunctions = [],
-            field, map;
+            items = me.items,
+            index = 0,
+            length = items.length,
+            order = [],
+            remaining = [],
+            oldIndex;
 
-        for (; i < ln; i++) {
-            field = fields[i];
-            map   = (field.mapping !== undefined && field.mapping !== null) ? field.mapping : field.name;
+        me.suspendEvents();
 
-            extractorFunctions.push(me.createAccessor(map));
+        //object of {oldPosition: newPosition} reversed to {newPosition: oldPosition}
+        for (oldIndex in mapping) {
+            order[mapping[oldIndex]] = items[oldIndex];
         }
-        me.fieldCount = ln;
 
-        me.extractorFunctions = extractorFunctions;
+        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);
+    },
+
+    /**
+     * Sorts this collection by <b>key</b>s.
+     * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.
+     * @param {Function} fn (optional) Comparison function that defines the sort order.
+     * Defaults to sorting by case insensitive string.
+     */
+    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);
+        });
     }
-}, function() {
-    Ext.apply(this, {
-        // Private. Empty ResultSet to return when response is falsy (null|undefined|empty string)
-        nullResultSet: Ext.create('Ext.data.ResultSet', {
-            total  : 0,
-            count  : 0,
-            records: [],
-            success: true
-        })
-    });
 });
+
 /**
  * @author Ed Spencer
- * @class Ext.data.reader.Json
- * @extends Ext.data.reader.Reader
- * 
- * <p>The JSON Reader is used by a Proxy to read a server response that is sent back in JSON format. This usually
- * happens as a result of loading a Store - for example we might create something like this:</p>
- * 
+ * @class Ext.data.Errors
+ * @extends Ext.util.MixedCollection
+ *
+ * <p>Wraps a collection of validation error responses and provides convenient functions for
+ * accessing and errors for specific fields.</p>
+ *
+ * <p>Usually this class does not need to be instantiated directly - instances are instead created
+ * automatically when {@link Ext.data.Model#validate validate} on a model instance:</p>
+ *
 <pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'name', 'email']
-});
+//validate some existing model instance - in this case it returned 2 failures messages
+var errors = myModel.validate();
 
-var store = new Ext.data.Store({
-    model: 'User',
-    proxy: {
-        type: 'ajax',
-        url : 'users.json',
-        reader: {
-            type: 'json'
-        }
-    }
-});
-</code></pre>
- * 
- * <p>The example above creates a 'User' model. Models are explained in the {@link Ext.data.Model Model} docs if you're
- * not already familiar with them.</p>
- * 
- * <p>We created the simplest type of JSON Reader possible by simply telling our {@link Ext.data.Store Store}'s 
- * {@link Ext.data.proxy.Proxy Proxy} that we want a JSON Reader. The Store automatically passes the configured model to the
- * Store, so it is as if we passed this instead:
- * 
-<pre><code>
-reader: {
-    type : 'json',
-    model: 'User'
-}
+errors.isValid(); //false
+
+errors.length; //2
+errors.getByField('name');  // [{field: 'name',  message: 'must be present'}]
+errors.getByField('title'); // [{field: 'title', message: 'is too short'}]
 </code></pre>
- * 
- * <p>The reader we set up is ready to read data from our server - at the moment it will accept a response like this:</p>
- * 
-<pre><code>
-[
-    {
-        "id": 1,
-        "name": "Ed Spencer",
-        "email": "ed@sencha.com"
+ */
+Ext.define('Ext.data.Errors', {
+    extend: 'Ext.util.MixedCollection',
+
+    /**
+     * Returns true if there are no errors in the collection
+     * @return {Boolean}
+     */
+    isValid: function() {
+        return this.length === 0;
     },
-    {
-        "id": 2,
-        "name": "Abe Elias",
-        "email": "abe@sencha.com"
+
+    /**
+     * Returns all of the errors for the given field
+     * @param {String} fieldName The field to get errors for
+     * @return {Object[]} All errors for the given field
+     */
+    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;
     }
-]
-</code></pre>
- * 
- * <p><u>Reading other JSON formats</u></p>
- * 
- * <p>If you already have your JSON format defined and it doesn't look quite like what we have above, you can usually
- * pass JsonReader a couple of configuration options to make it parse your format. For example, we can use the 
- * {@link #root} configuration to parse data that comes back like this:</p>
- * 
-<pre><code>
-{
-    "users": [
-       {
-           "id": 1,
-           "name": "Ed Spencer",
-           "email": "ed@sencha.com"
-       },
-       {
-           "id": 2,
-           "name": "Abe Elias",
-           "email": "abe@sencha.com"
-       }
-    ]
-}
-</code></pre>
+});
+
+/**
+ * @author Ed Spencer
+ *
+ * Readers are used to interpret data to be loaded into a {@link Ext.data.Model Model} instance or a {@link
+ * Ext.data.Store Store} - often in response to an AJAX request. In general there is usually no need to create
+ * a Reader instance directly, since a Reader is almost always used together with a {@link Ext.data.proxy.Proxy Proxy},
+ * and is configured using the Proxy's {@link Ext.data.proxy.Proxy#cfg-reader reader} configuration property:
  * 
- * <p>To parse this we just pass in a {@link #root} configuration that matches the 'users' above:</p>
+ *     Ext.create('Ext.data.Store', {
+ *         model: 'User',
+ *         proxy: {
+ *             type: 'ajax',
+ *             url : 'users.json',
+ *             reader: {
+ *                 type: 'json',
+ *                 root: 'users'
+ *             }
+ *         },
+ *     });
+ *     
+ * The above reader is configured to consume a JSON string that looks something like this:
+ *  
+ *     {
+ *         "success": true,
+ *         "users": [
+ *             { "name": "User 1" },
+ *             { "name": "User 2" }
+ *         ]
+ *     }
  * 
-<pre><code>
-reader: {
-    type: 'json',
-    root: 'users'
-}
-</code></pre>
- * 
- * <p>Sometimes the JSON structure is even more complicated. Document databases like CouchDB often provide metadata
- * around each record inside a nested structure like this:</p>
- * 
-<pre><code>
-{
-    "total": 122,
-    "offset": 0,
-    "users": [
-        {
-            "id": "ed-spencer-1",
-            "value": 1,
-            "user": {
-                "id": 1,
-                "name": "Ed Spencer",
-                "email": "ed@sencha.com"
-            }
-        }
-    ]
-}
-</code></pre>
- * 
- * <p>In the case above the record data is nested an additional level inside the "users" array as each "user" item has
- * additional metadata surrounding it ('id' and 'value' in this case). To parse data out of each "user" item in the 
- * JSON above we need to specify the {@link #record} configuration like this:</p>
- * 
-<pre><code>
-reader: {
-    type  : 'json',
-    root  : 'users',
-    record: 'user'
-}
-</code></pre>
- * 
- * <p><u>Response metadata</u></p>
- * 
- * <p>The server can return additional data in its response, such as the {@link #totalProperty total number of records} 
- * and the {@link #successProperty success status of the response}. These are typically included in the JSON response
- * like this:</p>
- * 
-<pre><code>
-{
-    "total": 100,
-    "success": true,
-    "users": [
-        {
-            "id": 1,
-            "name": "Ed Spencer",
-            "email": "ed@sencha.com"
-        }
-    ]
-}
-</code></pre>
- * 
- * <p>If these properties are present in the JSON response they can be parsed out by the JsonReader and used by the
- * Store that loaded it. We can set up the names of these properties by specifying a final pair of configuration 
- * options:</p>
- * 
-<pre><code>
-reader: {
-    type : 'json',
-    root : 'users',
-    totalProperty  : 'total',
-    successProperty: 'success'
-}
-</code></pre>
- * 
- * <p>These final options are not necessary to make the Reader work, but can be useful when the server needs to report
- * an error or if it needs to indicate that there is a lot of data available of which only a subset is currently being
- * returned.</p>
+ *
+ * # Loading Nested Data
+ *
+ * Readers have the ability to automatically load deeply-nested data objects based on the {@link Ext.data.Association
+ * associations} configured on each Model. Below is an example demonstrating the flexibility of these associations in a
+ * fictional CRM system which manages a User, their Orders, OrderItems and Products. First we'll define the models:
+ *
+ *     Ext.define("User", {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             'id', 'name'
+ *         ],
+ *
+ *         hasMany: {model: 'Order', name: 'orders'},
+ *
+ *         proxy: {
+ *             type: 'rest',
+ *             url : 'users.json',
+ *             reader: {
+ *                 type: 'json',
+ *                 root: 'users'
+ *             }
+ *         }
+ *     });
+ *
+ *     Ext.define("Order", {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             'id', 'total'
+ *         ],
+ *
+ *         hasMany  : {model: 'OrderItem', name: 'orderItems', associationKey: 'order_items'},
+ *         belongsTo: 'User'
+ *     });
+ *
+ *     Ext.define("OrderItem", {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             'id', 'price', 'quantity', 'order_id', 'product_id'
+ *         ],
+ *
+ *         belongsTo: ['Order', {model: 'Product', associationKey: 'product'}]
+ *     });
+ *
+ *     Ext.define("Product", {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             'id', 'name'
+ *         ],
+ *
+ *         hasMany: 'OrderItem'
+ *     });
+ *
+ * This may be a lot to take in - basically a User has many Orders, each of which is composed of several OrderItems.
+ * Finally, each OrderItem has a single Product. This allows us to consume data like this:
+ *
+ *     {
+ *         "users": [
+ *             {
+ *                 "id": 123,
+ *                 "name": "Ed",
+ *                 "orders": [
+ *                     {
+ *                         "id": 50,
+ *                         "total": 100,
+ *                         "order_items": [
+ *                             {
+ *                                 "id"      : 20,
+ *                                 "price"   : 40,
+ *                                 "quantity": 2,
+ *                                 "product" : {
+ *                                     "id": 1000,
+ *                                     "name": "MacBook Pro"
+ *                                 }
+ *                             },
+ *                             {
+ *                                 "id"      : 21,
+ *                                 "price"   : 20,
+ *                                 "quantity": 3,
+ *                                 "product" : {
+ *                                     "id": 1001,
+ *                                     "name": "iPhone"
+ *                                 }
+ *                             }
+ *                         ]
+ *                     }
+ *                 ]
+ *             }
+ *         ]
+ *     }
+ *
+ * The JSON response is deeply nested - it returns all Users (in this case just 1 for simplicity's sake), all of the
+ * Orders for each User (again just 1 in this case), all of the OrderItems for each Order (2 order items in this case),
+ * and finally the Product associated with each OrderItem. Now we can read the data and use it as follows:
+ *
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: "User"
+ *     });
+ *
+ *     store.load({
+ *         callback: function() {
+ *             //the user that was loaded
+ *             var user = store.first();
+ *
+ *             console.log("Orders for " + user.get('name') + ":")
+ *
+ *             //iterate over the Orders for each User
+ *             user.orders().each(function(order) {
+ *                 console.log("Order ID: " + order.getId() + ", which contains items:");
+ *
+ *                 //iterate over the OrderItems for each Order
+ *                 order.orderItems().each(function(orderItem) {
+ *                     //we know that the Product data is already loaded, so we can use the synchronous getProduct
+ *                     //usually, we would use the asynchronous version (see {@link Ext.data.BelongsToAssociation})
+ *                     var product = orderItem.getProduct();
+ *
+ *                     console.log(orderItem.get('quantity') + ' orders of ' + product.get('name'));
+ *                 });
+ *             });
+ *         }
+ *     });
+ *
+ * Running the code above results in the following:
+ *
+ *     Orders for Ed:
+ *     Order ID: 50, which contains items:
+ *     2 orders of MacBook Pro
+ *     3 orders of iPhone
  */
-Ext.define('Ext.data.reader.Json', {
-    extend: 'Ext.data.reader.Reader',
-    alternateClassName: 'Ext.data.JsonReader',
-    alias : 'reader.json',
+Ext.define('Ext.data.reader.Reader', {
+    requires: ['Ext.data.ResultSet'],
+    alternateClassName: ['Ext.data.Reader', 'Ext.data.DataReader'],
     
+    /**
+     * @cfg {String} idProperty
+     * Name of the property within a row object that contains a record identifier value. Defaults to The id of the
+     * model. If an idProperty is explicitly specified it will override that of the one specified on the model
+     */
+
+    /**
+     * @cfg {String} totalProperty
+     * Name of the property from which to retrieve the total number of records in the dataset. This is only needed if
+     * the whole dataset is not passed in one go, but is being paged from the remote server. Defaults to total.
+     */
+    totalProperty: 'total',
+
+    /**
+     * @cfg {String} successProperty
+     * Name of the property from which to retrieve the success attribute. Defaults to success. See
+     * {@link Ext.data.proxy.Server}.{@link Ext.data.proxy.Server#exception exception} for additional information.
+     */
+    successProperty: 'success',
+
+    /**
+     * @cfg {String} root
+     * The name of the property which contains the Array of row objects.  For JSON reader it's dot-separated list
+     * of property names.  For XML reader it's a CSS selector.  For array reader it's not applicable.
+     * 
+     * By default the natural root of the data will be used.  The root Json array, the root XML element, or the array.
+     *
+     * The data packet value for this property should be an empty array to clear the data or show no data.
+     */
     root: '',
     
     /**
-     * @cfg {String} record The optional location within the JSON response that the record data itself can be found at.
-     * See the JsonReader intro docs for more details. This is not often needed and defaults to undefined.
+     * @cfg {String} messageProperty
+     * The name of the property which contains a response message. This property is optional.
      */
     
     /**
-     * @cfg {Boolean} useSimpleAccessors True to ensure that field names/mappings are treated as literals when
-     * reading values. Defalts to <tt>false</tt>.
-     * For example, by default, using the mapping "foo.bar.baz" will try and read a property foo from the root, then a property bar
-     * from foo, then a property baz from bar. Setting the simple accessors to true will read the property with the name 
-     * "foo.bar.baz" direct from the root object.
+     * @cfg {Boolean} implicitIncludes
+     * True to automatically parse models nested within other models in a response object. See the
+     * Ext.data.reader.Reader intro docs for full explanation. Defaults to true.
      */
-    useSimpleAccessors: false,
+    implicitIncludes: true,
+    
+    isReader: true,
     
     /**
-     * Reads a JSON object and returns a ResultSet. Uses the internal getTotal and getSuccess extractors to
-     * retrieve meta data from the response, and extractData to turn the JSON data into model instances.
-     * @param {Object} data The raw JSON data
-     * @return {Ext.data.ResultSet} A ResultSet containing model instances and meta data about the results
+     * Creates new Reader.
+     * @param {Object} config (optional) Config object.
      */
-    readRecords: function(data) {
-        //this has to be before the call to super because we use the meta data in the superclass readRecords
-        if (data.metaData) {
-            this.onMetaChange(data.metaData);
-        }
-
-        /**
-         * DEPRECATED - will be removed in Ext JS 5.0. This is just a copy of this.rawData - use that instead
-         * @property jsonData
-         * @type Mixed
-         */
-        this.jsonData = data;
-        return this.callParent([data]);
-    },
-
-    //inherit docs
-    getResponseData: function(response) {
-        try {
-            var data = Ext.decode(response.responseText);
-        }
-        catch (ex) {
-            Ext.Error.raise({
-                response: response,
-                json: response.responseText,
-                parseError: ex,
-                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
-            });
-        }
-        //<debug>
-        if (!data) {
-            Ext.Error.raise('JSON object not found');
+    constructor: function(config) {
+        var me = this;
+        
+        Ext.apply(me, config || {});
+        me.fieldCount = 0;
+        me.model = Ext.ModelManager.getModel(config.model);
+        if (me.model) {
+            me.buildExtractors();
         }
-        //</debug>
-
-        return data;
     },
 
-    //inherit docs
-    buildExtractors : function() {
+    /**
+     * Sets a new model for the reader.
+     * @private
+     * @param {Object} model The model to set.
+     * @param {Boolean} setOnProxy True to also set on the Proxy, if one is configured
+     */
+    setModel: function(model, setOnProxy) {
         var me = this;
         
-        me.callParent(arguments);
-
-        if (me.root) {
-            me.getRoot = me.createAccessor(me.root);
-        } else {
-            me.getRoot = function(root) {
-                return root;
-            };
+        me.model = Ext.ModelManager.getModel(model);
+        me.buildExtractors(true);
+        
+        if (setOnProxy && me.proxy) {
+            me.proxy.setModel(me.model, true);
         }
     },
-    
+
     /**
-     * @private
-     * We're just preparing the data for the superclass by pulling out the record objects we want. If a {@link #record}
-     * was specified we have to pull those out of the larger JSON object, which is most of what this function is doing
-     * @param {Object} root The JSON root node
-     * @return {Array} The records
+     * Reads the given response object. This method normalizes the different types of response object that may be passed
+     * to it, before handing off the reading of records to the {@link #readRecords} function.
+     * @param {Object} response The response object. This may be either an XMLHttpRequest object or a plain JS object
+     * @return {Ext.data.ResultSet} The parsed ResultSet object
      */
-    extractData: function(root) {
-        var recordName = this.record,
-            data = [],
-            length, i;
+    read: function(response) {
+        var data = response;
         
-        if (recordName) {
-            length = root.length;
-            
-            for (i = 0; i < length; i++) {
-                data[i] = root[i][recordName];
-            }
+        if (response && response.responseText) {
+            data = this.getResponseData(response);
+        }
+        
+        if (data) {
+            return this.readRecords(data);
         } else {
-            data = root;
+            return this.nullResultSet;
         }
-        return this.callParent([data]);
     },
 
     /**
-     * @private
-     * Returns an accessor function for the given property string. Gives support for properties such as the following:
-     * 'someProperty'
-     * 'some.property'
-     * 'some["property"]'
-     * This is used by buildExtractors to create optimized extractor functions when casting raw data into model instances.
+     * Abstracts common functionality used by all Reader subclasses. Each subclass is expected to call this function
+     * before running its own logic and returning the Ext.data.ResultSet instance. For most Readers additional
+     * processing should not be needed.
+     * @param {Object} data The raw data object
+     * @return {Ext.data.ResultSet} A ResultSet object
      */
-    createAccessor: function() {
-        var re = /[\[\.]/;
+    readRecords: function(data) {
+        var me  = this;
         
-        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];
-            };
-        };
-    }()
-});
-/**
- * @class Ext.data.writer.Json
- * @extends Ext.data.writer.Writer
+        /*
+         * We check here whether the number of fields has changed since the last read.
+         * This works around an issue when a Model is used for both a Tree and another
+         * source, because the tree decorates the model with extra fields and it causes
+         * issues because the readers aren't notified.
+         */
+        if (me.fieldCount !== me.getFields().length) {
+            me.buildExtractors(true);
+        }
+        
+        /**
+         * @property {Object} rawData
+         * The raw data object that was last passed to readRecords. Stored for further processing if needed
+         */
+        me.rawData = data;
 
-This class is used to write {@link Ext.data.Model} data to the server in a JSON format.
-The {@link #allowSingle} configuration can be set to false to force the records to always be
-encoded in an array, even if there is only a single record being sent.
+        data = me.getData(data);
 
- * @markdown
- */
-Ext.define('Ext.data.writer.Json', {
-    extend: 'Ext.data.writer.Writer',
-    alternateClassName: 'Ext.data.JsonWriter',
-    alias: 'writer.json',
-    
-    /**
-     * @cfg {String} root The key under which the records in this Writer will be placed. Defaults to <tt>undefined</tt>.
-     * Example generated request, using root: 'records':
-<pre><code>
-{'records': [{name: 'my record'}, {name: 'another record'}]}
-</code></pre>
-     */
-    root: undefined,
-    
-    /**
-     * @cfg {Boolean} encode True to use Ext.encode() on the data before sending. Defaults to <tt>false</tt>.
-     * The encode option should only be set to true when a {@link #root} is defined, because the values will be
-     * sent as part of the request parameters as opposed to a raw post. The root will be the name of the parameter
-     * sent to the server.
-     */
-    encode: false,
-    
-    /**
-     * @cfg {Boolean} allowSingle False to ensure that records are always wrapped in an array, even if there is only
-     * one record being sent. When there is more than one record, they will always be encoded into an array.
-     * Defaults to <tt>true</tt>. Example:
-     * <pre><code>
-// with allowSingle: true
-"root": {
-    "first": "Mark",
-    "last": "Corrigan"
-}
+        // If we pass an array as the data, we dont use getRoot on the data.
+        // Instead the root equals to the data.
+        var root    = Ext.isArray(data) ? data : me.getRoot(data),
+            success = true,
+            recordCount = 0,
+            total, value, records, message;
+            
+        if (root) {
+            total = root.length;
+        }
 
-// with allowSingle: false
-"root": [{
-    "first": "Mark",
-    "last": "Corrigan"
-}]
-     * </code></pre>
-     */
-    allowSingle: true,
-    
-    //inherit docs
-    writeRecords: function(request, data) {
-        var root = this.root;
+        if (me.totalProperty) {
+            value = parseInt(me.getTotal(data), 10);
+            if (!isNaN(value)) {
+                total = value;
+            }
+        }
+
+        if (me.successProperty) {
+            value = me.getSuccess(data);
+            if (value === false || value === 'false') {
+                success = false;
+            }
+        }
         
-        if (this.allowSingle && data.length == 1) {
-            // convert to single object format
-            data = data[0];
+        if (me.messageProperty) {
+            message = me.getMessage(data);
         }
         
-        if (this.encode) {
-            if (root) {
-                // sending as a param, need to encode
-                request.params[root] = Ext.encode(data);
-            } else {
-                //<debug>
-                Ext.Error.raise('Must specify a root when using encode');
-                //</debug>
-            }
+        if (root) {
+            records = me.extractData(root);
+            recordCount = records.length;
         } else {
-            // send as jsonData
-            request.jsonData = request.jsonData || {};
-            if (root) {
-                request.jsonData[root] = data;
-            } else {
-                request.jsonData = data;
-            }
+            recordCount = 0;
+            records = [];
         }
-        return request;
-    }
-});
 
-/**
- * @author Ed Spencer
- * @class Ext.data.proxy.Proxy
- * 
- * <p>Proxies are used by {@link Ext.data.Store Stores} to handle the loading and saving of {@link Ext.data.Model Model} data.
- * Usually developers will not need to create or interact with proxies directly.</p>
- * <p><u>Types of Proxy</u></p>
- * 
- * <p>There are two main types of Proxy - {@link Ext.data.proxy.Client Client} and {@link Ext.data.proxy.Server Server}. The Client proxies
- * save their data locally and include the following subclasses:</p>
- * 
- * <ul style="list-style-type: disc; padding-left: 25px">
- * <li>{@link Ext.data.proxy.LocalStorage LocalStorageProxy} - saves its data to localStorage if the browser supports it</li>
- * <li>{@link Ext.data.proxy.SessionStorage SessionStorageProxy} - saves its data to sessionStorage if the browsers supports it</li>
- * <li>{@link Ext.data.proxy.Memory MemoryProxy} - holds data in memory only, any data is lost when the page is refreshed</li>
- * </ul>
- * 
- * <p>The Server proxies save their data by sending requests to some remote server. These proxies include:</p>
- * 
- * <ul style="list-style-type: disc; padding-left: 25px">
- * <li>{@link Ext.data.proxy.Ajax Ajax} - sends requests to a server on the same domain</li>
- * <li>{@link Ext.data.proxy.JsonP JsonP} - uses JSON-P to send requests to a server on a different domain</li>
- * <li>{@link Ext.data.proxy.Direct Direct} - uses {@link Ext.direct} to send requests</li>
- * </ul>
- * 
- * <p>Proxies operate on the principle that all operations performed are either Create, Read, Update or Delete. These four operations 
- * are mapped to the methods {@link #create}, {@link #read}, {@link #update} and {@link #destroy} respectively. Each Proxy subclass 
- * implements these functions.</p>
- * 
- * <p>The CRUD methods each expect an {@link Ext.data.Operation Operation} object as the sole argument. The Operation encapsulates 
- * information about the action the Store wishes to perform, the {@link Ext.data.Model model} instances that are to be modified, etc.
- * See the {@link Ext.data.Operation Operation} documentation for more details. Each CRUD method also accepts a callback function to be 
- * called asynchronously on completion.</p>
- * 
- * <p>Proxies also support batching of Operations via a {@link Ext.data.Batch batch} object, invoked by the {@link #batch} method.</p>
- * 
- */
-Ext.define('Ext.data.proxy.Proxy', {
-    alias: 'proxy.proxy',
-    alternateClassName: ['Ext.data.DataProxy', 'Ext.data.Proxy'],
-    requires: [
-        'Ext.data.reader.Json',
-        'Ext.data.writer.Json'
-    ],
-    uses: [
-        'Ext.data.Batch', 
-        'Ext.data.Operation', 
-        'Ext.data.Model'
-    ],
-    mixins: {
-        observable: 'Ext.util.Observable'
+        return Ext.create('Ext.data.ResultSet', {
+            total  : total || recordCount,
+            count  : recordCount,
+            records: records,
+            success: success,
+            message: message
+        });
     },
-    
-    /**
-     * @cfg {String} batchOrder
-     * Comma-separated ordering 'create', 'update' and 'destroy' actions when batching. Override this
-     * to set a different order for the batched CRUD actions to be executed in. Defaults to 'create,update,destroy'
-     */
-    batchOrder: 'create,update,destroy',
-    
-    /**
-     * @cfg {Boolean} batchActions True to batch actions of a particular type when synchronizing the store.
-     * Defaults to <tt>true</tt>.
-     */
-    batchActions: true,
-    
-    /**
-     * @cfg {String} defaultReaderType The default registered reader type. Defaults to 'json'
-     * @private
-     */
-    defaultReaderType: 'json',
-    
+
     /**
-     * @cfg {String} defaultWriterType The default registered writer type. Defaults to 'json'
+     * Returns extracted, type-cast rows of data.  Iterates to call #extractValues for each row
+     * @param {Object[]/Object} root from server response
      * @private
      */
-    defaultWriterType: 'json',
-    
-    /**
-     * @cfg {String/Ext.data.Model} model The name of the Model to tie to this Proxy. Can be either the string name of
-     * the Model, or a reference to the Model constructor. Required.
-     */
-    
-    isProxy: true,
-    
-    /**
-     * Creates the Proxy
-     * @param {Object} config (optional) Config object.
-     */
-    constructor: function(config) {
-        config = config || {};
-        
-        if (config.model === undefined) {
-            delete config.model;
+    extractData : function(root) {
+        var me = this,
+            values  = [],
+            records = [],
+            Model   = me.model,
+            i       = 0,
+            length  = root.length,
+            idProp  = me.getIdProperty(),
+            node, id, record;
+            
+        if (!root.length && Ext.isObject(root)) {
+            root = [root];
+            length = 1;
         }
 
-        this.mixins.observable.constructor.call(this, config);
-        
-        if (this.model !== undefined && !(this.model instanceof Ext.data.Model)) {
-            this.setModel(this.model);
+        for (; i < length; i++) {
+            node   = root[i];
+            values = me.extractValues(node);
+            id     = me.getId(node);
+
+            
+            record = new Model(values, id, node);
+            records.push(record);
+                
+            if (me.implicitIncludes) {
+                me.readAssociated(record, node);
+            }
         }
+
+        return records;
     },
     
     /**
-     * Sets the model associated with this proxy. This will only usually be called by a Store
-     * @param {String|Ext.data.Model} model The new model. Can be either the model name string,
-     * or a reference to the model's constructor
-     * @param {Boolean} setOnStore Sets the new model on the associated Store, if one is present
-     */
-    setModel: function(model, setOnStore) {
-        this.model = Ext.ModelManager.getModel(model);
-        
-        var reader = this.reader,
-            writer = this.writer;
-        
-        this.setReader(reader);
-        this.setWriter(writer);
+     * @private
+     * Loads a record's associations from the data object. This prepopulates hasMany and belongsTo associations
+     * on the record provided.
+     * @param {Ext.data.Model} record The record to load associations for
+     * @param {Object} data The data object
+     * @return {String} Return value description
+     */
+    readAssociated: function(record, data) {
+        var associations = record.associations.items,
+            i            = 0,
+            length       = associations.length,
+            association, associationData, proxy, reader;
         
-        if (setOnStore && this.store) {
-            this.store.setModel(this.model);
+        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 the associated model has a Reader already, use that, otherwise attempt to create a sensible one
+                    if (proxy) {
+                        reader = proxy.getReader();
+                    } else {
+                        reader = new this.constructor({
+                            model: association.associatedName
+                        });
+                    }
+                }
+                association.read(record, reader, associationData);
+            }  
         }
     },
     
     /**
-     * Returns the model attached to this Proxy
-     * @return {Ext.data.Model} The model
+     * @private
+     * Used internally by {@link #readAssociated}. Given a data object (which could be json, xml etc) for a specific
+     * record, this should return the relevant part of that data for the given association name. This is only really
+     * needed to support the XML Reader, which has to do a query to get the associated data object
+     * @param {Object} data The raw data object
+     * @param {String} associationName The name of the association to get data for (uses associationKey if present)
+     * @return {Object} The root
      */
-    getModel: function() {
-        return this.model;
+    getAssociatedDataRoot: function(data, associationName) {
+        return data[associationName];
     },
     
+    getFields: function() {
+        return this.model.prototype.fields.items;
+    },
+
     /**
-     * Sets the Proxy's Reader by string, config object or Reader instance
-     * @param {String|Object|Ext.data.reader.Reader} reader The new Reader, which can be either a type string, a configuration object
-     * or an Ext.data.reader.Reader instance
-     * @return {Ext.data.reader.Reader} The attached Reader object
+     * @private
+     * Given an object representing a single model instance's data, iterates over the model's fields and
+     * builds an object with the value for each field.
+     * @param {Object} data The data object to convert
+     * @return {Object} Data object suitable for use with a model constructor
      */
-    setReader: function(reader) {
-        var me = this;
-        
-        if (reader === undefined || typeof reader == 'string') {
-            reader = {
-                type: reader
-            };
-        }
+    extractValues: function(data) {
+        var fields = this.getFields(),
+            i      = 0,
+            length = fields.length,
+            output = {},
+            field, value;
 
-        if (reader.isReader) {
-            reader.setModel(me.model);
-        } else {
-            Ext.applyIf(reader, {
-                proxy: me,
-                model: me.model,
-                type : me.defaultReaderType
-            });
+        for (; i < length; i++) {
+            field = fields[i];
+            value = this.extractorFunctions[i](data);
 
-            reader = Ext.createByAlias('reader.' + reader.type, reader);
+            output[field.name] = value;
         }
-        
-        me.reader = reader;
-        return me.reader;
+
+        return output;
     },
-    
+
     /**
-     * Returns the reader currently attached to this proxy instance
-     * @return {Ext.data.reader.Reader} The Reader instance
+     * @private
+     * By default this function just returns what is passed to it. It can be overridden in a subclass
+     * to return something else. See XmlReader for an example.
+     * @param {Object} data The data object
+     * @return {Object} The normalized data object
      */
-    getReader: function() {
-        return this.reader;
+    getData: function(data) {
+        return data;
     },
-    
-    /**
-     * Sets the Proxy's Writer by string, config object or Writer instance
-     * @param {String|Object|Ext.data.writer.Writer} writer The new Writer, which can be either a type string, a configuration object
-     * or an Ext.data.writer.Writer instance
-     * @return {Ext.data.writer.Writer} The attached Writer object
-     */
-    setWriter: function(writer) {
-        if (writer === undefined || typeof writer == 'string') {
-            writer = {
-                type: writer
-            };
-        }
-
-        if (!(writer instanceof Ext.data.writer.Writer)) {
-            Ext.applyIf(writer, {
-                model: this.model,
-                type : this.defaultWriterType
-            });
 
-            writer = Ext.createByAlias('writer.' + writer.type, writer);
-        }
-        
-        this.writer = writer;
-        
-        return this.writer;
-    },
-    
     /**
-     * Returns the writer currently attached to this proxy instance
-     * @return {Ext.data.writer.Writer} The Writer instance
+     * @private
+     * This will usually need to be implemented in a subclass. Given a generic data object (the type depends on the type
+     * of data we are reading), this function should return the object as configured by the Reader's 'root' meta data config.
+     * See XmlReader's getRoot implementation for an example. By default the same data object will simply be returned.
+     * @param {Object} data The data object
+     * @return {Object} The same data object
      */
-    getWriter: function() {
-        return this.writer;
+    getRoot: function(data) {
+        return data;
     },
-    
+
     /**
-     * Performs the given create operation.
-     * @param {Ext.data.Operation} operation The Operation to perform
-     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
-     * @param {Object} scope Scope to execute the callback function in
-     * @method
+     * Takes a raw response object (as passed to this.read) and returns the useful data segment of it. This must be
+     * implemented by each subclass
+     * @param {Object} response The responce object
+     * @return {Object} The useful data from the response
      */
-    create: Ext.emptyFn,
-    
+    getResponseData: function(response) {
+        //<debug>
+        Ext.Error.raise("getResponseData must be implemented in the Ext.data.reader.Reader subclass");
+        //</debug>
+    },
+
     /**
-     * Performs the given read operation.
-     * @param {Ext.data.Operation} operation The Operation to perform
-     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
-     * @param {Object} scope Scope to execute the callback function in
-     * @method
+     * @private
+     * Reconfigures the meta data tied to this Reader
      */
-    read: Ext.emptyFn,
+    onMetaChange : function(meta) {
+        var fields = meta.fields,
+            newModel;
+        
+        Ext.apply(this, meta);
+        
+        if (fields) {
+            newModel = Ext.define("Ext.data.reader.Json-Model" + Ext.id(), {
+                extend: 'Ext.data.Model',
+                fields: fields
+            });
+            this.setModel(newModel, true);
+        } else {
+            this.buildExtractors(true);
+        }
+    },
     
     /**
-     * Performs the given update operation.
-     * @param {Ext.data.Operation} operation The Operation to perform
-     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
-     * @param {Object} scope Scope to execute the callback function in
-     * @method
+     * Get the idProperty to use for extracting data
+     * @private
+     * @return {String} The id property
      */
-    update: Ext.emptyFn,
-    
+    getIdProperty: function(){
+        var prop = this.idProperty;
+        if (Ext.isEmpty(prop)) {
+            prop = this.model.prototype.idProperty;
+        }
+        return prop;
+    },
+
     /**
-     * Performs the given destroy operation.
-     * @param {Ext.data.Operation} operation The Operation to perform
-     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
-     * @param {Object} scope Scope to execute the callback function in
-     * @method
+     * @private
+     * This builds optimized functions for retrieving record data and meta data from an object.
+     * Subclasses may need to implement their own getRoot function.
+     * @param {Boolean} [force=false] True to automatically remove existing extractor functions first
      */
-    destroy: Ext.emptyFn,
-    
+    buildExtractors: function(force) {
+        var me          = this,
+            idProp      = me.getIdProperty(),
+            totalProp   = me.totalProperty,
+            successProp = me.successProperty,
+            messageProp = me.messageProperty,
+            accessor;
+            
+        if (force === true) {
+            delete me.extractorFunctions;
+        }
+        
+        if (me.extractorFunctions) {
+            return;
+        }   
+
+        //build the extractors for all the meta data
+        if (totalProp) {
+            me.getTotal = me.createAccessor(totalProp);
+        }
+
+        if (successProp) {
+            me.getSuccess = me.createAccessor(successProp);
+        }
+
+        if (messageProp) {
+            me.getMessage = me.createAccessor(messageProp);
+        }
+
+        if (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.buildFieldExtractors();
+    },
+
     /**
-     * Performs a batch of {@link Ext.data.Operation Operations}, in the order specified by {@link #batchOrder}. Used internally by
-     * {@link Ext.data.Store}'s {@link Ext.data.Store#sync sync} method. Example usage:
-     * <pre><code>
-     * myProxy.batch({
-     *     create : [myModel1, myModel2],
-     *     update : [myModel3],
-     *     destroy: [myModel4, myModel5]
-     * });
-     * </code></pre>
-     * Where the myModel* above are {@link Ext.data.Model Model} instances - in this case 1 and 2 are new instances and have not been 
-     * saved before, 3 has been saved previously but needs to be updated, and 4 and 5 have already been saved but should now be destroyed.
-     * @param {Object} operations Object containing the Model instances to act upon, keyed by action name
-     * @param {Object} listeners Optional listeners object passed straight through to the Batch - see {@link Ext.data.Batch}
-     * @return {Ext.data.Batch} The newly created Ext.data.Batch object
+     * @private
      */
-    batch: function(operations, listeners) {
+    buildFieldExtractors: function() {
+        //now build the extractors for all the fields
         var me = this,
-            batch = Ext.create('Ext.data.Batch', {
-                proxy: me,
-                listeners: listeners || {}
-            }),
-            useBatch = me.batchActions, 
-            records;
-        
-        Ext.each(me.batchOrder.split(','), function(action) {
-            records = operations[action];
-            if (records) {
-                if (useBatch) {
-                    batch.add(Ext.create('Ext.data.Operation', {
-                        action: action,
-                        records: records
-                    }));
-                } else {
-                    Ext.each(records, function(record){
-                        batch.add(Ext.create('Ext.data.Operation', {
-                            action : action, 
-                            records: [record]
-                        }));
-                    });
-                }
-            }
-        }, me);
-        
-        batch.start();
-        return batch;
+            fields = me.getFields(),
+            ln = fields.length,
+            i  = 0,
+            extractorFunctions = [],
+            field, map;
+
+        for (; i < ln; i++) {
+            field = fields[i];
+            map   = (field.mapping !== undefined && field.mapping !== null) ? field.mapping : field.name;
+
+            extractorFunctions.push(me.createAccessor(map));
+        }
+        me.fieldCount = ln;
+
+        me.extractorFunctions = extractorFunctions;
     }
 }, function() {
-    // Ext.data.proxy.ProxyMgr.registerType('proxy', this);
-    
-    //backwards compatibility
-    Ext.data.DataProxy = this;
-    // Ext.deprecate('platform', '2.0', function() {
-    //     Ext.data.DataProxy = this;
-    // }, this);
+    Ext.apply(this, {
+        // Private. Empty ResultSet to return when response is falsy (null|undefined|empty string)
+        nullResultSet: Ext.create('Ext.data.ResultSet', {
+            total  : 0,
+            count  : 0,
+            records: [],
+            success: true
+        })
+    });
 });
-
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.Server
- * @extends Ext.data.proxy.Proxy
- * 
- * <p>ServerProxy is a superclass of {@link Ext.data.proxy.JsonP JsonPProxy} and {@link Ext.data.proxy.Ajax AjaxProxy},
- * and would not usually be used directly.</p>
- * 
- * <p>ServerProxy should ideally be named HttpProxy as it is a superclass for all HTTP proxies - for Ext JS 4.x it has been 
- * called ServerProxy to enable any 3.x applications that reference the HttpProxy to continue to work (HttpProxy is now an 
- * alias of AjaxProxy).</p>
+ * @class Ext.data.reader.Json
+ * @extends Ext.data.reader.Reader
+ *
+ * <p>The JSON Reader is used by a Proxy to read a server response that is sent back in JSON format. This usually
+ * happens as a result of loading a Store - for example we might create something like this:</p>
+ *
+<pre><code>
+Ext.define('User', {
+    extend: 'Ext.data.Model',
+    fields: ['id', 'name', 'email']
+});
+
+var store = Ext.create('Ext.data.Store', {
+    model: 'User',
+    proxy: {
+        type: 'ajax',
+        url : 'users.json',
+        reader: {
+            type: 'json'
+        }
+    }
+});
+</code></pre>
+ *
+ * <p>The example above creates a 'User' model. Models are explained in the {@link Ext.data.Model Model} docs if you're
+ * not already familiar with them.</p>
+ *
+ * <p>We created the simplest type of JSON Reader possible by simply telling our {@link Ext.data.Store Store}'s
+ * {@link Ext.data.proxy.Proxy Proxy} that we want a JSON Reader. The Store automatically passes the configured model to the
+ * Store, so it is as if we passed this instead:
+ *
+<pre><code>
+reader: {
+    type : 'json',
+    model: 'User'
+}
+</code></pre>
+ *
+ * <p>The reader we set up is ready to read data from our server - at the moment it will accept a response like this:</p>
+ *
+<pre><code>
+[
+    {
+        "id": 1,
+        "name": "Ed Spencer",
+        "email": "ed@sencha.com"
+    },
+    {
+        "id": 2,
+        "name": "Abe Elias",
+        "email": "abe@sencha.com"
+    }
+]
+</code></pre>
+ *
+ * <p><u>Reading other JSON formats</u></p>
+ *
+ * <p>If you already have your JSON format defined and it doesn't look quite like what we have above, you can usually
+ * pass JsonReader a couple of configuration options to make it parse your format. For example, we can use the
+ * {@link #root} configuration to parse data that comes back like this:</p>
+ *
+<pre><code>
+{
+    "users": [
+       {
+           "id": 1,
+           "name": "Ed Spencer",
+           "email": "ed@sencha.com"
+       },
+       {
+           "id": 2,
+           "name": "Abe Elias",
+           "email": "abe@sencha.com"
+       }
+    ]
+}
+</code></pre>
+ *
+ * <p>To parse this we just pass in a {@link #root} configuration that matches the 'users' above:</p>
+ *
+<pre><code>
+reader: {
+    type: 'json',
+    root: 'users'
+}
+</code></pre>
+ *
+ * <p>Sometimes the JSON structure is even more complicated. Document databases like CouchDB often provide metadata
+ * around each record inside a nested structure like this:</p>
+ *
+<pre><code>
+{
+    "total": 122,
+    "offset": 0,
+    "users": [
+        {
+            "id": "ed-spencer-1",
+            "value": 1,
+            "user": {
+                "id": 1,
+                "name": "Ed Spencer",
+                "email": "ed@sencha.com"
+            }
+        }
+    ]
+}
+</code></pre>
+ *
+ * <p>In the case above the record data is nested an additional level inside the "users" array as each "user" item has
+ * additional metadata surrounding it ('id' and 'value' in this case). To parse data out of each "user" item in the
+ * JSON above we need to specify the {@link #record} configuration like this:</p>
+ *
+<pre><code>
+reader: {
+    type  : 'json',
+    root  : 'users',
+    record: 'user'
+}
+</code></pre>
+ *
+ * <p><u>Response metadata</u></p>
+ *
+ * <p>The server can return additional data in its response, such as the {@link #totalProperty total number of records}
+ * and the {@link #successProperty success status of the response}. These are typically included in the JSON response
+ * like this:</p>
+ *
+<pre><code>
+{
+    "total": 100,
+    "success": true,
+    "users": [
+        {
+            "id": 1,
+            "name": "Ed Spencer",
+            "email": "ed@sencha.com"
+        }
+    ]
+}
+</code></pre>
+ *
+ * <p>If these properties are present in the JSON response they can be parsed out by the JsonReader and used by the
+ * Store that loaded it. We can set up the names of these properties by specifying a final pair of configuration
+ * options:</p>
+ *
+<pre><code>
+reader: {
+    type : 'json',
+    root : 'users',
+    totalProperty  : 'total',
+    successProperty: 'success'
+}
+</code></pre>
+ *
+ * <p>These final options are not necessary to make the Reader work, but can be useful when the server needs to report
+ * an error or if it needs to indicate that there is a lot of data available of which only a subset is currently being
+ * returned.</p>
  */
-Ext.define('Ext.data.proxy.Server', {
-    extend: 'Ext.data.proxy.Proxy',
-    alias : 'proxy.server',
-    alternateClassName: 'Ext.data.ServerProxy',
-    uses  : ['Ext.data.Request'],
-    
-    /**
-     * @cfg {String} url The URL from which to request the data object.
-     */
-    
-    /**
-     * @cfg {Object/String/Ext.data.reader.Reader} reader The Ext.data.reader.Reader to use to decode the server's response. This can
-     * either be a Reader instance, a config object or just a valid Reader type name (e.g. 'json', 'xml').
-     */
-    
-    /**
-     * @cfg {Object/String/Ext.data.writer.Writer} writer The Ext.data.writer.Writer to use to encode any request sent to the server.
-     * This can either be a Writer instance, a config object or just a valid Writer type name (e.g. 'json', 'xml').
-     */
-    
+Ext.define('Ext.data.reader.Json', {
+    extend: 'Ext.data.reader.Reader',
+    alternateClassName: 'Ext.data.JsonReader',
+    alias : 'reader.json',
+
+    root: '',
+
     /**
-     * @cfg {String} pageParam The name of the 'page' parameter to send in a request. Defaults to 'page'. Set this to
-     * undefined if you don't want to send a page parameter
+     * @cfg {String} record The optional location within the JSON response that the record data itself can be found at.
+     * See the JsonReader intro docs for more details. This is not often needed.
      */
-    pageParam: 'page',
-    
+
     /**
-     * @cfg {String} startParam The name of the 'start' parameter to send in a request. Defaults to 'start'. Set this
-     * to undefined if you don't want to send a start parameter
+     * @cfg {Boolean} useSimpleAccessors True to ensure that field names/mappings are treated as literals when
+     * reading values. Defalts to <tt>false</tt>.
+     * For example, by default, using the mapping "foo.bar.baz" will try and read a property foo from the root, then a property bar
+     * from foo, then a property baz from bar. Setting the simple accessors to true will read the property with the name
+     * "foo.bar.baz" direct from the root object.
      */
-    startParam: 'start',
+    useSimpleAccessors: false,
 
     /**
-     * @cfg {String} limitParam The name of the 'limit' parameter to send in a request. Defaults to 'limit'. Set this
-     * to undefined if you don't want to send a limit parameter
-     */
-    limitParam: 'limit',
-    
+     * Reads a JSON object and returns a ResultSet. Uses the internal getTotal and getSuccess extractors to
+     * retrieve meta data from the response, and extractData to turn the JSON data into model instances.
+     * @param {Object} data The raw JSON data
+     * @return {Ext.data.ResultSet} A ResultSet containing model instances and meta data about the results
+     */
+    readRecords: function(data) {
+        //this has to be before the call to super because we use the meta data in the superclass readRecords
+        if (data.metaData) {
+            this.onMetaChange(data.metaData);
+        }
+
+        /**
+         * @deprecated will be removed in Ext JS 5.0. This is just a copy of this.rawData - use that instead
+         * @property {Object} jsonData
+         */
+        this.jsonData = data;
+        return this.callParent([data]);
+    },
+
+    //inherit docs
+    getResponseData: function(response) {
+        var data;
+        try {
+            data = Ext.decode(response.responseText);
+        }
+        catch (ex) {
+            Ext.Error.raise({
+                response: response,
+                json: response.responseText,
+                parseError: ex,
+                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
+            });
+        }
+        //<debug>
+        if (!data) {
+            Ext.Error.raise('JSON object not found');
+        }
+        //</debug>
+
+        return data;
+    },
+
+    //inherit docs
+    buildExtractors : function() {
+        var me = this;
+
+        me.callParent(arguments);
+
+        if (me.root) {
+            me.getRoot = me.createAccessor(me.root);
+        } else {
+            me.getRoot = function(root) {
+                return root;
+            };
+        }
+    },
+
     /**
-     * @cfg {String} groupParam The name of the 'group' parameter to send in a request. Defaults to 'group'. Set this
-     * to undefined if you don't want to send a group parameter
+     * @private
+     * We're just preparing the data for the superclass by pulling out the record objects we want. If a {@link #record}
+     * was specified we have to pull those out of the larger JSON object, which is most of what this function is doing
+     * @param {Object} root The JSON root node
+     * @return {Ext.data.Model[]} The records
      */
-    groupParam: 'group',
-    
+    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]);
+    },
+
     /**
-     * @cfg {String} sortParam The name of the 'sort' parameter to send in a request. Defaults to 'sort'. Set this
-     * to undefined if you don't want to send a sort parameter
+     * @private
+     * Returns an accessor function for the given property string. Gives support for properties such as the following:
+     * 'someProperty'
+     * 'some.property'
+     * 'some["property"]'
+     * This is used by buildExtractors to create optimized extractor functions when casting raw data into model instances.
      */
-    sortParam: 'sort',
+    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];
+            };
+        };
+    }()
+});
+/**
+ * @class Ext.data.writer.Json
+ * @extends Ext.data.writer.Writer
+
+This class is used to write {@link Ext.data.Model} data to the server in a JSON format.
+The {@link #allowSingle} configuration can be set to false to force the records to always be
+encoded in an array, even if there is only a single record being sent.
+
+ * @markdown
+ */
+Ext.define('Ext.data.writer.Json', {
+    extend: 'Ext.data.writer.Writer',
+    alternateClassName: 'Ext.data.JsonWriter',
+    alias: 'writer.json',
     
     /**
-     * @cfg {String} filterParam The name of the 'filter' parameter to send in a request. Defaults to 'filter'. Set 
-     * this to undefined if you don't want to send a filter parameter
+     * @cfg {String} root The key under which the records in this Writer will be placed. Defaults to <tt>undefined</tt>.
+     * Example generated request, using root: 'records':
+<pre><code>
+{'records': [{name: 'my record'}, {name: 'another record'}]}
+</code></pre>
      */
-    filterParam: 'filter',
+    root: undefined,
     
     /**
-     * @cfg {String} directionParam The name of the direction parameter to send in a request. <strong>This is only used when simpleSortMode is set to true.</strong>
-     * Defaults to 'dir'.
+     * @cfg {Boolean} encode True to use Ext.encode() on the data before sending. Defaults to <tt>false</tt>.
+     * The encode option should only be set to true when a {@link #root} is defined, because the values will be
+     * sent as part of the request parameters as opposed to a raw post. The root will be the name of the parameter
+     * sent to the server.
      */
-    directionParam: 'dir',
+    encode: false,
     
     /**
-     * @cfg {Boolean} simpleSortMode Enabling simpleSortMode in conjunction with remoteSort will only send one sort property and a direction when a remote sort is requested.
-     * The directionParam and sortParam will be sent with the property name and either 'ASC' or 'DESC'
+     * @cfg {Boolean} allowSingle False to ensure that records are always wrapped in an array, even if there is only
+     * one record being sent. When there is more than one record, they will always be encoded into an array.
+     * Defaults to <tt>true</tt>. Example:
+     * <pre><code>
+// with allowSingle: true
+"root": {
+    "first": "Mark",
+    "last": "Corrigan"
+}
+
+// with allowSingle: false
+"root": [{
+    "first": "Mark",
+    "last": "Corrigan"
+}]
+     * </code></pre>
      */
-    simpleSortMode: false,
+    allowSingle: true,
+    
+    //inherit docs
+    writeRecords: function(request, data) {
+        var root = this.root;
+        
+        if (this.allowSingle && data.length == 1) {
+            // convert to single object format
+            data = data[0];
+        }
+        
+        if (this.encode) {
+            if (root) {
+                // sending as a param, need to encode
+                request.params[root] = Ext.encode(data);
+            } else {
+                //<debug>
+                Ext.Error.raise('Must specify a root when using encode');
+                //</debug>
+            }
+        } else {
+            // send as jsonData
+            request.jsonData = request.jsonData || {};
+            if (root) {
+                request.jsonData[root] = data;
+            } else {
+                request.jsonData = data;
+            }
+        }
+        return request;
+    }
+});
+
+/**
+ * @author Ed Spencer
+ *
+ * Proxies are used by {@link Ext.data.Store Stores} to handle the loading and saving of {@link Ext.data.Model Model}
+ * data. Usually developers will not need to create or interact with proxies directly.
+ *
+ * # Types of Proxy
+ *
+ * There are two main types of Proxy - {@link Ext.data.proxy.Client Client} and {@link Ext.data.proxy.Server Server}.
+ * The Client proxies save their data locally and include the following subclasses:
+ *
+ * - {@link Ext.data.proxy.LocalStorage LocalStorageProxy} - saves its data to localStorage if the browser supports it
+ * - {@link Ext.data.proxy.SessionStorage SessionStorageProxy} - saves its data to sessionStorage if the browsers supports it
+ * - {@link Ext.data.proxy.Memory MemoryProxy} - holds data in memory only, any data is lost when the page is refreshed
+ *
+ * The Server proxies save their data by sending requests to some remote server. These proxies include:
+ *
+ * - {@link Ext.data.proxy.Ajax Ajax} - sends requests to a server on the same domain
+ * - {@link Ext.data.proxy.JsonP JsonP} - uses JSON-P to send requests to a server on a different domain
+ * - {@link Ext.data.proxy.Direct Direct} - uses {@link Ext.direct.Manager} to send requests
+ *
+ * Proxies operate on the principle that all operations performed are either Create, Read, Update or Delete. These four
+ * operations are mapped to the methods {@link #create}, {@link #read}, {@link #update} and {@link #destroy}
+ * respectively. Each Proxy subclass implements these functions.
+ *
+ * The CRUD methods each expect an {@link Ext.data.Operation Operation} object as the sole argument. The Operation
+ * encapsulates information about the action the Store wishes to perform, the {@link Ext.data.Model model} instances
+ * that are to be modified, etc. See the {@link Ext.data.Operation Operation} documentation for more details. Each CRUD
+ * method also accepts a callback function to be called asynchronously on completion.
+ *
+ * Proxies also support batching of Operations via a {@link Ext.data.Batch batch} object, invoked by the {@link #batch}
+ * method.
+ */
+Ext.define('Ext.data.proxy.Proxy', {
+    alias: 'proxy.proxy',
+    alternateClassName: ['Ext.data.DataProxy', 'Ext.data.Proxy'],
+    requires: [
+        'Ext.data.reader.Json',
+        'Ext.data.writer.Json'
+    ],
+    uses: [
+        'Ext.data.Batch', 
+        'Ext.data.Operation', 
+        'Ext.data.Model'
+    ],
+    mixins: {
+        observable: 'Ext.util.Observable'
+    },
     
     /**
-     * @cfg {Boolean} noCache (optional) Defaults to true. Disable caching by adding a unique parameter
-     * name to the request.
+     * @cfg {String} batchOrder
+     * Comma-separated ordering 'create', 'update' and 'destroy' actions when batching. Override this to set a different
+     * order for the batched CRUD actions to be executed in. Defaults to 'create,update,destroy'.
      */
-    noCache : true,
+    batchOrder: 'create,update,destroy',
     
     /**
-     * @cfg {String} cacheString The name of the cache param added to the url when using noCache (defaults to "_dc")
+     * @cfg {Boolean} batchActions
+     * True to batch actions of a particular type when synchronizing the store. Defaults to true.
      */
-    cacheString: "_dc",
+    batchActions: true,
     
     /**
-     * @cfg {Number} timeout (optional) The number of milliseconds to wait for a response.
-     * Defaults to 30000 milliseconds (30 seconds).
+     * @cfg {String} defaultReaderType
+     * The default registered reader type. Defaults to 'json'.
+     * @private
      */
-    timeout : 30000,
+    defaultReaderType: 'json',
     
     /**
-     * @cfg {Object} api
-     * Specific urls to call on CRUD action methods "create", "read", "update" and "destroy".
-     * Defaults to:<pre><code>
-api: {
-    create  : undefined,
-    read    : undefined,
-    update  : undefined,
-    destroy : undefined
-}
-     * </code></pre>
-     * <p>The url is built based upon the action being executed <tt>[create|read|update|destroy]</tt>
-     * using the commensurate <tt>{@link #api}</tt> property, or if undefined default to the
-     * configured {@link Ext.data.Store}.{@link Ext.data.proxy.Server#url url}.</p><br>
-     * <p>For example:</p>
-     * <pre><code>
-api: {
-    create  : '/controller/new',
-    read    : '/controller/load',
-    update  : '/controller/update',
-    destroy : '/controller/destroy_action'
-}
-     * </code></pre>
-     * <p>If the specific URL for a given CRUD action is undefined, the CRUD action request
-     * will be directed to the configured <tt>{@link Ext.data.proxy.Server#url url}</tt>.</p>
+     * @cfg {String} defaultWriterType
+     * The default registered writer type. Defaults to 'json'.
+     * @private
      */
+    defaultWriterType: 'json',
     
     /**
-     * @ignore
+     * @cfg {String/Ext.data.Model} model
+     * The name of the Model to tie to this Proxy. Can be either the string name of the Model, or a reference to the
+     * Model constructor. Required.
      */
-    constructor: function(config) {
-        var me = this;
-        
-        config = config || {};
-        this.addEvents(
-            /**
-             * @event exception
-             * Fires when the server returns an exception
-             * @param {Ext.data.proxy.Proxy} this
-             * @param {Object} response The response from the AJAX request
-             * @param {Ext.data.Operation} operation The operation that triggered request
-             */
-            'exception'
-        );
-        me.callParent([config]);
-        
-        /**
-         * @cfg {Object} extraParams Extra parameters that will be included on every request. Individual requests with params
-         * of the same name will override these params when they are in conflict.
-         */
-        me.extraParams = config.extraParams || {};
-        
-        me.api = config.api || {};
-        
-        //backwards compatibility, will be deprecated in 5.0
-        me.nocache = me.noCache;
-    },
-    
-    //in a ServerProxy all four CRUD operations are executed in the same manner, so we delegate to doRequest in each case
-    create: function() {
-        return this.doRequest.apply(this, arguments);
-    },
     
-    read: function() {
-        return this.doRequest.apply(this, arguments);
-    },
+    /**
+     * @cfg {Object/String/Ext.data.reader.Reader} reader
+     * The Ext.data.reader.Reader to use to decode the server's response or data read from client. This can either be a
+     * Reader instance, a config object or just a valid Reader type name (e.g. 'json', 'xml').
+     */
     
-    update: function() {
-        return this.doRequest.apply(this, arguments);
-    },
+    /**
+     * @cfg {Object/String/Ext.data.writer.Writer} writer
+     * The Ext.data.writer.Writer to use to encode any request sent to the server or saved to client. This can either be
+     * a Writer instance, a config object or just a valid Writer type name (e.g. 'json', 'xml').
+     */
     
-    destroy: function() {
-        return this.doRequest.apply(this, arguments);
-    },
+    isProxy: true,
     
     /**
-     * Creates and returns an Ext.data.Request object based on the options passed by the {@link Ext.data.Store Store}
-     * that this Proxy is attached to.
-     * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute
-     * @return {Ext.data.Request} The request object
+     * Creates the Proxy
+     * @param {Object} config (optional) Config object.
      */
-    buildRequest: function(operation) {
-        var params = Ext.applyIf(operation.params || {}, this.extraParams || {}),
-            request;
-        
-        //copy any sorters, filters etc into the params so they can be sent over the wire
-        params = Ext.applyIf(params, this.getParams(params, operation));
+    constructor: function(config) {
+        config = config || {};
         
-        if (operation.id && !params.id) {
-            params.id = operation.id;
+        if (config.model === undefined) {
+            delete config.model;
         }
+
+        this.mixins.observable.constructor.call(this, config);
         
-        request = Ext.create('Ext.data.Request', {
-            params   : params,
-            action   : operation.action,
-            records  : operation.records,
-            operation: operation,
-            url      : operation.url
-        });
-        
-        request.url = this.buildUrl(request);
-        
-        /*
-         * Save the request on the Operation. Operations don't usually care about Request and Response data, but in the
-         * ServerProxy and any of its subclasses we add both request and response as they may be useful for further processing
-         */
-        operation.request = request;
-        
-        return request;
+        if (this.model !== undefined && !(this.model instanceof Ext.data.Model)) {
+            this.setModel(this.model);
+        }
     },
     
     /**
-     * 
+     * Sets the model associated with this proxy. This will only usually be called by a Store
+     *
+     * @param {String/Ext.data.Model} model The new model. Can be either the model name string,
+     * or a reference to the model's constructor
+     * @param {Boolean} setOnStore Sets the new model on the associated Store, if one is present
      */
-    processResponse: function(success, operation, request, response, callback, scope){
-        var me = this,
-            reader,
-            result,
-            records,
-            length,
-            mc,
-            record,
-            i;
-            
-        if (success === true) {
-            reader = me.getReader();
-            result = reader.read(me.extractResponseData(response));
-            records = result.records;
-            length = records.length;
-            
-            if (result.success !== false) {
-                mc = Ext.create('Ext.util.MixedCollection', true, function(r) {return r.getId();});
-                mc.addAll(operation.records);
-                for (i = 0; i < length; i++) {
-                    record = mc.get(records[i].getId());
-                    
-                    if (record) {
-                        record.beginEdit();
-                        record.set(record.data);
-                        record.endEdit(true);
-                    }
-                }
-                
-                //see comment in buildRequest for why we include the response object here
-                Ext.apply(operation, {
-                    response: response,
-                    resultSet: result
-                });
-                
-                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);              
-        }
-            
-        //this callback is the one that was passed to the 'read' or 'write' function above
-        if (typeof callback == 'function') {
-            callback.call(scope || me, operation);
+    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);
         }
-            
-        me.afterRequest(request, success);
     },
     
     /**
-     * Sets up an exception on the operation
-     * @private
-     * @param {Ext.data.Operation} operation The operation
-     * @param {Object} response The response
+     * Returns the model attached to this Proxy
+     * @return {Ext.data.Model} The model
      */
-    setException: function(operation, response){
-        operation.setException({
-            status: response.status,
-            statusText: response.statusText
-        });     
+    getModel: function() {
+        return this.model;
     },
     
     /**
-     * Template method to allow subclasses to specify how to get the response for the reader.
-     * @private
-     * @param {Object} response The server response
-     * @return {Mixed} The response data to be used by the reader
+     * Sets the Proxy's Reader by string, config object or Reader instance
+     *
+     * @param {String/Object/Ext.data.reader.Reader} reader The new Reader, which can be either a type string,
+     * a configuration object or an Ext.data.reader.Reader instance
+     * @return {Ext.data.reader.Reader} The attached Reader object
      */
-    extractResponseData: function(response){
-        return response; 
+    setReader: function(reader) {
+        var me = this;
+        
+        if (reader === undefined || typeof reader == 'string') {
+            reader = {
+                type: reader
+            };
+        }
+
+        if (reader.isReader) {
+            reader.setModel(me.model);
+        } else {
+            Ext.applyIf(reader, {
+                proxy: me,
+                model: me.model,
+                type : me.defaultReaderType
+            });
+
+            reader = Ext.createByAlias('reader.' + reader.type, reader);
+        }
+        
+        me.reader = reader;
+        return me.reader;
     },
     
     /**
-     * Encode any values being sent to the server. Can be overridden in subclasses.
-     * @private
-     * @param {Array} An array of sorters/filters.
-     * @return {Mixed} The encoded value
+     * Returns the reader currently attached to this proxy instance
+     * @return {Ext.data.reader.Reader} The Reader instance
      */
-    applyEncoding: function(value){
-        return Ext.encode(value);
+    getReader: function() {
+        return this.reader;
     },
     
     /**
-     * Encodes the array of {@link Ext.util.Sorter} objects into a string to be sent in the request url. By default, 
-     * this simply JSON-encodes the sorter data
-     * @param {Array} sorters The array of {@link Ext.util.Sorter Sorter} objects
-     * @return {String} The encoded sorters
+     * Sets the Proxy's Writer by string, config object or Writer instance
+     *
+     * @param {String/Object/Ext.data.writer.Writer} writer The new Writer, which can be either a type string,
+     * a configuration object or an Ext.data.writer.Writer instance
+     * @return {Ext.data.writer.Writer} The attached Writer object
      */
-    encodeSorters: function(sorters) {
-        var min = [],
-            length = sorters.length,
-            i = 0;
-        
-        for (; i < length; i++) {
-            min[i] = {
-                property : sorters[i].property,
-                direction: sorters[i].direction
+    setWriter: function(writer) {
+        if (writer === undefined || typeof writer == 'string') {
+            writer = {
+                type: writer
             };
         }
-        return this.applyEncoding(min);
+
+        if (!(writer instanceof Ext.data.writer.Writer)) {
+            Ext.applyIf(writer, {
+                model: this.model,
+                type : this.defaultWriterType
+            });
+
+            writer = Ext.createByAlias('writer.' + writer.type, writer);
+        }
+        
+        this.writer = writer;
         
+        return this.writer;
     },
     
     /**
-     * Encodes the array of {@link Ext.util.Filter} objects into a string to be sent in the request url. By default, 
-     * this simply JSON-encodes the filter data
-     * @param {Array} sorters The array of {@link Ext.util.Filter Filter} objects
-     * @return {String} The encoded filters
+     * Returns the writer currently attached to this proxy instance
+     * @return {Ext.data.writer.Writer} The Writer instance
      */
-    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);
+    getWriter: function() {
+        return this.writer;
     },
     
     /**
-     * @private
-     * Copy any sorters, filters etc into the params so they can be sent over the wire
+     * Performs the given create operation.
+     * @param {Ext.data.Operation} operation The Operation to perform
+     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
+     * @param {Object} scope Scope to execute the callback function in
+     * @method
      */
-    getParams: function(params, operation) {
-        params = params || {};
-        
-        var me             = this,
-            isDef          = Ext.isDefined,
-            groupers       = operation.groupers,
-            sorters        = operation.sorters,
-            filters        = operation.filters,
-            page           = operation.page,
-            start          = operation.start,
-            limit          = operation.limit,
-            
-            simpleSortMode = me.simpleSortMode,
-            
-            pageParam      = me.pageParam,
-            startParam     = me.startParam,
-            limitParam     = me.limitParam,
-            groupParam     = me.groupParam,
-            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) {
-            // Grouper is a subclass of sorter, so we can just use the sorter method
-            params[groupParam] = me.encodeSorters(groupers);
-        }
+    create: Ext.emptyFn,
+    
+    /**
+     * Performs the given read operation.
+     * @param {Ext.data.Operation} operation The Operation to perform
+     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
+     * @param {Object} scope Scope to execute the callback function in
+     * @method
+     */
+    read: Ext.emptyFn,
+    
+    /**
+     * Performs the given update operation.
+     * @param {Ext.data.Operation} operation The Operation to perform
+     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
+     * @param {Object} scope Scope to execute the callback function in
+     * @method
+     */
+    update: Ext.emptyFn,
+    
+    /**
+     * Performs the given destroy operation.
+     * @param {Ext.data.Operation} operation The Operation to perform
+     * @param {Function} callback Callback function to be called when the Operation has completed (whether successful or not)
+     * @param {Object} scope Scope to execute the callback function in
+     * @method
+     */
+    destroy: Ext.emptyFn,
+    
+    /**
+     * Performs a batch of {@link Ext.data.Operation Operations}, in the order specified by {@link #batchOrder}. Used
+     * internally by {@link Ext.data.Store}'s {@link Ext.data.Store#sync sync} method. Example usage:
+     *
+     *     myProxy.batch({
+     *         create : [myModel1, myModel2],
+     *         update : [myModel3],
+     *         destroy: [myModel4, myModel5]
+     *     });
+     *
+     * Where the myModel* above are {@link Ext.data.Model Model} instances - in this case 1 and 2 are new instances and
+     * have not been saved before, 3 has been saved previously but needs to be updated, and 4 and 5 have already been
+     * saved but should now be destroyed.
+     *
+     * @param {Object} operations Object containing the Model instances to act upon, keyed by action name
+     * @param {Object} listeners (optional) listeners object passed straight through to the Batch -
+     * see {@link Ext.data.Batch}
+     * @return {Ext.data.Batch} The newly created Ext.data.Batch object
+     */
+    batch: function(operations, listeners) {
+        var me = this,
+            batch = Ext.create('Ext.data.Batch', {
+                proxy: me,
+                listeners: listeners || {}
+            }),
+            useBatch = me.batchActions, 
+            records;
+        
+        Ext.each(me.batchOrder.split(','), function(action) {
+            records = operations[action];
+            if (records) {
+                if (useBatch) {
+                    batch.add(Ext.create('Ext.data.Operation', {
+                        action: action,
+                        records: records
+                    }));
+                } else {
+                    Ext.each(records, function(record){
+                        batch.add(Ext.create('Ext.data.Operation', {
+                            action : action, 
+                            records: [record]
+                        }));
+                    });
+                }
+            }
+        }, me);
         
+        batch.start();
+        return batch;
+    }
+}, function() {
+    // Ext.data.proxy.ProxyMgr.registerType('proxy', this);
+    
+    //backwards compatibility
+    Ext.data.DataProxy = this;
+    // Ext.deprecate('platform', '2.0', function() {
+    //     Ext.data.DataProxy = this;
+    // }, this);
+});
+
+/**
+ * @author Ed Spencer
+ *
+ * ServerProxy is a superclass of {@link Ext.data.proxy.JsonP JsonPProxy} and {@link Ext.data.proxy.Ajax AjaxProxy}, and
+ * would not usually be used directly.
+ *
+ * ServerProxy should ideally be named HttpProxy as it is a superclass for all HTTP proxies - for Ext JS 4.x it has been
+ * called ServerProxy to enable any 3.x applications that reference the HttpProxy to continue to work (HttpProxy is now
+ * an alias of AjaxProxy).
+ * @private
+ */
+Ext.define('Ext.data.proxy.Server', {
+    extend: 'Ext.data.proxy.Proxy',
+    alias : 'proxy.server',
+    alternateClassName: 'Ext.data.ServerProxy',
+    uses  : ['Ext.data.Request'],
+
+    /**
+     * @cfg {String} url
+     * The URL from which to request the data object.
+     */
+
+    /**
+     * @cfg {String} pageParam
+     * The name of the 'page' parameter to send in a request. Defaults to 'page'. Set this to undefined if you don't
+     * want to send a page parameter.
+     */
+    pageParam: 'page',
+
+    /**
+     * @cfg {String} startParam
+     * The name of the 'start' parameter to send in a request. Defaults to 'start'. Set this to undefined if you don't
+     * want to send a start parameter.
+     */
+    startParam: 'start',
+
+    /**
+     * @cfg {String} limitParam
+     * The name of the 'limit' parameter to send in a request. Defaults to 'limit'. Set this to undefined if you don't
+     * want to send a limit parameter.
+     */
+    limitParam: 'limit',
+
+    /**
+     * @cfg {String} groupParam
+     * The name of the 'group' parameter to send in a request. Defaults to 'group'. Set this to undefined if you don't
+     * want to send a group parameter.
+     */
+    groupParam: 'group',
+
+    /**
+     * @cfg {String} sortParam
+     * The name of the 'sort' parameter to send in a request. Defaults to 'sort'. Set this to undefined if you don't
+     * want to send a sort parameter.
+     */
+    sortParam: 'sort',
+
+    /**
+     * @cfg {String} filterParam
+     * The name of the 'filter' parameter to send in a request. Defaults to 'filter'. Set this to undefined if you don't
+     * want to send a filter parameter.
+     */
+    filterParam: 'filter',
+
+    /**
+     * @cfg {String} directionParam
+     * The name of the direction parameter to send in a request. **This is only used when simpleSortMode is set to
+     * true.** Defaults to 'dir'.
+     */
+    directionParam: 'dir',
+
+    /**
+     * @cfg {Boolean} simpleSortMode
+     * Enabling simpleSortMode in conjunction with remoteSort will only send one sort property and a direction when a
+     * remote sort is requested. The directionParam and sortParam will be sent with the property name and either 'ASC'
+     * or 'DESC'.
+     */
+    simpleSortMode: false,
+
+    /**
+     * @cfg {Boolean} noCache
+     * Disable caching by adding a unique parameter name to the request. Set to false to allow caching. Defaults to true.
+     */
+    noCache : true,
+
+    /**
+     * @cfg {String} cacheString
+     * The name of the cache param added to the url when using noCache. Defaults to "_dc".
+     */
+    cacheString: "_dc",
+
+    /**
+     * @cfg {Number} timeout
+     * The number of milliseconds to wait for a response. Defaults to 30000 milliseconds (30 seconds).
+     */
+    timeout : 30000,
+
+    /**
+     * @cfg {Object} api
+     * Specific urls to call on CRUD action methods "create", "read", "update" and "destroy". Defaults to:
+     *
+     *     api: {
+     *         create  : undefined,
+     *         read    : undefined,
+     *         update  : undefined,
+     *         destroy : undefined
+     *     }
+     *
+     * The url is built based upon the action being executed [create|read|update|destroy] using the commensurate
+     * {@link #api} property, or if undefined default to the configured
+     * {@link Ext.data.Store}.{@link Ext.data.proxy.Server#url url}.
+     *
+     * For example:
+     *
+     *     api: {
+     *         create  : '/controller/new',
+     *         read    : '/controller/load',
+     *         update  : '/controller/update',
+     *         destroy : '/controller/destroy_action'
+     *     }
+     *
+     * If the specific URL for a given CRUD action is undefined, the CRUD action request will be directed to the
+     * configured {@link Ext.data.proxy.Server#url url}.
+     */
+
+    constructor: function(config) {
+        var me = this;
+
+        config = config || {};
+        this.addEvents(
+            /**
+             * @event exception
+             * Fires when the server returns an exception
+             * @param {Ext.data.proxy.Proxy} this
+             * @param {Object} response The response from the AJAX request
+             * @param {Ext.data.Operation} operation The operation that triggered request
+             */
+            'exception'
+        );
+        me.callParent([config]);
+
+        /**
+         * @cfg {Object} extraParams
+         * Extra parameters that will be included on every request. Individual requests with params of the same name
+         * will override these params when they are in conflict.
+         */
+        me.extraParams = config.extraParams || {};
+
+        me.api = config.api || {};
+
+        //backwards compatibility, will be deprecated in 5.0
+        me.nocache = me.noCache;
+    },
+
+    //in a ServerProxy all four CRUD operations are executed in the same manner, so we delegate to doRequest in each case
+    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);
+    },
+
+    /**
+     * Creates and returns an Ext.data.Request object based on the options passed by the {@link Ext.data.Store Store}
+     * that this Proxy is attached to.
+     * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute
+     * @return {Ext.data.Request} The request object
+     */
+    buildRequest: function(operation) {
+        var params = Ext.applyIf(operation.params || {}, this.extraParams || {}),
+            request;
+
+        //copy any sorters, filters etc into the params so they can be sent over the wire
+        params = Ext.applyIf(params, this.getParams(operation));
+
+        if (operation.id && !params.id) {
+            params.id = operation.id;
+        }
+
+        request = Ext.create('Ext.data.Request', {
+            params   : params,
+            action   : operation.action,
+            records  : operation.records,
+            operation: operation,
+            url      : operation.url
+        });
+
+        request.url = this.buildUrl(request);
+
+        /*
+         * Save the request on the Operation. Operations don't usually care about Request and Response data, but in the
+         * ServerProxy and any of its subclasses we add both request and response as they may be useful for further processing
+         */
+        operation.request = request;
+
+        return request;
+    },
+
+    // Should this be documented as protected method?
+    processResponse: function(success, operation, request, response, callback, scope){
+        var me = this,
+            reader,
+            result;
+
+        if (success === true) {
+            reader = me.getReader();
+            result = reader.read(me.extractResponseData(response));
+
+            if (result.success !== false) {
+                //see comment in buildRequest for why we include the response object here
+                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);
+        }
+
+        //this callback is the one that was passed to the 'read' or 'write' function above
+        if (typeof callback == 'function') {
+            callback.call(scope || me, operation);
+        }
+
+        me.afterRequest(request, success);
+    },
+
+    /**
+     * Sets up an exception on the operation
+     * @private
+     * @param {Ext.data.Operation} operation The operation
+     * @param {Object} response The response
+     */
+    setException: function(operation, response){
+        operation.setException({
+            status: response.status,
+            statusText: response.statusText
+        });
+    },
+
+    /**
+     * Template method to allow subclasses to specify how to get the response for the reader.
+     * @template
+     * @private
+     * @param {Object} response The server response
+     * @return {Object} The response data to be used by the reader
+     */
+    extractResponseData: function(response){
+        return response;
+    },
+
+    /**
+     * Encode any values being sent to the server. Can be overridden in subclasses.
+     * @private
+     * @param {Array} An array of sorters/filters.
+     * @return {Object} The encoded value
+     */
+    applyEncoding: function(value){
+        return Ext.encode(value);
+    },
+
+    /**
+     * Encodes the array of {@link Ext.util.Sorter} objects into a string to be sent in the request url. By default,
+     * this simply JSON-encodes the sorter data
+     * @param {Ext.util.Sorter[]} sorters The array of {@link Ext.util.Sorter Sorter} objects
+     * @return {String} The encoded sorters
+     */
+    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);
+
+    },
+
+    /**
+     * Encodes the array of {@link Ext.util.Filter} objects into a string to be sent in the request url. By default,
+     * this simply JSON-encodes the filter data
+     * @param {Ext.util.Filter[]} filters The array of {@link Ext.util.Filter Filter} objects
+     * @return {String} The encoded filters
+     */
+    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);
+    },
+
+    /**
+     * @private
+     * Copy any sorters, filters etc into the params so they can be sent over the wire
+     */
+    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,
+
+            pageParam      = me.pageParam,
+            startParam     = me.startParam,
+            limitParam     = me.limitParam,
+            groupParam     = me.groupParam,
+            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) {
+            // Grouper is a subclass of sorter, so we can just use the sorter method
+            params[groupParam] = me.encodeSorters(groupers);
+        }
+
         if (sortParam && sorters && sorters.length > 0) {
             if (simpleSortMode) {
                 params[sortParam] = sorters[0].property;
@@ -18621,40 +18969,39 @@ api: {
             } else {
                 params[sortParam] = me.encodeSorters(sorters);
             }
-            
+
         }
-        
+
         if (filterParam && filters && filters.length > 0) {
             params[filterParam] = me.encodeFilters(filters);
         }
-        
+
         return params;
     },
-    
+
     /**
-     * Generates a url based on a given Ext.data.Request object. By default, ServerProxy's buildUrl will
-     * add the cache-buster param to the end of the url. Subclasses may need to perform additional modifications
-     * to the url.
+     * Generates a url based on a given Ext.data.Request object. By default, ServerProxy's buildUrl will add the
+     * cache-buster param to the end of the url. Subclasses may need to perform additional modifications to the url.
      * @param {Ext.data.Request} request The request object
      * @return {String} The url
      */
     buildUrl: function(request) {
         var me = this,
             url = me.getUrl(request);
-        
+
         //<debug>
         if (!url) {
             Ext.Error.raise("You are using a ServerProxy but have not supplied it with a url.");
         }
         //</debug>
-        
+
         if (me.noCache) {
             url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.cacheString, Ext.Date.now()));
         }
-        
+
         return url;
     },
-    
+
     /**
      * Get the url for the request taking into account the order of priority,
      * - The request
@@ -18667,11 +19014,13 @@ api: {
     getUrl: function(request){
         return request.url || this.api[request.action] || this.url;
     },
-    
+
     /**
-     * In ServerProxy subclasses, the {@link #create}, {@link #read}, {@link #update} and {@link #destroy} methods all pass
-     * through to doRequest. Each ServerProxy subclass must implement the doRequest method - see {@link Ext.data.proxy.JsonP}
-     * and {@link Ext.data.proxy.Ajax} for examples. This method carries the same signature as each of the methods that delegate to it.
+     * In ServerProxy subclasses, the {@link #create}, {@link #read}, {@link #update} and {@link #destroy} methods all
+     * pass through to doRequest. Each ServerProxy subclass must implement the doRequest method - see {@link
+     * Ext.data.proxy.JsonP} and {@link Ext.data.proxy.Ajax} for examples. This method carries the same signature as
+     * each of the methods that delegate to it.
+     *
      * @param {Ext.data.Operation} operation The Ext.data.Operation object
      * @param {Function} callback The callback function to call when the Operation has completed
      * @param {Object} scope The scope in which to execute the callback
@@ -18681,7 +19030,7 @@ api: {
         Ext.Error.raise("The doRequest function has not been implemented on your Ext.data.proxy.Server subclass. See src/data/ServerProxy.js for details");
         //</debug>
     },
-    
+
     /**
      * Optional callback function which can be used to clean up after a request has been completed.
      * @param {Ext.data.Request} request The Request object
@@ -18689,7 +19038,7 @@ api: {
      * @method
      */
     afterRequest: Ext.emptyFn,
-    
+
     onDestroy: function() {
         Ext.destroy(this.reader, this.writer);
     }
@@ -18697,236 +19046,207 @@ api: {
 
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.Ajax
- * @extends Ext.data.proxy.Server
- * 
- * <p>AjaxProxy is one of the most widely-used ways of getting data into your application. It uses AJAX requests to 
- * load data from the server, usually to be placed into a {@link Ext.data.Store Store}. Let's take a look at a typical
- * setup. Here we're going to set up a Store that has an AjaxProxy. To prepare, we'll also set up a 
- * {@link Ext.data.Model Model}:</p>
- * 
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'name', 'email']
-});
-
-//The Store contains the AjaxProxy as an inline configuration
-var store = new Ext.data.Store({
-    model: 'User',
-    proxy: {
-        type: 'ajax',
-        url : 'users.json'
-    }
-});
-
-store.load();
-</code></pre>
- * 
- * <p>Our example is going to load user data into a Store, so we start off by defining a {@link Ext.data.Model Model}
- * with the fields that we expect the server to return. Next we set up the Store itself, along with a {@link #proxy}
- * configuration. This configuration was automatically turned into an Ext.data.proxy.Ajax instance, with the url we
- * specified being passed into AjaxProxy's constructor. It's as if we'd done this:</p>
- * 
-<pre><code>
-new Ext.data.proxy.Ajax({
-    url: 'users.json',
-    model: 'User',
-    reader: 'json'
-});
-</code></pre>
- * 
- * <p>A couple of extra configurations appeared here - {@link #model} and {@link #reader}. These are set by default 
- * when we create the proxy via the Store - the Store already knows about the Model, and Proxy's default 
- * {@link Ext.data.reader.Reader Reader} is {@link Ext.data.reader.Json JsonReader}.</p>
- * 
- * <p>Now when we call store.load(), the AjaxProxy springs into action, making a request to the url we configured
- * ('users.json' in this case). As we're performing a read, it sends a GET request to that url (see {@link #actionMethods}
- * to customize this - by default any kind of read will be sent as a GET request and any kind of write will be sent as a
- * POST request).</p>
- * 
- * <p><u>Limitations</u></p>
- * 
- * <p>AjaxProxy cannot be used to retrieve data from other domains. If your application is running on http://domainA.com
- * it cannot load data from http://domainB.com because browsers have a built-in security policy that prohibits domains
- * talking to each other via AJAX.</p>
- * 
- * <p>If you need to read data from another domain and can't set up a proxy server (some software that runs on your own
+ *
+ * AjaxProxy is one of the most widely-used ways of getting data into your application. It uses AJAX requests to load
+ * data from the server, usually to be placed into a {@link Ext.data.Store Store}. Let's take a look at a typical setup.
+ * Here we're going to set up a Store that has an AjaxProxy. To prepare, we'll also set up a {@link Ext.data.Model
+ * Model}:
+ *
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'name', 'email']
+ *     });
+ *
+ *     //The Store contains the AjaxProxy as an inline configuration
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: 'User',
+ *         proxy: {
+ *             type: 'ajax',
+ *             url : 'users.json'
+ *         }
+ *     });
+ *
+ *     store.load();
+ *
+ * Our example is going to load user data into a Store, so we start off by defining a {@link Ext.data.Model Model} with
+ * the fields that we expect the server to return. Next we set up the Store itself, along with a
+ * {@link Ext.data.Store#proxy proxy} configuration. This configuration was automatically turned into an
+ * Ext.data.proxy.Ajax instance, with the url we specified being passed into AjaxProxy's constructor.
+ * It's as if we'd done this:
+ *
+ *     new Ext.data.proxy.Ajax({
+ *         url: 'users.json',
+ *         model: 'User',
+ *         reader: 'json'
+ *     });
+ *
+ * A couple of extra configurations appeared here - {@link #model} and {@link #reader}. These are set by default when we
+ * create the proxy via the Store - the Store already knows about the Model, and Proxy's default {@link
+ * Ext.data.reader.Reader Reader} is {@link Ext.data.reader.Json JsonReader}.
+ *
+ * Now when we call store.load(), the AjaxProxy springs into action, making a request to the url we configured
+ * ('users.json' in this case). As we're performing a read, it sends a GET request to that url (see
+ * {@link #actionMethods} to customize this - by default any kind of read will be sent as a GET request and any kind of write
+ * will be sent as a POST request).
+ *
+ * # Limitations
+ *
+ * AjaxProxy cannot be used to retrieve data from other domains. If your application is running on http://domainA.com it
+ * cannot load data from http://domainB.com because browsers have a built-in security policy that prohibits domains
+ * talking to each other via AJAX.
+ *
+ * If you need to read data from another domain and can't set up a proxy server (some software that runs on your own
  * domain's web server and transparently forwards requests to http://domainB.com, making it look like they actually came
- * from http://domainA.com), you can use {@link Ext.data.proxy.JsonP} and a technique known as JSON-P (JSON with 
+ * from http://domainA.com), you can use {@link Ext.data.proxy.JsonP} and a technique known as JSON-P (JSON with
  * Padding), which can help you get around the problem so long as the server on http://domainB.com is set up to support
- * JSON-P responses. See {@link Ext.data.proxy.JsonP JsonPProxy}'s introduction docs for more details.</p>
- * 
- * <p><u>Readers and Writers</u></p>
- * 
- * <p>AjaxProxy can be configured to use any type of {@link Ext.data.reader.Reader Reader} to decode the server's response. If
- * no Reader is supplied, AjaxProxy will default to using a {@link Ext.data.reader.Json JsonReader}. Reader configuration
- * can be passed in as a simple object, which the Proxy automatically turns into a {@link Ext.data.reader.Reader Reader}
- * instance:</p>
- * 
-<pre><code>
-var proxy = new Ext.data.proxy.Ajax({
-    model: 'User',
-    reader: {
-        type: 'xml',
-        root: 'users'
-    }
-});
-
-proxy.getReader(); //returns an {@link Ext.data.reader.Xml XmlReader} instance based on the config we supplied
-</code></pre>
- * 
- * <p><u>Url generation</u></p>
- * 
- * <p>AjaxProxy automatically inserts any sorting, filtering, paging and grouping options into the url it generates for
- * each request. These are controlled with the following configuration options:</p>
- * 
- * <ul style="list-style-type: disc; padding-left: 20px;">
- *     <li>{@link #pageParam} - controls how the page number is sent to the server 
- *     (see also {@link #startParam} and {@link #limitParam})</li>
- *     <li>{@link #sortParam} - controls how sort information is sent to the server</li>
- *     <li>{@link #groupParam} - controls how grouping information is sent to the server</li>
- *     <li>{@link #filterParam} - controls how filter information is sent to the server</li>
- * </ul>
- * 
- * <p>Each request sent by AjaxProxy is described by an {@link Ext.data.Operation Operation}. To see how we can 
- * customize the generated urls, let's say we're loading the Proxy with the following Operation:</p>
- * 
-<pre><code>
-var operation = new Ext.data.Operation({
-    action: 'read',
-    page  : 2
-});
-</code></pre>
- * 
- * <p>Now we'll issue the request for this Operation by calling {@link #read}:</p>
- * 
-<pre><code>
-var proxy = new Ext.data.proxy.Ajax({
-    url: '/users'
-});
-
-proxy.read(operation); //GET /users?page=2
-</code></pre>
- * 
- * <p>Easy enough - the Proxy just copied the page property from the Operation. We can customize how this page data is
- * sent to the server:</p>
- * 
-<pre><code>
-var proxy = new Ext.data.proxy.Ajax({
-    url: '/users',
-    pagePage: 'pageNumber'
-});
-
-proxy.read(operation); //GET /users?pageNumber=2
-</code></pre>
- * 
- * <p>Alternatively, our Operation could have been configured to send start and limit parameters instead of page:</p>
- * 
-<pre><code>
-var operation = new Ext.data.Operation({
-    action: 'read',
-    start : 50,
-    limit : 25
-});
-
-var proxy = new Ext.data.proxy.Ajax({
-    url: '/users'
-});
-
-proxy.read(operation); //GET /users?start=50&limit=25
-</code></pre>
- * 
- * <p>Again we can customize this url:</p>
- * 
-<pre><code>
-var proxy = new Ext.data.proxy.Ajax({
-    url: '/users',
-    startParam: 'startIndex',
-    limitParam: 'limitIndex'
-});
-
-proxy.read(operation); //GET /users?startIndex=50&limitIndex=25
-</code></pre>
- * 
- * <p>AjaxProxy will also send sort and filter information to the server. Let's take a look at how this looks with a
- * more expressive Operation object:</p>
- * 
-<pre><code>
-var operation = new Ext.data.Operation({
-    action: 'read',
-    sorters: [
-        new Ext.util.Sorter({
-            property : 'name',
-            direction: 'ASC'
-        }),
-        new Ext.util.Sorter({
-            property : 'age',
-            direction: 'DESC'
-        })
-    ],
-    filters: [
-        new Ext.util.Filter({
-            property: 'eyeColor',
-            value   : 'brown'
-        })
-    ]
-});
-</code></pre>
- * 
- * <p>This is the type of object that is generated internally when loading a {@link Ext.data.Store Store} with sorters
- * and filters defined. By default the AjaxProxy will JSON encode the sorters and filters, resulting in something like
- * this (note that the url is escaped before sending the request, but is left unescaped here for clarity):</p>
- * 
-<pre><code>
-var proxy = new Ext.data.proxy.Ajax({
-    url: '/users'
-});
-
-proxy.read(operation); //GET /users?sort=[{"property":"name","direction":"ASC"},{"property":"age","direction":"DESC"}]&filter=[{"property":"eyeColor","value":"brown"}]
-</code></pre>
- * 
- * <p>We can again customize how this is created by supplying a few configuration options. Let's say our server is set 
- * up to receive sorting information is a format like "sortBy=name#ASC,age#DESC". We can configure AjaxProxy to provide
- * that format like this:</p>
- * 
- <pre><code>
- var proxy = new Ext.data.proxy.Ajax({
-     url: '/users',
-     sortParam: 'sortBy',
-     filterParam: 'filterBy',
-
-     //our custom implementation of sorter encoding - turns our sorters into "name#ASC,age#DESC"
-     encodeSorters: function(sorters) {
-         var length   = sorters.length,
-             sortStrs = [],
-             sorter, i;
-
-         for (i = 0; i < length; i++) {
-             sorter = sorters[i];
-
-             sortStrs[i] = sorter.property + '#' + sorter.direction
-         }
-
-         return sortStrs.join(",");
-     }
- });
-
- proxy.read(operation); //GET /users?sortBy=name#ASC,age#DESC&filterBy=[{"property":"eyeColor","value":"brown"}]
- </code></pre>
- * 
- * <p>We can also provide a custom {@link #encodeFilters} function to encode our filters.</p>
- * 
+ * JSON-P responses. See {@link Ext.data.proxy.JsonP JsonPProxy}'s introduction docs for more details.
+ *
+ * # Readers and Writers
+ *
+ * AjaxProxy can be configured to use any type of {@link Ext.data.reader.Reader Reader} to decode the server's response.
+ * If no Reader is supplied, AjaxProxy will default to using a {@link Ext.data.reader.Json JsonReader}. Reader
+ * configuration can be passed in as a simple object, which the Proxy automatically turns into a {@link
+ * Ext.data.reader.Reader Reader} instance:
+ *
+ *     var proxy = new Ext.data.proxy.Ajax({
+ *         model: 'User',
+ *         reader: {
+ *             type: 'xml',
+ *             root: 'users'
+ *         }
+ *     });
+ *
+ *     proxy.getReader(); //returns an {@link Ext.data.reader.Xml XmlReader} instance based on the config we supplied
+ *
+ * # Url generation
+ *
+ * AjaxProxy automatically inserts any sorting, filtering, paging and grouping options into the url it generates for
+ * each request. These are controlled with the following configuration options:
+ *
+ * - {@link #pageParam} - controls how the page number is sent to the server (see also {@link #startParam} and {@link #limitParam})
+ * - {@link #sortParam} - controls how sort information is sent to the server
+ * - {@link #groupParam} - controls how grouping information is sent to the server
+ * - {@link #filterParam} - controls how filter information is sent to the server
+ *
+ * Each request sent by AjaxProxy is described by an {@link Ext.data.Operation Operation}. To see how we can customize
+ * the generated urls, let's say we're loading the Proxy with the following Operation:
+ *
+ *     var operation = new Ext.data.Operation({
+ *         action: 'read',
+ *         page  : 2
+ *     });
+ *
+ * Now we'll issue the request for this Operation by calling {@link #read}:
+ *
+ *     var proxy = new Ext.data.proxy.Ajax({
+ *         url: '/users'
+ *     });
+ *
+ *     proxy.read(operation); //GET /users?page=2
+ *
+ * Easy enough - the Proxy just copied the page property from the Operation. We can customize how this page data is sent
+ * to the server:
+ *
+ *     var proxy = new Ext.data.proxy.Ajax({
+ *         url: '/users',
+ *         pagePage: 'pageNumber'
+ *     });
+ *
+ *     proxy.read(operation); //GET /users?pageNumber=2
+ *
+ * Alternatively, our Operation could have been configured to send start and limit parameters instead of page:
+ *
+ *     var operation = new Ext.data.Operation({
+ *         action: 'read',
+ *         start : 50,
+ *         limit : 25
+ *     });
+ *
+ *     var proxy = new Ext.data.proxy.Ajax({
+ *         url: '/users'
+ *     });
+ *
+ *     proxy.read(operation); //GET /users?start=50&limit;=25
+ *
+ * Again we can customize this url:
+ *
+ *     var proxy = new Ext.data.proxy.Ajax({
+ *         url: '/users',
+ *         startParam: 'startIndex',
+ *         limitParam: 'limitIndex'
+ *     });
+ *
+ *     proxy.read(operation); //GET /users?startIndex=50&limitIndex;=25
+ *
+ * AjaxProxy will also send sort and filter information to the server. Let's take a look at how this looks with a more
+ * expressive Operation object:
+ *
+ *     var operation = new Ext.data.Operation({
+ *         action: 'read',
+ *         sorters: [
+ *             new Ext.util.Sorter({
+ *                 property : 'name',
+ *                 direction: 'ASC'
+ *             }),
+ *             new Ext.util.Sorter({
+ *                 property : 'age',
+ *                 direction: 'DESC'
+ *             })
+ *         ],
+ *         filters: [
+ *             new Ext.util.Filter({
+ *                 property: 'eyeColor',
+ *                 value   : 'brown'
+ *             })
+ *         ]
+ *     });
+ *
+ * This is the type of object that is generated internally when loading a {@link Ext.data.Store Store} with sorters and
+ * filters defined. By default the AjaxProxy will JSON encode the sorters and filters, resulting in something like this
+ * (note that the url is escaped before sending the request, but is left unescaped here for clarity):
+ *
+ *     var proxy = new Ext.data.proxy.Ajax({
+ *         url: '/users'
+ *     });
+ *
+ *     proxy.read(operation); //GET /users?sort=[{"property":"name","direction":"ASC"},{"property":"age","direction":"DESC"}]&filter;=[{"property":"eyeColor","value":"brown"}]
+ *
+ * We can again customize how this is created by supplying a few configuration options. Let's say our server is set up
+ * to receive sorting information is a format like "sortBy=name#ASC,age#DESC". We can configure AjaxProxy to provide
+ * that format like this:
+ *
+ *      var proxy = new Ext.data.proxy.Ajax({
+ *          url: '/users',
+ *          sortParam: 'sortBy',
+ *          filterParam: 'filterBy',
+ *
+ *          //our custom implementation of sorter encoding - turns our sorters into "name#ASC,age#DESC"
+ *          encodeSorters: function(sorters) {
+ *              var length   = sorters.length,
+ *                  sortStrs = [],
+ *                  sorter, i;
+ *
+ *              for (i = 0; i < length; i++) {
+ *                  sorter = sorters[i];
+ *
+ *                  sortStrs[i] = sorter.property + '#' + sorter.direction
+ *              }
+ *
+ *              return sortStrs.join(",");
+ *          }
+ *      });
+ *
+ *      proxy.read(operation); //GET /users?sortBy=name#ASC,age#DESC&filterBy;=[{"property":"eyeColor","value":"brown"}]
+ *
+ * We can also provide a custom {@link #encodeFilters} function to encode our filters.
+ *
  * @constructor
- * 
- * <p>Note that if this HttpProxy is being used by a {@link Ext.data.Store Store}, then the
- * Store's call to {@link #load} will override any specified <tt>callback</tt> and <tt>params</tt>
- * options. In this case, use the Store's {@link Ext.data.Store#events events} to modify parameters,
- * or react to loading events. The Store's {@link Ext.data.Store#baseParams baseParams} may also be
- * used to pass parameters known at instantiation time.</p>
- * 
- * <p>If an options parameter is passed, the singleton {@link Ext.Ajax} object will be used to make
- * the request.</p>
+ * Note that if this HttpProxy is being used by a {@link Ext.data.Store Store}, then the Store's call to
+ * {@link Ext.data.Store#load load} will override any specified callback and params options. In this case, use the
+ * {@link Ext.data.Store Store}'s events to modify parameters, or react to loading events.
+ *
+ * @param {Object} config (optional) Config object.
+ * If an options parameter is passed, the singleton {@link Ext.Ajax} object will be used to make the request.
  */
 Ext.define('Ext.data.proxy.Ajax', {
     requires: ['Ext.util.MixedCollection', 'Ext.Ajax'],
@@ -18935,9 +19255,10 @@ Ext.define('Ext.data.proxy.Ajax', {
     alternateClassName: ['Ext.data.HttpProxy', 'Ext.data.AjaxProxy'],
     
     /**
-     * @property actionMethods
-     * Mapping of action name to HTTP request method. In the basic AjaxProxy these are set to 'GET' for 'read' actions and 'POST' 
-     * for 'create', 'update' and 'destroy' actions. The {@link Ext.data.proxy.Rest} maps these to the correct RESTful methods.
+     * @property {Object} actionMethods
+     * Mapping of action name to HTTP request method. In the basic AjaxProxy these are set to 'GET' for 'read' actions
+     * and 'POST' for 'create', 'update' and 'destroy' actions. The {@link Ext.data.proxy.Rest} maps these to the
+     * correct RESTful methods.
      */
     actionMethods: {
         create : 'POST',
@@ -18947,7 +19268,8 @@ Ext.define('Ext.data.proxy.Ajax', {
     },
     
     /**
-     * @cfg {Object} headers Any headers to add to the Ajax request. Defaults to <tt>undefined</tt>.
+     * @cfg {Object} headers
+     * Any headers to add to the Ajax request. Defaults to undefined.
      */
     
     /**
@@ -18976,7 +19298,8 @@ Ext.define('Ext.data.proxy.Ajax', {
     },
     
     /**
-     * Returns the HTTP method name for a given request. By default this returns based on a lookup on {@link #actionMethods}.
+     * Returns the HTTP method name for a given request. By default this returns based on a lookup on
+     * {@link #actionMethods}.
      * @param {Ext.data.Request} request The request object
      * @return {String} The HTTP method to use (should be one of 'GET', 'POST', 'PUT' or 'DELETE')
      */
@@ -19009,236 +19332,217 @@ Ext.define('Ext.data.proxy.Ajax', {
 
 /**
  * @author Ed Spencer
- * @class Ext.data.Model
  *
- * <p>A Model represents some object that your application manages. For example, one might define a Model for Users, Products,
- * Cars, or any other real-world object that we want to model in the system. Models are registered via the {@link Ext.ModelManager model manager},
- * and are used by {@link Ext.data.Store stores}, which are in turn used by many of the data-bound components in Ext.</p>
+ * A Model represents some object that your application manages. For example, one might define a Model for Users,
+ * Products, Cars, or any other real-world object that we want to model in the system. Models are registered via the
+ * {@link Ext.ModelManager model manager}, and are used by {@link Ext.data.Store stores}, which are in turn used by many
+ * of the data-bound components in Ext.
  *
- * <p>Models are defined as a set of fields and any arbitrary methods and properties relevant to the model. For example:</p>
+ * Models are defined as a set of fields and any arbitrary methods and properties relevant to the model. For example:
  *
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'name',  type: 'string'},
-        {name: 'age',   type: 'int'},
-        {name: 'phone', type: 'string'},
-        {name: 'alive', type: 'boolean', defaultValue: true}
-    ],
-
-    changeName: function() {
-        var oldName = this.get('name'),
-            newName = oldName + " The Barbarian";
-
-        this.set('name', newName);
-    }
-});
-</code></pre>
-*
-* <p>The fields array is turned into a {@link Ext.util.MixedCollection MixedCollection} automatically by the {@link Ext.ModelManager ModelManager}, and all
-* other functions and properties are copied to the new Model's prototype.</p>
-*
-* <p>Now we can create instances of our User model and call any model logic we defined:</p>
-*
-<pre><code>
-var user = Ext.ModelManager.create({
-    name : 'Conan',
-    age  : 24,
-    phone: '555-555-5555'
-}, 'User');
-
-user.changeName();
-user.get('name'); //returns "Conan The Barbarian"
-</code></pre>
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             {name: 'name',  type: 'string'},
+ *             {name: 'age',   type: 'int'},
+ *             {name: 'phone', type: 'string'},
+ *             {name: 'alive', type: 'boolean', defaultValue: true}
+ *         ],
  *
- * <p><u>Validations</u></p>
+ *         changeName: function() {
+ *             var oldName = this.get('name'),
+ *                 newName = oldName + " The Barbarian";
  *
- * <p>Models have built-in support for validations, which are executed against the validator functions in
- * {@link Ext.data.validations} ({@link Ext.data.validations see all validation functions}). Validations are easy to add to models:</p>
+ *             this.set('name', newName);
+ *         }
+ *     });
  *
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'name',     type: 'string'},
-        {name: 'age',      type: 'int'},
-        {name: 'phone',    type: 'string'},
-        {name: 'gender',   type: 'string'},
-        {name: 'username', type: 'string'},
-        {name: 'alive',    type: 'boolean', defaultValue: true}
-    ],
-
-    validations: [
-        {type: 'presence',  field: 'age'},
-        {type: 'length',    field: 'name',     min: 2},
-        {type: 'inclusion', field: 'gender',   list: ['Male', 'Female']},
-        {type: 'exclusion', field: 'username', list: ['Admin', 'Operator']},
-        {type: 'format',    field: 'username', matcher: /([a-z]+)[0-9]{2,3}/}
-    ]
-});
-</code></pre>
+ * The fields array is turned into a {@link Ext.util.MixedCollection MixedCollection} automatically by the {@link
+ * Ext.ModelManager ModelManager}, and all other functions and properties are copied to the new Model's prototype.
  *
- * <p>The validations can be run by simply calling the {@link #validate} function, which returns a {@link Ext.data.Errors}
- * object:</p>
+ * Now we can create instances of our User model and call any model logic we defined:
  *
-<pre><code>
-var instance = Ext.ModelManager.create({
-    name: 'Ed',
-    gender: 'Male',
-    username: 'edspencer'
-}, 'User');
-
-var errors = instance.validate();
-</code></pre>
+ *     var user = Ext.create('User', {
+ *         name : 'Conan',
+ *         age  : 24,
+ *         phone: '555-555-5555'
+ *     });
  *
- * <p><u>Associations</u></p>
+ *     user.changeName();
+ *     user.get('name'); //returns "Conan The Barbarian"
  *
- * <p>Models can have associations with other Models via {@link Ext.data.BelongsToAssociation belongsTo} and
- * {@link Ext.data.HasManyAssociation hasMany} associations. For example, let's say we're writing a blog administration
- * application which deals with Users, Posts and Comments. We can express the relationships between these models like this:</p>
+ * # Validations
  *
-<pre><code>
-Ext.define('Post', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'user_id'],
-
-    belongsTo: 'User',
-    hasMany  : {model: 'Comment', name: 'comments'}
-});
-
-Ext.define('Comment', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'user_id', 'post_id'],
-
-    belongsTo: 'Post'
-});
-
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id'],
-
-    hasMany: [
-        'Post',
-        {model: 'Comment', name: 'comments'}
-    ]
-});
-</code></pre>
+ * Models have built-in support for validations, which are executed against the validator functions in {@link
+ * Ext.data.validations} ({@link Ext.data.validations see all validation functions}). Validations are easy to add to
+ * models:
  *
- * <p>See the docs for {@link Ext.data.BelongsToAssociation} and {@link Ext.data.HasManyAssociation} for details on the usage
- * and configuration of associations. Note that associations can also be specified like this:</p>
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             {name: 'name',     type: 'string'},
+ *             {name: 'age',      type: 'int'},
+ *             {name: 'phone',    type: 'string'},
+ *             {name: 'gender',   type: 'string'},
+ *             {name: 'username', type: 'string'},
+ *             {name: 'alive',    type: 'boolean', defaultValue: true}
+ *         ],
  *
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id'],
-
-    associations: [
-        {type: 'hasMany', model: 'Post',    name: 'posts'},
-        {type: 'hasMany', model: 'Comment', name: 'comments'}
-    ]
-});
-</code></pre>
+ *         validations: [
+ *             {type: 'presence',  field: 'age'},
+ *             {type: 'length',    field: 'name',     min: 2},
+ *             {type: 'inclusion', field: 'gender',   list: ['Male', 'Female']},
+ *             {type: 'exclusion', field: 'username', list: ['Admin', 'Operator']},
+ *             {type: 'format',    field: 'username', matcher: /([a-z]+)[0-9]{2,3}/}
+ *         ]
+ *     });
  *
- * <p><u>Using a Proxy</u></p>
+ * The validations can be run by simply calling the {@link #validate} function, which returns a {@link Ext.data.Errors}
+ * object:
  *
- * <p>Models are great for representing types of data and relationships, but sooner or later we're going to want to
- * load or save that data somewhere. All loading and saving of data is handled via a {@link Ext.data.proxy.Proxy Proxy},
- * which can be set directly on the Model:</p>
+ *     var instance = Ext.create('User', {
+ *         name: 'Ed',
+ *         gender: 'Male',
+ *         username: 'edspencer'
+ *     });
  *
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'name', 'email'],
-
-    proxy: {
-        type: 'rest',
-        url : '/users'
-    }
-});
-</code></pre>
+ *     var errors = instance.validate();
  *
- * <p>Here we've set up a {@link Ext.data.proxy.Rest Rest Proxy}, which knows how to load and save data to and from a
- * RESTful backend. Let's see how this works:</p>
+ * # Associations
  *
-<pre><code>
-var user = Ext.ModelManager.create({name: 'Ed Spencer', email: 'ed@sencha.com'}, 'User');
-
-user.save(); //POST /users
-</code></pre>
+ * Models can have associations with other Models via {@link Ext.data.BelongsToAssociation belongsTo} and {@link
+ * Ext.data.HasManyAssociation hasMany} associations. For example, let's say we're writing a blog administration
+ * application which deals with Users, Posts and Comments. We can express the relationships between these models like
+ * this:
  *
- * <p>Calling {@link #save} on the new Model instance tells the configured RestProxy that we wish to persist this
- * Model's data onto our server. RestProxy figures out that this Model hasn't been saved before because it doesn't
- * have an id, and performs the appropriate action - in this case issuing a POST request to the url we configured
- * (/users). We configure any Proxy on any Model and always follow this API - see {@link Ext.data.proxy.Proxy} for a full
- * list.</p>
+ *     Ext.define('Post', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'user_id'],
  *
- * <p>Loading data via the Proxy is equally easy:</p>
+ *         belongsTo: 'User',
+ *         hasMany  : {model: 'Comment', name: 'comments'}
+ *     });
  *
-<pre><code>
-//get a reference to the User model class
-var User = Ext.ModelManager.getModel('User');
-
-//Uses the configured RestProxy to make a GET request to /users/123
-User.load(123, {
-    success: function(user) {
-        console.log(user.getId()); //logs 123
-    }
-});
-</code></pre>
+ *     Ext.define('Comment', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'user_id', 'post_id'],
  *
- * <p>Models can also be updated and destroyed easily:</p>
+ *         belongsTo: 'Post'
+ *     });
  *
-<pre><code>
-//the user Model we loaded in the last snippet:
-user.set('name', 'Edward Spencer');
-
-//tells the Proxy to save the Model. In this case it will perform a PUT request to /users/123 as this Model already has an id
-user.save({
-    success: function() {
-        console.log('The User was updated');
-    }
-});
-
-//tells the Proxy to destroy the Model. Performs a DELETE request to /users/123
-user.destroy({
-    success: function() {
-        console.log('The User was destroyed!');
-    }
-});
-</code></pre>
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id'],
  *
- * <p><u>Usage in Stores</u></p>
+ *         hasMany: [
+ *             'Post',
+ *             {model: 'Comment', name: 'comments'}
+ *         ]
+ *     });
  *
- * <p>It is very common to want to load a set of Model instances to be displayed and manipulated in the UI. We do this
- * by creating a {@link Ext.data.Store Store}:</p>
+ * See the docs for {@link Ext.data.BelongsToAssociation} and {@link Ext.data.HasManyAssociation} for details on the
+ * usage and configuration of associations. Note that associations can also be specified like this:
  *
-<pre><code>
-var store = new Ext.data.Store({
-    model: 'User'
-});
-
-//uses the Proxy we set up on Model to load the Store data
-store.load();
-</code></pre>
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id'],
+ *
+ *         associations: [
+ *             {type: 'hasMany', model: 'Post',    name: 'posts'},
+ *             {type: 'hasMany', model: 'Comment', name: 'comments'}
+ *         ]
+ *     });
+ *
+ * # Using a Proxy
+ *
+ * Models are great for representing types of data and relationships, but sooner or later we're going to want to load or
+ * save that data somewhere. All loading and saving of data is handled via a {@link Ext.data.proxy.Proxy Proxy}, which
+ * can be set directly on the Model:
+ *
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'name', 'email'],
+ *
+ *         proxy: {
+ *             type: 'rest',
+ *             url : '/users'
+ *         }
+ *     });
+ *
+ * Here we've set up a {@link Ext.data.proxy.Rest Rest Proxy}, which knows how to load and save data to and from a
+ * RESTful backend. Let's see how this works:
+ *
+ *     var user = Ext.create('User', {name: 'Ed Spencer', email: 'ed@sencha.com'});
+ *
+ *     user.save(); //POST /users
+ *
+ * Calling {@link #save} on the new Model instance tells the configured RestProxy that we wish to persist this Model's
+ * data onto our server. RestProxy figures out that this Model hasn't been saved before because it doesn't have an id,
+ * and performs the appropriate action - in this case issuing a POST request to the url we configured (/users). We
+ * configure any Proxy on any Model and always follow this API - see {@link Ext.data.proxy.Proxy} for a full list.
+ *
+ * Loading data via the Proxy is equally easy:
+ *
+ *     //get a reference to the User model class
+ *     var User = Ext.ModelManager.getModel('User');
+ *
+ *     //Uses the configured RestProxy to make a GET request to /users/123
+ *     User.load(123, {
+ *         success: function(user) {
+ *             console.log(user.getId()); //logs 123
+ *         }
+ *     });
+ *
+ * Models can also be updated and destroyed easily:
+ *
+ *     //the user Model we loaded in the last snippet:
+ *     user.set('name', 'Edward Spencer');
+ *
+ *     //tells the Proxy to save the Model. In this case it will perform a PUT request to /users/123 as this Model already has an id
+ *     user.save({
+ *         success: function() {
+ *             console.log('The User was updated');
+ *         }
+ *     });
+ *
+ *     //tells the Proxy to destroy the Model. Performs a DELETE request to /users/123
+ *     user.destroy({
+ *         success: function() {
+ *             console.log('The User was destroyed!');
+ *         }
+ *     });
+ *
+ * # Usage in Stores
+ *
+ * It is very common to want to load a set of Model instances to be displayed and manipulated in the UI. We do this by
+ * creating a {@link Ext.data.Store Store}:
+ *
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: 'User'
+ *     });
+ *
+ *     //uses the Proxy we set up on Model to load the Store data
+ *     store.load();
  *
- * <p>A Store is just a collection of Model instances - usually loaded from a server somewhere. Store can also maintain
- * a set of added, updated and removed Model instances to be synchronized with the server via the Proxy. See the
- * {@link Ext.data.Store Store docs} for more information on Stores.</p>
+ * A Store is just a collection of Model instances - usually loaded from a server somewhere. Store can also maintain a
+ * set of added, updated and removed Model instances to be synchronized with the server via the Proxy. See the {@link
+ * Ext.data.Store Store docs} for more information on Stores.
  *
  * @constructor
+ * Creates new Model instance.
  * @param {Object} data An object containing keys corresponding to this model's fields, and their associated values
  * @param {Number} id (optional) Unique ID to assign to this model instance
  */
 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',
@@ -19261,6 +19565,7 @@ Ext.define('Ext.data.Model', {
                 associations = data.associations || [],
                 belongsTo = data.belongsTo,
                 hasMany = data.hasMany,
+                idgen = data.idgen,
 
                 fieldsMixedCollection = new Ext.util.MixedCollection(false, function(field) {
                     return field.name;
@@ -19299,6 +19604,10 @@ Ext.define('Ext.data.Model', {
 
             data.fields = fieldsMixedCollection;
 
+            if (idgen) {
+                data.idgen = Ext.data.IdGenerator.get(idgen);
+            }
+
             //associations can be specified in the more convenient format (e.g. not inside an 'associations' array).
             //we support that here
             if (belongsTo) {
@@ -19383,9 +19692,12 @@ Ext.define('Ext.data.Model', {
 
     inheritableStatics: {
         /**
-         * Sets the Proxy to use for this model. Accepts any options that can be accepted by {@link Ext#createByAlias Ext.createByAlias}
+         * Sets the Proxy to use for this model. Accepts any options that can be accepted by
+         * {@link Ext#createByAlias Ext.createByAlias}.
          * @param {String/Object/Ext.data.proxy.Proxy} proxy The proxy
+         * @return {Ext.data.proxy.Proxy}
          * @static
+         * @inheritable
          */
         setProxy: function(proxy) {
             //make sure we have an Ext.data.proxy.Proxy object
@@ -19406,40 +19718,42 @@ Ext.define('Ext.data.Model', {
         /**
          * Returns the configured Proxy for this Model
          * @return {Ext.data.proxy.Proxy} The proxy
+         * @static
+         * @inheritable
          */
         getProxy: function() {
             return this.proxy;
         },
 
         /**
-         * <b>Static</b>. Asynchronously loads a model instance by id. Sample usage:
-    <pre><code>
-    MyApp.User = Ext.define('User', {
-        extend: 'Ext.data.Model',
-        fields: [
-            {name: 'id', type: 'int'},
-            {name: 'name', type: 'string'}
-        ]
-    });
-
-    MyApp.User.load(10, {
-        scope: this,
-        failure: function(record, operation) {
-            //do something if the load failed
-        },
-        success: function(record, operation) {
-            //do something if the load succeeded
-        },
-        callback: function(record, operation) {
-            //do something whether the load succeeded or failed
-        }
-    });
-    </code></pre>
+         * Asynchronously loads a model instance by id. Sample usage:
+         *
+         *     MyApp.User = Ext.define('User', {
+         *         extend: 'Ext.data.Model',
+         *         fields: [
+         *             {name: 'id', type: 'int'},
+         *             {name: 'name', type: 'string'}
+         *         ]
+         *     });
+         *
+         *     MyApp.User.load(10, {
+         *         scope: this,
+         *         failure: function(record, operation) {
+         *             //do something if the load failed
+         *         },
+         *         success: function(record, operation) {
+         *             //do something if the load succeeded
+         *         },
+         *         callback: function(record, operation) {
+         *             //do something whether the load succeeded or failed
+         *         }
+         *     });
+         *
          * @param {Number} id The id of the model to load
-         * @param {Object} config Optional config object containing success, failure and callback functions, plus optional scope
-         * @member Ext.data.Model
-         * @method load
+         * @param {Object} config (optional) config object containing success, failure and callback functions, plus
+         * optional scope
          * @static
+         * @inheritable
          */
         load: function(id, config) {
             config = Ext.apply({}, config);
@@ -19475,17 +19789,15 @@ Ext.define('Ext.data.Model', {
         COMMIT : 'commit',
 
         /**
-         * Generates a sequential id. This method is typically called when a record is {@link #create}d
-         * and {@link #Record no id has been specified}. The id will automatically be assigned
-         * to the record. The returned id takes the form:
-         * <tt>&#123;PREFIX}-&#123;AUTO_ID}</tt>.<div class="mdetail-params"><ul>
-         * <li><b><tt>PREFIX</tt></b> : String<p class="sub-desc"><tt>Ext.data.Model.PREFIX</tt>
-         * (defaults to <tt>'ext-record'</tt>)</p></li>
-         * <li><b><tt>AUTO_ID</tt></b> : String<p class="sub-desc"><tt>Ext.data.Model.AUTO_ID</tt>
-         * (defaults to <tt>1</tt> initially)</p></li>
-         * </ul></div>
-         * @param {Ext.data.Model} rec The record being created.  The record does not exist, it's a {@link #phantom}.
-         * @return {String} auto-generated string id, <tt>"ext-record-i++'</tt>;
+         * Generates a sequential id. This method is typically called when a record is {@link Ext#create
+         * create}d and {@link #constructor no id has been specified}. The id will automatically be assigned to the
+         * record. The returned id takes the form: {PREFIX}-{AUTO_ID}.
+         *
+         * - **PREFIX** : String - Ext.data.Model.PREFIX (defaults to 'ext-record')
+         * - **AUTO_ID** : String - Ext.data.Model.AUTO_ID (defaults to 1 initially)
+         *
+         * @param {Ext.data.Model} rec The record being created. The record does not exist, it's a {@link #phantom}.
+         * @return {String} auto-generated string id, `"ext-record-i++"`;
          * @static
          */
         id: function(rec) {
@@ -19495,23 +19807,98 @@ Ext.define('Ext.data.Model', {
             return id;
         }
     },
-    
+
     /**
-     * Internal flag used to track whether or not the model instance is currently being edited. Read-only
-     * @property editing
-     * @type Boolean
+     * @cfg {String/Object} idgen
+     * The id generator to use for this model. The default id generator does not generate
+     * values for the {@link #idProperty}.
+     *
+     * This can be overridden at the model level to provide a custom generator for a model.
+     * The simplest form of this would be:
+     *
+     *      Ext.define('MyApp.data.MyModel', {
+     *          extend: 'Ext.data.Model',
+     *          requires: ['Ext.data.SequentialIdGenerator'],
+     *          idgen: 'sequential',
+     *          ...
+     *      });
+     *
+     * The above would generate {@link Ext.data.SequentialIdGenerator sequential} id's such
+     * as 1, 2, 3 etc..
+     *
+     * Another useful id generator is {@link Ext.data.UuidGenerator}:
+     *
+     *      Ext.define('MyApp.data.MyModel', {
+     *          extend: 'Ext.data.Model',
+     *          requires: ['Ext.data.UuidGenerator'],
+     *          idgen: 'uuid',
+     *          ...
+     *      });
+     *
+     * An id generation can also be further configured:
+     *
+     *      Ext.define('MyApp.data.MyModel', {
+     *          extend: 'Ext.data.Model',
+     *          idgen: {
+     *              type: 'sequential',
+     *              seed: 1000,
+     *              prefix: 'ID_'
+     *          }
+     *      });
+     *
+     * The above would generate id's such as ID_1000, ID_1001, ID_1002 etc..
+     *
+     * If multiple models share an id space, a single generator can be shared:
+     *
+     *      Ext.define('MyApp.data.MyModelX', {
+     *          extend: 'Ext.data.Model',
+     *          idgen: {
+     *              type: 'sequential',
+     *              id: 'xy'
+     *          }
+     *      });
+     *
+     *      Ext.define('MyApp.data.MyModelY', {
+     *          extend: 'Ext.data.Model',
+     *          idgen: {
+     *              type: 'sequential',
+     *              id: 'xy'
+     *          }
+     *      });
+     *
+     * For more complex, shared id generators, a custom generator is the best approach.
+     * See {@link Ext.data.IdGenerator} for details on creating custom id generators.
+     *
+     * @markdown
+     */
+    idgen: {
+        isGenerator: true,
+        type: 'default',
+
+        generate: function () {
+            return null;
+        },
+        getRecId: function (rec) {
+            return rec.modelName + '-' + rec.internalId;
+        }
+    },
+
+    /**
+     * @property {Boolean} editing
+     * Internal flag used to track whether or not the model instance is currently being edited. Read-only.
      */
     editing : false,
 
     /**
-     * Readonly flag - true if this Record has been modified.
-     * @type Boolean
+     * @property {Boolean} dirty
+     * True if this Record has been modified. Read-only.
      */
     dirty : false,
 
     /**
-     * @cfg {String} persistenceProperty The property on this Persistable object that its data is saved to.
-     * Defaults to 'data' (e.g. all persistable data resides in this.data.)
+     * @cfg {String} persistenceProperty
+     * The property on this Persistable object that its data is saved to. Defaults to 'data'
+     * (e.g. all persistable data resides in this.data.)
      */
     persistenceProperty: 'data',
 
@@ -19519,42 +19906,73 @@ Ext.define('Ext.data.Model', {
     isModel: true,
 
     /**
-     * <tt>true</tt> when the record does not yet exist in a server-side database (see
-     * {@link #setDirty}).  Any record which has a real database pk set as its id property
-     * is NOT a phantom -- it's real.
-     * @property phantom
-     * @type {Boolean}
+     * @property {Boolean} phantom
+     * True when the record does not yet exist in a server-side database (see {@link #setDirty}).
+     * Any record which has a real database pk set as its id property is NOT a phantom -- it's real.
      */
     phantom : false,
 
     /**
-     * @cfg {String} idProperty The name of the field treated as this Model's unique id (defaults to 'id').
+     * @cfg {String} idProperty
+     * The name of the field treated as this Model's unique id. Defaults to 'id'.
      */
     idProperty: 'id',
 
     /**
-     * The string type of the default Model Proxy. Defaults to 'ajax'
-     * @property defaultProxyType
-     * @type String
+     * @cfg {String} defaultProxyType
+     * The string type of the default Model Proxy. Defaults to 'ajax'.
      */
     defaultProxyType: 'ajax',
 
+    // Fields config and property
+    /**
+     * @cfg {Object[]/String[]} fields
+     * The fields for this model.
+     */
+    /**
+     * @property {Ext.util.MixedCollection} fields
+     * The fields defined on this model.
+     */
+
+    /**
+     * @cfg {Object[]} validations
+     * An array of {@link Ext.data.validations validations} for this model.
+     */
+
+    // Associations configs and properties
+    /**
+     * @cfg {Object[]} associations
+     * An array of {@link Ext.data.Association associations} for this model.
+     */
+    /**
+     * @cfg {String/Object/String[]/Object[]} hasMany
+     * One or more {@link Ext.data.HasManyAssociation HasMany associations} for this model.
+     */
+    /**
+     * @cfg {String/Object/String[]/Object[]} belongsTo
+     * One or more {@link Ext.data.BelongsToAssociation BelongsTo associations} for this model.
+     */
+    /**
+     * @property {Ext.util.MixedCollection} associations
+     * {@link Ext.data.Association Associations} defined on this model.
+     */
+
     /**
-     * An array of the fields defined on this model
-     * @property fields
-     * @type {Array}
+     * @cfg {String/Object/Ext.data.proxy.Proxy} proxy
+     * The {@link Ext.data.proxy.Proxy proxy} to use for this model.
      */
 
     // raw not documented intentionally, meant to be used internally.
     constructor: function(data, id, raw) {
         data = data || {};
-        
+
         var me = this,
             fields,
             length,
             field,
             name,
             i,
+            newId,
             isArray = Ext.isArray(data),
             newData = isArray ? {} : null; // to hold mapped array data if needed
 
@@ -19565,22 +19983,18 @@ Ext.define('Ext.data.Model', {
          * @private
          */
         me.internalId = (id || id === 0) ? id : Ext.data.Model.id(me);
-        
+
         /**
-         * The raw data used to create this model if created via a reader.
-         * @property raw
-         * @type Object
+         * @property {Object} raw The raw data used to create this model if created via a reader.
          */
         me.raw = raw;
 
         Ext.applyIf(me, {
-            data: {}    
+            data: {}
         });
-        
+
         /**
-         * Key: value pairs of all fields whose values have changed
-         * @property modified
-         * @type Object
+         * @property {Object} modified Key: value pairs of all fields whose values have changed
          */
         me.modified = {};
 
@@ -19605,7 +20019,7 @@ Ext.define('Ext.data.Model', {
             field = fields[i];
             name  = field.name;
 
-            if (isArray){ 
+            if (isArray){
                 // Have to map array data so the values get assigned to the named fields
                 // rather than getting set as the field names with undefined values.
                 newData[name] = data[i];
@@ -19616,50 +20030,58 @@ Ext.define('Ext.data.Model', {
         }
 
         me.set(newData || data);
-        // clear any dirty/modified since we're initializing
-        me.dirty = false;
-        me.modified = {};
 
         if (me.getId()) {
             me.phantom = false;
+        } else if (me.phantom) {
+            newId = me.idgen.generate();
+            if (newId !== null) {
+                me.setId(newId);
+            }
         }
 
+        // clear any dirty/modified since we're initializing
+        me.dirty = false;
+        me.modified = {};
+
         if (typeof me.init == 'function') {
             me.init();
         }
 
-        me.id = me.modelName + '-' + me.internalId;
+        me.id = me.idgen.getRecId(me);
     },
-    
+
     /**
      * Returns the value of the given field
      * @param {String} fieldName The field to fetch the value for
-     * @return {Mixed} The value
+     * @return {Object} The value
      */
     get: function(field) {
         return this[this.persistenceProperty][field];
     },
-    
+
     /**
      * Sets the given field to the given value, marks the instance as dirty
-     * @param {String|Object} fieldName The field to set, or an object containing key/value pairs
-     * @param {Mixed} value The value to set
+     * @param {String/Object} fieldName The field to set, or an object containing key/value pairs
+     * @param {Object} value The value to set
      */
     set: function(fieldName, value) {
         var me = this,
             fields = me.fields,
             modified = me.modified,
             convertFields = [],
-            field, key, i, currentValue;
+            field, key, i, currentValue, notEditing, count, length;
 
         /*
          * If we're passed an object, iterate over that object. NOTE: we pull out fields with a convert function and
          * set those last so that all other possible data is set before the convert function is called
          */
         if (arguments.length == 1 && Ext.isObject(fieldName)) {
+            notEditing = !me.editing;
+            count = 0;
             for (key in fieldName) {
                 if (fieldName.hasOwnProperty(key)) {
-                
+
                     //here we check for the custom convert function. Note that if a field doesn't have a convert function,
                     //we default it to its type's convert function, so we have to check that here. This feels rather dirty.
                     field = fields.get(key);
@@ -19667,16 +20089,30 @@ Ext.define('Ext.data.Model', {
                         convertFields.push(key);
                         continue;
                     }
-                    
+
+                    if (!count && notEditing) {
+                        me.beginEdit();
+                    }
+                    ++count;
                     me.set(key, fieldName[key]);
                 }
             }
 
-            for (i = 0; i < convertFields.length; i++) {
-                field = convertFields[i];
-                me.set(field, fieldName[field]);
+            length = convertFields.length;
+            if (length) {
+                if (!count && notEditing) {
+                    me.beginEdit();
+                }
+                count += length;
+                for (i = 0; i < length; i++) {
+                    field = convertFields[i];
+                    me.set(field, fieldName[field]);
+                }
             }
 
+            if (notEditing && count) {
+                me.endEdit();
+            }
         } else {
             if (fields) {
                 field = fields.get(fieldName);
@@ -19687,7 +20123,7 @@ Ext.define('Ext.data.Model', {
             }
             currentValue = me.get(fieldName);
             me[me.persistenceProperty][fieldName] = value;
-            
+
             if (field && field.persist && !me.isEqual(currentValue, value)) {
                 if (me.isModified(fieldName)) {
                     if (me.isEqual(modified[fieldName], value)) {
@@ -19715,7 +20151,7 @@ Ext.define('Ext.data.Model', {
             }
         }
     },
-    
+
     /**
      * Checks if two values are equal, taking into account certain
      * special factors, for example dates.
@@ -19730,11 +20166,10 @@ Ext.define('Ext.data.Model', {
         }
         return a === b;
     },
-    
+
     /**
-     * Begin an edit. While in edit mode, no events (e.g.. the <code>update</code> event)
-     * are relayed to the containing store. When an edit has begun, it must be followed
-     * by either {@link #endEdit} or {@link #cancelEdit}.
+     * Begins an edit. While in edit mode, no events (e.g.. the `update` event) are relayed to the containing store.
+     * When an edit has begun, it must be followed by either {@link #endEdit} or {@link #cancelEdit}.
      */
     beginEdit : function(){
         var me = this;
@@ -19745,7 +20180,7 @@ Ext.define('Ext.data.Model', {
             me.modifiedSave = Ext.apply({}, me.modified);
         }
     },
-    
+
     /**
      * Cancels all changes made in the current edit operation.
      */
@@ -19762,28 +20197,54 @@ Ext.define('Ext.data.Model', {
             delete me.dirtySave;
         }
     },
-    
+
     /**
-     * End an edit. If any data was modified, the containing store is notified
-     * (ie, the store's <code>update</code> event will fire).
+     * Ends an edit. If any data was modified, the containing store is notified (ie, the store's `update` event will
+     * fire).
      * @param {Boolean} silent True to not notify the store of the change
      */
     endEdit : function(silent){
-        var me = this;
+        var me = this,
+            didChange;
+            
         if (me.editing) {
             me.editing = false;
+            didChange = me.dirty || me.changedWhileEditing();
             delete me.modifiedSave;
             delete me.dataSave;
             delete me.dirtySave;
-            if (silent !== true && me.dirty) {
+            if (silent !== true && didChange) {
                 me.afterEdit();
             }
         }
     },
     
+    /**
+     * Checks if the underlying data has changed during an edit. This doesn't necessarily
+     * mean the record is dirty, however we still need to notify the store since it may need
+     * to update any views.
+     * @private
+     * @return {Boolean} True if the underlying data has changed during an edit.
+     */
+    changedWhileEditing: function(){
+        var me = this,
+            saved = me.dataSave,
+            data = me[me.persistenceProperty],
+            key;
+            
+        for (key in data) {
+            if (data.hasOwnProperty(key)) {
+                if (!me.isEqual(data[key], saved[key])) {
+                    return true;
+                }
+            }
+        }
+        return false; 
+    },
+
     /**
      * Gets a hash of only the fields that have been modified since this Model was created or commited.
-     * @return Object
+     * @return {Object}
      */
     getChanges : function(){
         var modified = this.modified,
@@ -19798,30 +20259,27 @@ Ext.define('Ext.data.Model', {
 
         return changes;
     },
-    
+
     /**
-     * Returns <tt>true</tt> if the passed field name has been <code>{@link #modified}</code>
-     * since the load or last commit.
+     * Returns true if the passed field name has been `{@link #modified}` since the load or last commit.
      * @param {String} fieldName {@link Ext.data.Field#name}
      * @return {Boolean}
      */
     isModified : function(fieldName) {
         return this.modified.hasOwnProperty(fieldName);
     },
-    
+
     /**
-     * <p>Marks this <b>Record</b> as <code>{@link #dirty}</code>.  This method
-     * is used interally when adding <code>{@link #phantom}</code> records to a
-     * {@link Ext.data.Store#writer writer enabled store}.</p>
-     * <br><p>Marking a record <code>{@link #dirty}</code> causes the phantom to
-     * be returned by {@link Ext.data.Store#getModifiedRecords} where it will
-     * have a create action composed for it during {@link Ext.data.Store#save store save}
-     * operations.</p>
+     * Marks this **Record** as `{@link #dirty}`. This method is used interally when adding `{@link #phantom}` records
+     * to a {@link Ext.data.proxy.Server#writer writer enabled store}.
+     *
+     * Marking a record `{@link #dirty}` causes the phantom to be returned by {@link Ext.data.Store#getUpdatedRecords}
+     * where it will have a create action composed for it during {@link Ext.data.Model#save model save} operations.
      */
     setDirty : function() {
         var me = this,
             name;
-        
+
         me.dirty = true;
 
         me.fields.each(function(field) {
@@ -19840,15 +20298,17 @@ Ext.define('Ext.data.Model', {
         return this.setDirty.apply(this, arguments);
     },
     //</debug>
-    
+
     /**
-     * Usually called by the {@link Ext.data.Store} to which this model instance has been {@link #join joined}.
-     * Rejects all changes made to the model instance since either creation, or the last commit operation.
-     * Modified fields are reverted to their original values.
-     * <p>Developers should subscribe to the {@link Ext.data.Store#update} event
-     * to have their code notified of reject operations.</p>
-     * @param {Boolean} silent (optional) True to skip notification of the owning
-     * store of the change (defaults to false)
+     * Usually called by the {@link Ext.data.Store} to which this model instance has been {@link #join joined}. Rejects
+     * all changes made to the model instance since either creation, or the last commit operation. Modified fields are
+     * reverted to their original values.
+     *
+     * Developers should subscribe to the {@link Ext.data.Store#update} event to have their code notified of reject
+     * operations.
+     *
+     * @param {Boolean} silent (optional) True to skip notification of the owning store of the change.
+     * Defaults to false.
      */
     reject : function(silent) {
         var me = this,
@@ -19873,19 +20333,19 @@ Ext.define('Ext.data.Model', {
     },
 
     /**
-     * Usually called by the {@link Ext.data.Store} which owns the model instance.
-     * Commits all changes made to the instance since either creation or the last commit operation.
-     * <p>Developers should subscribe to the {@link Ext.data.Store#update} event
-     * to have their code notified of commit operations.</p>
-     * @param {Boolean} silent (optional) True to skip notification of the owning
-     * store of the change (defaults to false)
+     * Usually called by the {@link Ext.data.Store} which owns the model instance. Commits all changes made to the
+     * instance since either creation or the last commit operation.
+     *
+     * Developers should subscribe to the {@link Ext.data.Store#update} event to have their code notified of commit
+     * operations.
+     *
+     * @param {Boolean} silent (optional) True to skip notification of the owning store of the change.
+     * Defaults to false.
      */
     commit : function(silent) {
         var me = this;
-        
-        me.dirty = false;
-        me.editing = false;
 
+        me.phantom = me.dirty = me.editing = false;
         me.modified = {};
 
         if (silent !== true) {
@@ -19895,24 +20355,27 @@ Ext.define('Ext.data.Model', {
 
     /**
      * Creates a copy (clone) of this Model instance.
-     * @param {String} id (optional) A new id, defaults to the id
-     * of the instance being copied. See <code>{@link #id}</code>.
-     * To generate a phantom instance with a new id use:<pre><code>
-var rec = record.copy(); // clone the record
-Ext.data.Model.id(rec); // automatically generate a unique sequential id
-     * </code></pre>
-     * @return {Record}
+     *
+     * @param {String} [id] A new id, defaults to the id of the instance being copied.
+     * See `{@link Ext.data.Model#id id}`. To generate a phantom instance with a new id use:
+     *
+     *     var rec = record.copy(); // clone the record
+     *     Ext.data.Model.id(rec); // automatically generate a unique sequential id
+     *
+     * @return {Ext.data.Model}
      */
     copy : function(newId) {
         var me = this;
-        
+
         return new me.self(Ext.apply({}, me[me.persistenceProperty]), newId || me.internalId);
     },
 
     /**
-     * Sets the Proxy to use for this model. Accepts any options that can be accepted by {@link Ext#createByAlias Ext.createByAlias}
+     * Sets the Proxy to use for this model. Accepts any options that can be accepted by
+     * {@link Ext#createByAlias Ext.createByAlias}.
+     *
      * @param {String/Object/Ext.data.proxy.Proxy} proxy The proxy
-     * @static
+     * @return {Ext.data.proxy.Proxy}
      */
     setProxy: function(proxy) {
         //make sure we have an Ext.data.proxy.Proxy object
@@ -19931,7 +20394,7 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Returns the configured Proxy for this Model
+     * Returns the configured Proxy for this Model.
      * @return {Ext.data.proxy.Proxy} The proxy
      */
     getProxy: function() {
@@ -19939,8 +20402,7 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Validates the current data against all of its configured {@link #validations} and returns an
-     * {@link Ext.data.Errors Errors} object
+     * Validates the current data against all of its configured {@link #validations}.
      * @return {Ext.data.Errors} The errors object
      */
     validate: function() {
@@ -19979,8 +20441,8 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Saves the model instance using the configured proxy
-     * @param {Object} options Options to pass to the proxy
+     * Saves the model instance using the configured proxy.
+     * @param {Object} options Options to pass to the proxy. Config object for {@link Ext.data.Operation}.
      * @return {Ext.data.Model} The Model instance
      */
     save: function(options) {
@@ -20022,8 +20484,8 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Destroys the model using the configured proxy
-     * @param {Object} options Options to pass to the proxy
+     * Destroys the model using the configured proxy.
+     * @param {Object} options Options to pass to the proxy. Config object for {@link Ext.data.Operation}.
      * @return {Ext.data.Model} The Model instance
      */
     destroy: function(options){
@@ -20055,7 +20517,7 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Returns the unique ID allocated to this model instance as defined by {@link #idProperty}
+     * Returns the unique ID allocated to this model instance as defined by {@link #idProperty}.
      * @return {Number} The id
      */
     getId: function() {
@@ -20063,7 +20525,7 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Sets the model instance's id field to the given id
+     * Sets the model instance's id field to the given id.
      * @param {Number} id The new id
      */
     setId: function(id) {
@@ -20071,22 +20533,22 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Tells this model instance that it has been added to a store
-     * @param {Ext.data.Store} store The store that the model has been added to
+     * Tells this model instance that it has been added to a store.
+     * @param {Ext.data.Store} store The store to which this model has been added.
      */
     join : function(store) {
         /**
-         * The {@link Ext.data.Store} to which this Record belongs.
-         * @property store
-         * @type {Ext.data.Store}
+         * @property {Ext.data.Store} store
+         * The {@link Ext.data.Store Store} to which this Record belongs.
          */
         this.store = store;
     },
 
     /**
-     * Tells this model instance that it has been removed from the store
+     * Tells this model instance that it has been removed from the store.
+     * @param {Ext.data.Store} store The store from which this model has been removed.
      */
-    unjoin: function() {
+    unjoin: function(store) {
         delete this.store;
     },
 
@@ -20133,20 +20595,21 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
     },
 
     /**
-     * Gets all of the data from this Models *loaded* associations.
-     * It does this recursively - for example if we have a User which
-     * hasMany Orders, and each Order hasMany OrderItems, it will return an object like this:
-     * {
-     *     orders: [
-     *         {
-     *             id: 123,
-     *             status: 'shipped',
-     *             orderItems: [
-     *                 ...
-     *             ]
-     *         }
-     *     ]
-     * }
+     * Gets all of the data from this Models *loaded* associations. It does this recursively - for example if we have a
+     * User which hasMany Orders, and each Order hasMany OrderItems, it will return an object like this:
+     *
+     *     {
+     *         orders: [
+     *             {
+     *                 id: 123,
+     *                 status: 'shipped',
+     *                 orderItems: [
+     *                     ...
+     *                 ]
+     *             }
+     *         ]
+     *     }
+     *
      * @return {Object} The nested data set for the Model's loaded associations
      */
     getAssociatedData: function(){
@@ -20158,7 +20621,7 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
      * This complex-looking method takes a given Model instance and returns an object containing all data from
      * all of that Model's *loaded* associations. See (@link #getAssociatedData}
      * @param {Ext.data.Model} record The Model instance
-     * @param {Array} ids PRIVATE. The set of Model instance internalIds that have already been loaded
+     * @param {String[]} ids PRIVATE. The set of Model instance internalIds that have already been loaded
      * @param {String} associationType (optional) The name of the type of association to limit to.
      * @return {Object} The nested data set for the Model's loaded associations
      */
@@ -20224,127 +20687,278 @@ Ext.data.Model.id(rec); // automatically generate a unique sequential id
 });
 
 /**
- * @class Ext.Component
- * @extends Ext.AbstractComponent
- * <p>Base class for all Ext components.  All subclasses of Component may participate in the automated
- * Ext component lifecycle of creation, rendering and destruction which is provided by the {@link Ext.container.Container Container} class.
- * Components may be added to a Container through the {@link Ext.container.Container#items items} config option at the time the Container is created,
- * or they may be added dynamically via the {@link Ext.container.Container#add add} method.</p>
- * <p>The Component base class has built-in support for basic hide/show and enable/disable and size control behavior.</p>
- * <p>All Components are registered with the {@link Ext.ComponentManager} on construction so that they can be referenced at any time via
- * {@link Ext#getCmp Ext.getCmp}, passing the {@link #id}.</p>
- * <p>All user-developed visual widgets that are required to participate in automated lifecycle and size management should subclass Component.</p>
- * <p>See the <a href="http://sencha.com/learn/Tutorial:Creating_new_UI_controls">Creating new UI controls</a> tutorial for details on how
- * and to either extend or augment ExtJs base classes to create custom Components.</p>
- * <p>Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the
- * xtype like {@link #getXType} and {@link #isXType}. This is the list of all valid xtypes:</p>
- * <pre>
-xtype            Class
--------------    ------------------
-button           {@link Ext.button.Button}
-buttongroup      {@link Ext.container.ButtonGroup}
-colorpalette     {@link Ext.picker.Color}
-component        {@link Ext.Component}
-container        {@link Ext.container.Container}
-cycle            {@link Ext.button.Cycle}
-dataview         {@link Ext.view.View}
-datepicker       {@link Ext.picker.Date}
-editor           {@link Ext.Editor}
-editorgrid       {@link Ext.grid.plugin.Editing}
-grid             {@link Ext.grid.Panel}
-multislider      {@link Ext.slider.Multi}
-panel            {@link Ext.panel.Panel}
-progress         {@link Ext.ProgressBar}
-slider           {@link Ext.slider.Single}
-spacer           {@link Ext.toolbar.Spacer}
-splitbutton      {@link Ext.button.Split}
-tabpanel         {@link Ext.tab.Panel}
-treepanel        {@link Ext.tree.Panel}
-viewport         {@link Ext.container.Viewport}
-window           {@link Ext.window.Window}
-
-Toolbar components
----------------------------------------
-paging           {@link Ext.toolbar.Paging}
-toolbar          {@link Ext.toolbar.Toolbar}
-tbfill           {@link Ext.toolbar.Fill}
-tbitem           {@link Ext.toolbar.Item}
-tbseparator      {@link Ext.toolbar.Separator}
-tbspacer         {@link Ext.toolbar.Spacer}
-tbtext           {@link Ext.toolbar.TextItem}
-
-Menu components
----------------------------------------
-menu             {@link Ext.menu.Menu}
-menucheckitem    {@link Ext.menu.CheckItem}
-menuitem         {@link Ext.menu.Item}
-menuseparator    {@link Ext.menu.Separator}
-menutextitem     {@link Ext.menu.Item}
-
-Form components
----------------------------------------
-form             {@link Ext.form.Panel}
-checkbox         {@link Ext.form.field.Checkbox}
-combo            {@link Ext.form.field.ComboBox}
-datefield        {@link Ext.form.field.Date}
-displayfield     {@link Ext.form.field.Display}
-field            {@link Ext.form.field.Base}
-fieldset         {@link Ext.form.FieldSet}
-hidden           {@link Ext.form.field.Hidden}
-htmleditor       {@link Ext.form.field.HtmlEditor}
-label            {@link Ext.form.Label}
-numberfield      {@link Ext.form.field.Number}
-radio            {@link Ext.form.field.Radio}
-radiogroup       {@link Ext.form.RadioGroup}
-textarea         {@link Ext.form.field.TextArea}
-textfield        {@link Ext.form.field.Text}
-timefield        {@link Ext.form.field.Time}
-trigger          {@link Ext.form.field.Trigger}
-
-Chart components
----------------------------------------
-chart            {@link Ext.chart.Chart}
-barchart         {@link Ext.chart.series.Bar}
-columnchart      {@link Ext.chart.series.Column}
-linechart        {@link Ext.chart.series.Line}
-piechart         {@link Ext.chart.series.Pie}
-
-</pre><p>
- * It should not usually be necessary to instantiate a Component because there are provided subclasses which implement specialized Component
- * use cases which over most application needs. However it is possible to instantiate a base Component, and it will be renderable,
- * or will particpate in layouts as the child item of a Container:
-{@img Ext.Component/Ext.Component.png Ext.Component component}
-<pre><code>
-    Ext.create('Ext.Component', {
-        html: 'Hello world!',
-        width: 300,
-        height: 200,
-        padding: 20,
-        style: {
-            color: '#FFFFFF',
-            backgroundColor:'#000000'
-        },
-        renderTo: Ext.getBody()
-    });
-</code></pre>
- *</p>
- *<p>The Component above creates its encapsulating <code>div</code> upon render, and use the configured HTML as content. More complex
- * internal structure may be created using the {@link #renderTpl} configuration, although to display database-derived mass
- * data, it is recommended that an ExtJS data-backed Component such as a {@link Ext.view.View View}, or
- * {@link Ext.grid.Panel GridPanel}, or {@link Ext.tree.Panel TreePanel} be used.</p>
- * @constructor
- * Creates new Component.
- * @param {Ext.core.Element/String/Object} config The configuration options may be specified as either:
- * <div class="mdetail-params"><ul>
- * <li><b>an element</b> :
- * <p class="sub-desc">it is set as the internal element and its id used as the component id</p></li>
- * <li><b>a string</b> :
- * <p class="sub-desc">it is assumed to be the id of an existing element and is used as the component id</p></li>
- * <li><b>anything else</b> :
- * <p class="sub-desc">it is assumed to be a standard config object and is applied to the component</p></li>
- * </ul></div>
+ * @docauthor Evan Trimboli <evan@sencha.com>
+ *
+ * Contains a collection of all stores that are created that have an identifier. An identifier can be assigned by
+ * setting the {@link Ext.data.AbstractStore#storeId storeId} property. When a store is in the StoreManager, it can be
+ * referred to via it's identifier:
+ *
+ *     Ext.create('Ext.data.Store', {
+ *         model: 'SomeModel',
+ *         storeId: 'myStore'
+ *     });
+ *
+ *     var store = Ext.data.StoreManager.lookup('myStore');
+ *
+ * Also note that the {@link #lookup} method is aliased to {@link Ext#getStore} for convenience.
+ *
+ * If a store is registered with the StoreManager, you can also refer to the store by it's identifier when registering
+ * it with any Component that consumes data from a store:
+ *
+ *     Ext.create('Ext.data.Store', {
+ *         model: 'SomeModel',
+ *         storeId: 'myStore'
+ *     });
+ *
+ *     Ext.create('Ext.view.View', {
+ *         store: 'myStore',
+ *         // other configuration here
+ *     });
+ *
  */
+Ext.define('Ext.data.StoreManager', {
+    extend: 'Ext.util.MixedCollection',
+    alternateClassName: ['Ext.StoreMgr', 'Ext.data.StoreMgr', 'Ext.StoreManager'],
+    singleton: true,
+    uses: ['Ext.data.ArrayStore'],
+    
+    /**
+     * @cfg {Object} listeners @hide
+     */
+
+    /**
+     * Registers one or more Stores with the StoreManager. You do not normally need to register stores manually. Any
+     * store initialized with a {@link Ext.data.Store#storeId} will be auto-registered.
+     * @param {Ext.data.Store...} stores Any number of Store instances
+     */
+    register : function() {
+        for (var i = 0, s; (s = arguments[i]); i++) {
+            this.add(s);
+        }
+    },
 
+    /**
+     * Unregisters one or more Stores with the StoreManager
+     * @param {String/Object...} stores Any number of Store instances or ID-s
+     */
+    unregister : function() {
+        for (var i = 0, s; (s = arguments[i]); i++) {
+            this.remove(this.lookup(s));
+        }
+    },
+
+    /**
+     * Gets a registered Store by id
+     * @param {String/Object} store The id of the Store, or a Store instance, or a store configuration
+     * @return {Ext.data.Store}
+     */
+    lookup : function(store) {
+        // handle the case when we are given an array or an array of arrays.
+        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 Ext.create('Ext.data.ArrayStore', {
+                data  : data,
+                fields: fields,
+                autoDestroy: true,
+                autoCreated: true,
+                expanded: expand
+            });
+        }
+        
+        if (Ext.isString(store)) {
+            // store id
+            return this.get(store);
+        } else {
+            // store instance or store config
+            return Ext.data.AbstractStore.create(store);
+        }
+    },
+
+    // getKey implementation for MixedCollection
+    getKey : function(o) {
+         return o.storeId;
+    }
+}, function() {    
+    /**
+     * Creates a new store for the given id and config, then registers it with the {@link Ext.data.StoreManager Store Mananger}. 
+     * Sample usage:
+     *
+     *     Ext.regStore('AllUsers', {
+     *         model: 'User'
+     *     });
+     *
+     *     // the store can now easily be used throughout the application
+     *     new Ext.List({
+     *         store: 'AllUsers',
+     *         ... other config
+     *     });
+     *
+     * @param {String} id The id to set on the new store
+     * @param {Object} config The store config
+     * @member Ext
+     * @method regStore
+     */
+    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 = Ext.create('Ext.data.Store', config);
+        }
+
+        return Ext.data.StoreManager.register(store);
+    };
+
+    /**
+     * Shortcut to {@link Ext.data.StoreManager#lookup}.
+     * @member Ext
+     * @method getStore
+     * @alias Ext.data.StoreManager#lookup
+     */
+    Ext.getStore = function(name) {
+        return Ext.data.StoreManager.lookup(name);
+    };
+});
+
+/**
+ * Base class for all Ext components. All subclasses of Component may participate in the automated Ext component
+ * lifecycle of creation, rendering and destruction which is provided by the {@link Ext.container.Container Container}
+ * class. Components may be added to a Container through the {@link Ext.container.Container#items items} config option
+ * at the time the Container is created, or they may be added dynamically via the
+ * {@link Ext.container.Container#add add} method.
+ *
+ * The Component base class has built-in support for basic hide/show and enable/disable and size control behavior.
+ *
+ * All Components are registered with the {@link Ext.ComponentManager} on construction so that they can be referenced at
+ * any time via {@link Ext#getCmp Ext.getCmp}, passing the {@link #id}.
+ *
+ * All user-developed visual widgets that are required to participate in automated lifecycle and size management should
+ * subclass Component.
+ *
+ * See the [Creating new UI controls][1] tutorial for details on how and to either extend or augment ExtJs base classes
+ * to create custom Components.
+ *
+ * Every component has a specific xtype, which is its Ext-specific type name, along with methods for checking the xtype
+ * like {@link #getXType} and {@link #isXType}. See the [Component Guide][2] for more information on xtypes and the
+ * Component hierarchy.
+ *
+ * This is the list of all valid xtypes:
+ *
+ *     xtype            Class
+ *     -------------    ------------------
+ *     button           {@link Ext.button.Button}
+ *     buttongroup      {@link Ext.container.ButtonGroup}
+ *     colorpalette     {@link Ext.picker.Color}
+ *     component        {@link Ext.Component}
+ *     container        {@link Ext.container.Container}
+ *     cycle            {@link Ext.button.Cycle}
+ *     dataview         {@link Ext.view.View}
+ *     datepicker       {@link Ext.picker.Date}
+ *     editor           {@link Ext.Editor}
+ *     editorgrid       {@link Ext.grid.plugin.Editing}
+ *     grid             {@link Ext.grid.Panel}
+ *     multislider      {@link Ext.slider.Multi}
+ *     panel            {@link Ext.panel.Panel}
+ *     progressbar      {@link Ext.ProgressBar}
+ *     slider           {@link Ext.slider.Single}
+ *     splitbutton      {@link Ext.button.Split}
+ *     tabpanel         {@link Ext.tab.Panel}
+ *     treepanel        {@link Ext.tree.Panel}
+ *     viewport         {@link Ext.container.Viewport}
+ *     window           {@link Ext.window.Window}
+ *
+ *     Toolbar components
+ *     ---------------------------------------
+ *     pagingtoolbar    {@link Ext.toolbar.Paging}
+ *     toolbar          {@link Ext.toolbar.Toolbar}
+ *     tbfill           {@link Ext.toolbar.Fill}
+ *     tbitem           {@link Ext.toolbar.Item}
+ *     tbseparator      {@link Ext.toolbar.Separator}
+ *     tbspacer         {@link Ext.toolbar.Spacer}
+ *     tbtext           {@link Ext.toolbar.TextItem}
+ *
+ *     Menu components
+ *     ---------------------------------------
+ *     menu             {@link Ext.menu.Menu}
+ *     menucheckitem    {@link Ext.menu.CheckItem}
+ *     menuitem         {@link Ext.menu.Item}
+ *     menuseparator    {@link Ext.menu.Separator}
+ *     menutextitem     {@link Ext.menu.Item}
+ *
+ *     Form components
+ *     ---------------------------------------
+ *     form             {@link Ext.form.Panel}
+ *     checkbox         {@link Ext.form.field.Checkbox}
+ *     combo            {@link Ext.form.field.ComboBox}
+ *     datefield        {@link Ext.form.field.Date}
+ *     displayfield     {@link Ext.form.field.Display}
+ *     field            {@link Ext.form.field.Base}
+ *     fieldset         {@link Ext.form.FieldSet}
+ *     hidden           {@link Ext.form.field.Hidden}
+ *     htmleditor       {@link Ext.form.field.HtmlEditor}
+ *     label            {@link Ext.form.Label}
+ *     numberfield      {@link Ext.form.field.Number}
+ *     radio            {@link Ext.form.field.Radio}
+ *     radiogroup       {@link Ext.form.RadioGroup}
+ *     textarea         {@link Ext.form.field.TextArea}
+ *     textfield        {@link Ext.form.field.Text}
+ *     timefield        {@link Ext.form.field.Time}
+ *     trigger          {@link Ext.form.field.Trigger}
+ *
+ *     Chart components
+ *     ---------------------------------------
+ *     chart            {@link Ext.chart.Chart}
+ *     barchart         {@link Ext.chart.series.Bar}
+ *     columnchart      {@link Ext.chart.series.Column}
+ *     linechart        {@link Ext.chart.series.Line}
+ *     piechart         {@link Ext.chart.series.Pie}
+ *
+ * It should not usually be necessary to instantiate a Component because there are provided subclasses which implement
+ * specialized Component use cases which cover most application needs. However it is possible to instantiate a base
+ * Component, and it will be renderable, or will particpate in layouts as the child item of a Container:
+ *
+ *     @example
+ *     Ext.create('Ext.Component', {
+ *         html: 'Hello world!',
+ *         width: 300,
+ *         height: 200,
+ *         padding: 20,
+ *         style: {
+ *             color: '#FFFFFF',
+ *             backgroundColor:'#000000'
+ *         },
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ * The Component above creates its encapsulating `div` upon render, and use the configured HTML as content. More complex
+ * internal structure may be created using the {@link #renderTpl} configuration, although to display database-derived
+ * mass data, it is recommended that an ExtJS data-backed Component such as a {@link Ext.view.View View}, or {@link
+ * Ext.grid.Panel GridPanel}, or {@link Ext.tree.Panel TreePanel} be used.
+ *
+ * [1]: http://sencha.com/learn/Tutorial:Creating_new_UI_controls
+ */
 Ext.define('Ext.Component', {
 
     /* Begin Definitions */
@@ -20374,119 +20988,150 @@ Ext.define('Ext.Component', {
         DIRECTION_BOTTOM: 'bottom',
         DIRECTION_LEFT: 'left',
 
-        VERTICAL_DIRECTION: /^(?:top|bottom)$/
+        VERTICAL_DIRECTION_Re: /^(?:top|bottom)$/,
+
+        // RegExp whih specifies characters in an xtype which must be translated to '-' when generating auto IDs.
+        // This includes dot, comma and whitespace
+        INVALID_ID_CHARS_Re: /[\.,\s]/g
     },
 
     /* End Definitions */
 
     /**
-     * @cfg {Mixed} resizable
-     * <p>Specify as <code>true</code> to apply a {@link Ext.resizer.Resizer Resizer} to this Component
-     * after rendering.</p>
-     * <p>May also be specified as a config object to be passed to the constructor of {@link Ext.resizer.Resizer Resizer}
+     * @cfg {Boolean/Object} resizable
+     * Specify as `true` to apply a {@link Ext.resizer.Resizer Resizer} to this Component after rendering.
+     *
+     * May also be specified as a config object to be passed to the constructor of {@link Ext.resizer.Resizer Resizer}
      * to override any defaults. By default the Component passes its minimum and maximum size, and uses
-     * <code>{@link Ext.resizer.Resizer#dynamic}: false</code></p>
+     * `{@link Ext.resizer.Resizer#dynamic}: false`
      */
 
     /**
      * @cfg {String} resizeHandles
-     * A valid {@link Ext.resizer.Resizer} handles config string (defaults to 'all').  Only applies when resizable = true.
+     * A valid {@link Ext.resizer.Resizer} handles config string. Only applies when resizable = true.
      */
     resizeHandles: 'all',
 
     /**
-     * @cfg {Boolean} autoScroll
-     * <code>true</code> to use overflow:'auto' on the components layout element and show scroll bars automatically when
-     * necessary, <code>false</code> to clip any overflowing content (defaults to <code>false</code>).
+     * @cfg {Boolean} [autoScroll=false]
+     * `true` to use overflow:'auto' on the components layout element and show scroll bars automatically when necessary,
+     * `false` to clip any overflowing content.
      */
 
     /**
      * @cfg {Boolean} floating
-     * <p>Specify as true to float the Component outside of the document flow using CSS absolute positioning.</p>
-     * <p>Components such as {@link Ext.window.Window Window}s and {@link Ext.menu.Menu Menu}s are floating
-     * by default.</p>
-     * <p>Floating Components that are programatically {@link Ext.Component#render rendered} will register themselves with the global
-     * {@link Ext.WindowManager ZIndexManager}</p>
-     * <h3 class="pa">Floating Components as child items of a Container</h3>
-     * <p>A floating Component may be used as a child item of a Container. This just allows the floating Component to seek a ZIndexManager by
-     * examining the ownerCt chain.</p>
-     * <p>When configured as floating, Components acquire, at render time, a {@link Ext.ZIndexManager ZIndexManager} which manages a stack
-     * of related floating Components. The ZIndexManager brings a single floating Component to the top of its stack when
-     * the Component's {@link #toFront} method is called.</p>
-     * <p>The ZIndexManager is found by traversing up the {@link #ownerCt} chain to find an ancestor which itself is floating. This is so that
-     * descendant floating Components of floating <i>Containers</i> (Such as a ComboBox dropdown within a Window) can have its zIndex managed relative
-     * to any siblings, but always <b>above</b> that floating ancestor Container.</p>
-     * <p>If no floating ancestor is found, a floating Component registers itself with the default {@link Ext.WindowManager ZIndexManager}.</p>
-     * <p>Floating components <i>do not participate in the Container's layout</i>. Because of this, they are not rendered until you explicitly
-     * {@link #show} them.</p>
-     * <p>After rendering, the ownerCt reference is deleted, and the {@link #floatParent} property is set to the found floating ancestor Container.
-     * If no floating ancestor Container was found the {@link #floatParent} property will not be set.</p>
+     * Specify as true to float the Component outside of the document flow using CSS absolute positioning.
+     *
+     * Components such as {@link Ext.window.Window Window}s and {@link Ext.menu.Menu Menu}s are floating by default.
+     *
+     * Floating Components that are programatically {@link Ext.Component#render rendered} will register themselves with
+     * the global {@link Ext.WindowManager ZIndexManager}
+     *
+     * ### Floating Components as child items of a Container
+     *
+     * A floating Component may be used as a child item of a Container. This just allows the floating Component to seek
+     * a ZIndexManager by examining the ownerCt chain.
+     *
+     * When configured as floating, Components acquire, at render time, a {@link Ext.ZIndexManager ZIndexManager} which
+     * manages a stack of related floating Components. The ZIndexManager brings a single floating Component to the top
+     * of its stack when the Component's {@link #toFront} method is called.
+     *
+     * The ZIndexManager is found by traversing up the {@link #ownerCt} chain to find an ancestor which itself is
+     * floating. This is so that descendant floating Components of floating _Containers_ (Such as a ComboBox dropdown
+     * within a Window) can have its zIndex managed relative to any siblings, but always **above** that floating
+     * ancestor Container.
+     *
+     * If no floating ancestor is found, a floating Component registers itself with the default {@link Ext.WindowManager
+     * ZIndexManager}.
+     *
+     * Floating components _do not participate in the Container's layout_. Because of this, they are not rendered until
+     * you explicitly {@link #show} them.
+     *
+     * After rendering, the ownerCt reference is deleted, and the {@link #floatParent} property is set to the found
+     * floating ancestor Container. If no floating ancestor Container was found the {@link #floatParent} property will
+     * not be set.
      */
     floating: false,
 
     /**
      * @cfg {Boolean} toFrontOnShow
-     * <p>True to automatically call {@link #toFront} when the {@link #show} method is called
-     * on an already visible, floating component (default is <code>true</code>).</p>
+     * True to automatically call {@link #toFront} when the {@link #show} method is called on an already visible,
+     * floating component.
      */
     toFrontOnShow: true,
 
     /**
-     * <p>Optional. Only present for {@link #floating} Components after they have been rendered.</p>
-     * <p>A reference to the ZIndexManager which is managing this Component's z-index.</p>
-     * <p>The {@link Ext.ZIndexManager ZIndexManager} maintains a stack of floating Component z-indices, and also provides a single modal
-     * mask which is insert just beneath the topmost visible modal floating Component.</p>
-     * <p>Floating Components may be {@link #toFront brought to the front} or {@link #toBack sent to the back} of the z-index stack.</p>
-     * <p>This defaults to the global {@link Ext.WindowManager ZIndexManager} for floating Components that are programatically
-     * {@link Ext.Component#render rendered}.</p>
-     * <p>For {@link #floating} Components which are added to a Container, the ZIndexManager is acquired from the first ancestor Container found
-     * which is floating, or if not found the global {@link Ext.WindowManager ZIndexManager} is used.</p>
-     * <p>See {@link #floating} and {@link #floatParent}</p>
-     * @property zIndexManager
-     * @type Ext.ZIndexManager
+     * @property {Ext.ZIndexManager} zIndexManager
+     * Only present for {@link #floating} Components after they have been rendered.
+     *
+     * A reference to the ZIndexManager which is managing this Component's z-index.
+     *
+     * The {@link Ext.ZIndexManager ZIndexManager} maintains a stack of floating Component z-indices, and also provides
+     * a single modal mask which is insert just beneath the topmost visible modal floating Component.
+     *
+     * Floating Components may be {@link #toFront brought to the front} or {@link #toBack sent to the back} of the
+     * z-index stack.
+     *
+     * This defaults to the global {@link Ext.WindowManager ZIndexManager} for floating Components that are
+     * programatically {@link Ext.Component#render rendered}.
+     *
+     * For {@link #floating} Components which are added to a Container, the ZIndexManager is acquired from the first
+     * ancestor Container found which is floating, or if not found the global {@link Ext.WindowManager ZIndexManager} is
+     * used.
+     *
+     * See {@link #floating} and {@link #floatParent}
      */
 
-     /**
-      * <p>Optional. Only present for {@link #floating} Components which were inserted as descendant items of floating Containers.</p>
-      * <p>Floating Components that are programatically {@link Ext.Component#render rendered} will not have a <code>floatParent</code> property.</p>
-      * <p>For {@link #floating} Components which are child items of a Container, the floatParent will be the floating ancestor Container which is
-      * responsible for the base z-index value of all its floating descendants. It provides a {@link Ext.ZIndexManager ZIndexManager} which provides
-      * z-indexing services for all its descendant floating Components.</p>
-      * <p>For example, the dropdown {@link Ext.view.BoundList BoundList} of a ComboBox which is in a Window will have the Window as its
-      * <code>floatParent</code></p>
-      * <p>See {@link #floating} and {@link #zIndexManager}</p>
-      * @property floatParent
-      * @type Ext.Container
-      */
+    /**
+     * @property {Ext.Container} floatParent
+     * Only present for {@link #floating} Components which were inserted as descendant items of floating Containers.
+     *
+     * Floating Components that are programatically {@link Ext.Component#render rendered} will not have a `floatParent`
+     * property.
+     *
+     * For {@link #floating} Components which are child items of a Container, the floatParent will be the floating
+     * ancestor Container which is responsible for the base z-index value of all its floating descendants. It provides
+     * a {@link Ext.ZIndexManager ZIndexManager} which provides z-indexing services for all its descendant floating
+     * Components.
+     *
+     * For example, the dropdown {@link Ext.view.BoundList BoundList} of a ComboBox which is in a Window will have the
+     * Window as its `floatParent`
+     *
+     * See {@link #floating} and {@link #zIndexManager}
+     */
 
     /**
-     * @cfg {Mixed} draggable
-     * <p>Specify as true to make a {@link #floating} Component draggable using the Component's encapsulating element as the drag handle.</p>
-     * <p>This may also be specified as a config object for the {@link Ext.util.ComponentDragger ComponentDragger} which is instantiated to perform dragging.</p>
-     * <p>For example to create a Component which may only be dragged around using a certain internal element as the drag handle,
-     * use the delegate option:</p>
-     * <code><pre>
-new Ext.Component({
-    constrain: true,
-    floating:true,
-    style: {
-        backgroundColor: '#fff',
-        border: '1px solid black'
-    },
-    html: '&lt;h1 style="cursor:move"&gt;The title&lt;/h1&gt;&lt;p&gt;The content&lt;/p&gt;',
-    draggable: {
-        delegate: 'h1'
-    }
-}).show();
-</pre></code>
+     * @cfg {Boolean/Object} [draggable=false]
+     * Specify as true to make a {@link #floating} Component draggable using the Component's encapsulating element as
+     * the drag handle.
+     *
+     * This may also be specified as a config object for the {@link Ext.util.ComponentDragger ComponentDragger} which is
+     * instantiated to perform dragging.
+     *
+     * For example to create a Component which may only be dragged around using a certain internal element as the drag
+     * handle, use the delegate option:
+     *
+     *     new Ext.Component({
+     *         constrain: true,
+     *         floating: true,
+     *         style: {
+     *             backgroundColor: '#fff',
+     *             border: '1px solid black'
+     *         },
+     *         html: '<h1 style="cursor:move">The title</h1><p>The content</p>',
+     *         draggable: {
+     *             delegate: 'h1'
+     *         }
+     *     }).show();
      */
 
     /**
-     * @cfg {Boolean} maintainFlex
-     * <p><b>Only valid when a sibling element of a {@link Ext.resizer.Splitter Splitter} within a {@link Ext.layout.container.VBox VBox} or
-     * {@link Ext.layout.container.HBox HBox} layout.</b></p>
-     * <p>Specifies that if an immediate sibling Splitter is moved, the Component on the <i>other</i> side is resized, and this
-     * Component maintains its configured {@link Ext.layout.container.Box#flex flex} value.</p>
+     * @cfg {Boolean} [maintainFlex=false]
+     * **Only valid when a sibling element of a {@link Ext.resizer.Splitter Splitter} within a
+     * {@link Ext.layout.container.VBox VBox} or {@link Ext.layout.container.HBox HBox} layout.**
+     *
+     * Specifies that if an immediate sibling Splitter is moved, the Component on the *other* side is resized, and this
+     * Component maintains its configured {@link Ext.layout.container.Box#flex flex} value.
      */
 
     hideMode: 'display',
@@ -20506,13 +21151,24 @@ new Ext.Component({
     //        disableFormats: true
     //    }
     //),
+
+    /**
+     * Creates new Component.
+     * @param {Ext.Element/String/Object} config The configuration options may be specified as either:
+     *
+     * - **an element** : it is set as the internal element and its id used as the component id
+     * - **a string** : it is assumed to be the id of an existing element and is used as the component id
+     * - **anything else** : it is assumed to be a standard config object and is applied to the component
+     */
     constructor: function(config) {
+        var me = this;
+
         config = config || {};
         if (config.initialConfig) {
 
             // Being initialized from an Ext.Action instance...
             if (config.isAction) {
-                this.baseAction = config;
+                me.baseAction = config;
             }
             config = config.initialConfig;
             // component cloning / action set up
@@ -20525,18 +21181,49 @@ new Ext.Component({
             };
         }
 
-        this.callParent([config]);
+        me.callParent([config]);
 
         // If we were configured from an instance of Ext.Action, (or configured with a baseAction option),
         // register this Component as one of its items
-        if (this.baseAction){
-            this.baseAction.addComponent(this);
+        if (me.baseAction){
+            me.baseAction.addComponent(me);
         }
     },
 
+    /**
+     * The initComponent template method is an important initialization step for a Component. It is intended to be
+     * implemented by each subclass of Ext.Component to provide any needed constructor logic. The
+     * initComponent method of the class being created is called first, with each initComponent method
+     * up the hierarchy to Ext.Component being called thereafter. This makes it easy to implement and,
+     * if needed, override the constructor logic of the Component at any step in the hierarchy.
+     *
+     * The initComponent method **must** contain a call to {@link Ext.Base#callParent callParent} in order
+     * to ensure that the parent class' initComponent method is also called.
+     *
+     * The following example demonstrates using a dynamic string for the text of a button at the time of
+     * instantiation of the class.
+     *
+     *     Ext.define('DynamicButtonText', {
+     *         extend: 'Ext.button.Button',
+     *
+     *         initComponent: function() {
+     *             this.text = new Date();
+     *             this.renderTo = Ext.getBody();
+     *             this.callParent();
+     *         }
+     *     });
+     *
+     *     Ext.onReady(function() {
+     *         Ext.create('DynamicButtonText');
+     *     });
+     *
+     * @template
+     */
     initComponent: function() {
         var me = this;
 
+        me.callParent();
+
         if (me.listeners) {
             me.on(me.listeners);
             delete me.listeners;
@@ -20553,7 +21240,7 @@ new Ext.Component({
         if (me.floating) {
             me.makeFloating(me.floating);
         } else {
-            me.el.setVisibilityMode(Ext.core.Element[me.hideMode.toUpperCase()]);
+            me.el.setVisibilityMode(Ext.Element[me.hideMode.toUpperCase()]);
         }
 
         if (Ext.isDefined(me.autoScroll)) {
@@ -20612,14 +21299,16 @@ new Ext.Component({
     },
 
     initResizable: function(resizable) {
+        var me = this;
+
         resizable = Ext.apply({
-            target: this,
+            target: me,
             dynamic: false,
-            constrainTo: this.constrainTo,
-            handles: this.resizeHandles
+            constrainTo: me.constrainTo || (me.floatParent ? me.floatParent.getTargetEl() : me.el.getScopeParent()),
+            handles: me.resizeHandles
         }, resizable);
-        resizable.target = this;
-        this.resizer = Ext.create('Ext.resizer.Resizer', resizable);
+        resizable.target = me;
+        me.resizer = Ext.create('Ext.resizer.Resizer', resizable);
     },
 
     getDragEl: function() {
@@ -20629,9 +21318,9 @@ new Ext.Component({
     initDraggable: function() {
         var me = this,
             ddConfig = Ext.applyIf({
-                el: this.getDragEl(),
-                constrainTo: me.constrainTo || (me.floatParent ? me.floatParent.getTargetEl() : me.el.dom.parentNode)
-            }, this.draggable);
+                el: me.getDragEl(),
+                constrainTo: me.constrain ? (me.constrainTo || (me.floatParent ? me.floatParent.getTargetEl() : me.el.getScopeParent())) : undefined
+            }, me.draggable);
 
         // Add extra configs if Component is specified to be constrained
         if (me.constrain || me.constrainDelegate) {
@@ -20639,15 +21328,16 @@ new Ext.Component({
             ddConfig.constrainDelegate = me.constrainDelegate;
         }
 
-        this.dd = Ext.create('Ext.util.ComponentDragger', this, ddConfig);
+        me.dd = Ext.create('Ext.util.ComponentDragger', me, ddConfig);
     },
 
     /**
-     * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
-     * This method fires the {@link #move} event.
+     * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}. This
+     * method fires the {@link #move} event.
      * @param {Number} left The new left
      * @param {Number} top The new top
-     * @param {Mixed} animate If true, the Component is <i>animated</i> into its new position. You may also pass an animation configuration.
+     * @param {Boolean/Object} [animate] If true, the Component is _animated_ into its new position. You may also pass an
+     * animation configuration.
      * @return {Ext.Component} this
      */
     setPosition: function(x, y, animate) {
@@ -20709,30 +21399,60 @@ new Ext.Component({
     },
 
     /**
-     * @private Template method called after a Component has been positioned.
+     * @private
+     * @template
+     * Template method called after a Component has been positioned.
      */
     afterSetPosition: function(ax, ay) {
         this.onPosition(ax, ay);
         this.fireEvent('move', this, ax, ay);
     },
 
+    /**
+     * Displays component at specific xy position.
+     * A floating component (like a menu) is positioned relative to its ownerCt if any.
+     * Useful for popping up a context menu:
+     *
+     *     listeners: {
+     *         itemcontextmenu: function(view, record, item, index, event, options) {
+     *             Ext.create('Ext.menu.Menu', {
+     *                 width: 100,
+     *                 height: 100,
+     *                 margin: '0 0 10 0',
+     *                 items: [{
+     *                     text: 'regular item 1'
+     *                 },{
+     *                     text: 'regular item 2'
+     *                 },{
+     *                     text: 'regular item 3'
+     *                 }]
+     *             }).showAt(event.getXY());
+     *         }
+     *     }
+     *
+     * @param {Number} x The new x position
+     * @param {Number} y The new y position
+     * @param {Boolean/Object} [animate] True to animate the Component into its new position. You may also pass an
+     * animation configuration.
+     */
     showAt: function(x, y, animate) {
-        // A floating Component is positioned relative to its ownerCt if any.
-        if (this.floating) {
-            this.setPosition(x, y, animate);
+        var me = this;
+
+        if (me.floating) {
+            me.setPosition(x, y, animate);
         } else {
-            this.setPagePosition(x, y, animate);
+            me.setPagePosition(x, y, animate);
         }
-        this.show();
+        me.show();
     },
 
     /**
-     * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
+     * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
      * This method fires the {@link #move} event.
      * @param {Number} x The new x position
      * @param {Number} y The new y position
-     * @param {Mixed} animate If passed, the Component is <i>animated</i> into its new position. If this parameter
-     * is a number, it is used as the animation duration in milliseconds.
+     * @param {Boolean/Object} [animate] True to animate the Component into its new position. You may also pass an
+     * animation configuration.
      * @return {Ext.Component} this
      */
     setPagePosition: function(x, y, animate) {
@@ -20765,15 +21485,16 @@ new Ext.Component({
 
     /**
      * Gets the current box measurements of the component's underlying element.
-     * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
+     * @param {Boolean} [local=false] If true the element's left and top are returned instead of page XY.
      * @return {Object} box An object in the format {x, y, width, height}
      */
     getBox : function(local){
-        var pos = this.getPosition(local);
-        var s = this.getSize();
-        s.x = pos[0];
-        s.y = pos[1];
-        return s;
+        var pos = this.getPosition(local),
+            size = this.getSize();
+
+        size.x = pos[0];
+        size.y = pos[1];
+        return size;
     },
 
     /**
@@ -20796,22 +21517,6 @@ new Ext.Component({
         };
     },
 
-    // private
-    adjustSize: function(w, h) {
-        if (this.autoWidth) {
-            w = 'auto';
-        }
-
-        if (this.autoHeight) {
-            h = 'auto';
-        }
-
-        return {
-            width: w,
-            height: h
-        };
-    },
-
     // private
     adjustPosition: function(x, y) {
 
@@ -20830,30 +21535,40 @@ new Ext.Component({
 
     /**
      * Gets the current XY position of the component's underlying element.
-     * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
-     * @return {Array} The XY position of the element (e.g., [100, 200])
+     * @param {Boolean} [local=false] If true the element's left and top are returned instead of page XY.
+     * @return {Number[]} The XY position of the element (e.g., [100, 200])
      */
     getPosition: function(local) {
-        var el = this.el,
-            xy;
+        var me = this,
+            el = me.el,
+            xy,
+            o;
 
-        if (local === true) {
+        // Floating Components which were just rendered with no ownerCt return local position.
+        if ((local === true) || (me.floating && !me.floatParent)) {
             return [el.getLeft(true), el.getTop(true)];
         }
-        xy = this.xy || el.getXY();
+        xy = me.xy || el.getXY();
 
         // Floating Components in an ownerCt have to have their positions made relative
-        if (this.floating && this.floatParent) {
-            var o = this.floatParent.getTargetEl().getViewRegion();
+        if (me.floating) {
+            o = me.floatParent.getTargetEl().getViewRegion();
             xy[0] -= o.left;
             xy[1] -= o.top;
         }
         return xy;
     },
 
-    // Todo: add in xtype prefix support
     getId: function() {
-        return this.id || (this.id = (this.getXType() || 'ext-comp') + '-' + this.getAutoId());
+        var me = this,
+            xtype;
+
+        if (!me.id) {
+            xtype = me.getXType();
+            xtype = xtype ? xtype.replace(Ext.Component.INVALID_ID_CHARS_Re, '-') : 'ext-comp';
+            me.id = xtype + '-' + me.getAutoId();
+        }
+        return me.id;
     },
 
     onEnable: function() {
@@ -20871,42 +21586,47 @@ new Ext.Component({
     },
 
     /**
-     * <p>Shows this Component, rendering it first if {@link #autoRender} or {@link #floating} are <code>true</code>.</p>
-     * <p>After being shown, a {@link #floating} Component (such as a {@link Ext.window.Window}), is activated it and brought to the front of
-     * its {@link #zIndexManager z-index stack}.</p>
-     * @param {String/Element} animateTarget Optional, and <b>only valid for {@link #floating} Components such as
-     * {@link Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have been configured
-     * with <code>floating: true</code>.</b> The target from which the Component should
-     * animate from while opening (defaults to null with no animation)
-     * @param {Function} callback (optional) A callback function to call after the Component is displayed. Only necessary if animation was specified.
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Component.
-     * @return {Component} this
+     * Shows this Component, rendering it first if {@link #autoRender} or {@link #floating} are `true`.
+     *
+     * After being shown, a {@link #floating} Component (such as a {@link Ext.window.Window}), is activated it and
+     * brought to the front of its {@link #zIndexManager z-index stack}.
+     *
+     * @param {String/Ext.Element} [animateTarget=null] **only valid for {@link #floating} Components such as {@link
+     * Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have been configured
+     * with `floating: true`.** The target from which the Component should animate from while opening.
+     * @param {Function} [callback] A callback function to call after the Component is displayed.
+     * Only necessary if animation was specified.
+     * @param {Object} [scope] The scope (`this` reference) in which the callback is executed.
+     * Defaults to this Component.
+     * @return {Ext.Component} this
      */
     show: function(animateTarget, cb, scope) {
-        if (this.rendered && this.isVisible()) {
-            if (this.toFrontOnShow && this.floating) {
-                this.toFront();
+        var me = this;
+
+        if (me.rendered && me.isVisible()) {
+            if (me.toFrontOnShow && me.floating) {
+                me.toFront();
             }
-        } else if (this.fireEvent('beforeshow', this) !== false) {
-            this.hidden = false;
+        } else if (me.fireEvent('beforeshow', me) !== false) {
+            me.hidden = false;
 
             // Render on first show if there is an autoRender config, or if this is a floater (Window, Menu, BoundList etc).
-            if (!this.rendered && (this.autoRender || this.floating)) {
-                this.doAutoRender();
+            if (!me.rendered && (me.autoRender || me.floating)) {
+                me.doAutoRender();
             }
-            if (this.rendered) {
-                this.beforeShow();
-                this.onShow.apply(this, arguments);
+            if (me.rendered) {
+                me.beforeShow();
+                me.onShow.apply(me, arguments);
 
                 // Notify any owning Container unless it's suspended.
                 // Floating Components do not participate in layouts.
-                if (this.ownerCt && !this.floating && !(this.ownerCt.suspendLayout || this.ownerCt.layout.layoutBusy)) {
-                    this.ownerCt.doLayout();
+                if (me.ownerCt && !me.floating && !(me.ownerCt.suspendLayout || me.ownerCt.layout.layoutBusy)) {
+                    me.ownerCt.doLayout();
                 }
-                this.afterShow.apply(this, arguments);
+                me.afterShow.apply(me, arguments);
             }
         }
-        return this;
+        return me;
     },
 
     beforeShow: Ext.emptyFn,
@@ -20916,10 +21636,10 @@ new Ext.Component({
         var me = this;
 
         me.el.show();
-        if (this.floating && this.constrain) {
-            this.doConstrain();
-        }
         me.callParent(arguments);
+        if (me.floating && me.constrain) {
+            me.doConstrain();
+        }
     },
 
     afterShow: function(animateTarget, cb, scope) {
@@ -20940,14 +21660,13 @@ new Ext.Component({
             animateTarget = animateTarget.el ? animateTarget.el : Ext.get(animateTarget);
             toBox = me.el.getBox();
             fromBox = animateTarget.getBox();
-            fromBox.width += 'px';
-            fromBox.height += 'px';
-            toBox.width += 'px';
-            toBox.height += 'px';
             me.el.addCls(Ext.baseCSSPrefix + 'hide-offsets');
             ghostPanel = me.ghost();
             ghostPanel.el.stopAnimation();
 
+            // Shunting it offscreen immediately, *before* the Animation class grabs it ensure no flicker.
+            ghostPanel.el.setX(-10000);
+
             ghostPanel.el.animate({
                 from: fromBox,
                 to: toBox,
@@ -20956,52 +21675,55 @@ new Ext.Component({
                         delete ghostPanel.componentLayout.lastComponentSize;
                         me.unghost();
                         me.el.removeCls(Ext.baseCSSPrefix + 'hide-offsets');
-                        if (me.floating) {
-                            me.toFront();
-                        }
-                        Ext.callback(cb, scope || me);
+                        me.onShowComplete(cb, scope);
                     }
                 }
             });
         }
         else {
-            if (me.floating) {
-                me.toFront();
-            }
-            Ext.callback(cb, scope || me);
+            me.onShowComplete(cb, scope);
+        }
+    },
+
+    onShowComplete: function(cb, scope) {
+        var me = this;
+        if (me.floating) {
+            me.toFront();
         }
+        Ext.callback(cb, scope || me);
         me.fireEvent('show', me);
     },
 
     /**
      * Hides this Component, setting it to invisible using the configured {@link #hideMode}.
-     * @param {String/Element/Component} animateTarget Optional, and <b>only valid for {@link #floating} Components such as
-     * {@link Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have been configured
-     * with <code>floating: true</code>.</b>.
-     * The target to which the Component should animate while hiding (defaults to null with no animation)
-     * @param {Function} callback (optional) A callback function to call after the Component is hidden.
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to this Component.
+     * @param {String/Ext.Element/Ext.Component} [animateTarget=null] **only valid for {@link #floating} Components
+     * such as {@link Ext.window.Window Window}s or {@link Ext.tip.ToolTip ToolTip}s, or regular Components which have
+     * been configured with `floating: true`.**. The target to which the Component should animate while hiding.
+     * @param {Function} [callback] A callback function to call after the Component is hidden.
+     * @param {Object} [scope] The scope (`this` reference) in which the callback is executed.
+     * Defaults to this Component.
      * @return {Ext.Component} this
      */
     hide: function() {
+        var me = this;
 
         // Clear the flag which is set if a floatParent was hidden while this is visible.
         // If a hide operation was subsequently called, that pending show must be hidden.
-        this.showOnParentShow = false;
+        me.showOnParentShow = false;
 
-        if (!(this.rendered && !this.isVisible()) && this.fireEvent('beforehide', this) !== false) {
-            this.hidden = true;
-            if (this.rendered) {
-                this.onHide.apply(this, arguments);
+        if (!(me.rendered && !me.isVisible()) && me.fireEvent('beforehide', me) !== false) {
+            me.hidden = true;
+            if (me.rendered) {
+                me.onHide.apply(me, arguments);
 
                 // Notify any owning Container unless it's suspended.
                 // Floating Components do not participate in layouts.
-                if (this.ownerCt && !this.floating && !(this.ownerCt.suspendLayout || this.ownerCt.layout.layoutBusy)) {
-                    this.ownerCt.doLayout();
+                if (me.ownerCt && !me.floating && !(me.ownerCt.suspendLayout || me.ownerCt.layout.layoutBusy)) {
+                    me.ownerCt.doLayout();
                 }
             }
         }
-        return this;
+        return me;
     },
 
     // Possibly animate down to a target element.
@@ -21049,6 +21771,7 @@ new Ext.Component({
 
     /**
      * @private
+     * @template
      * Template method to contribute functionality at destroy time.
      */
     onDestroy: function() {
@@ -21058,6 +21781,7 @@ new Ext.Component({
         if (me.rendered) {
             Ext.destroy(
                 me.proxy,
+                me.proxyWrap,
                 me.resizer
             );
             // Different from AbstractComponent
@@ -21080,8 +21804,8 @@ new Ext.Component({
 
     /**
      * Try to focus this component.
-     * @param {Boolean} selectText (optional) If applicable, true to also select the text in this component
-     * @param {Boolean/Number} delay (optional) Delay the focus this number of milliseconds (true for 10 milliseconds).
+     * @param {Boolean} [selectText] If applicable, true to also select the text in this component
+     * @param {Boolean/Number} [delay] Delay the focus this number of milliseconds (true for 10 milliseconds).
      * @return {Ext.Component} this
      */
     focus: function(selectText, delay) {
@@ -21118,7 +21842,7 @@ new Ext.Component({
      * Returns the focus holder element associated with this Component. By default, this is the Component's encapsulating
      * element. Subclasses which use embedded focusable elements (such as Window and Button) should override this for use
      * by the {@link #focus} method.
-     * @returns {Ext.core.Element} the focus holing element.
+     * @returns {Ext.Element} the focus holing element.
      */
     getFocusEl: function() {
         return this.el;
@@ -21177,23 +21901,25 @@ new Ext.Component({
      */
     cloneConfig: function(overrides) {
         overrides = overrides || {};
-        var id = overrides.id || Ext.id();
-        var cfg = Ext.applyIf(overrides, this.initialConfig);
+        var id = overrides.id || Ext.id(),
+            cfg = Ext.applyIf(overrides, this.initialConfig),
+            self;
+
         cfg.id = id;
 
-        var self = Ext.getClass(this);
+        self = Ext.getClass(this);
 
         // prevent dup id
         return new self(cfg);
     },
 
     /**
-     * Gets the xtype for this component as registered with {@link Ext.ComponentManager}. For a list of all
-     * available xtypes, see the {@link Ext.Component} header. Example usage:
-     * <pre><code>
-var t = new Ext.form.field.Text();
-alert(t.getXType());  // alerts 'textfield'
-</code></pre>
+     * Gets the xtype for this component as registered with {@link Ext.ComponentManager}. For a list of all available
+     * xtypes, see the {@link Ext.Component} header. Example usage:
+     *
+     *     var t = new Ext.form.field.Text();
+     *     alert(t.getXType());  // alerts 'textfield'
+     *
      * @return {String} The xtype
      */
     getXType: function() {
@@ -21201,8 +21927,8 @@ alert(t.getXType());  // alerts 'textfield'
     },
 
     /**
-     * Find a container above this component at any level by a custom function. If the passed function returns
-     * true, the container will be returned.
+     * Find a container above this component at any level by a custom function. If the passed function returns true, the
+     * container will be returned.
      * @param {Function} fn The custom function to call with the arguments (container, this component).
      * @return {Ext.container.Container} The first Container for which the custom function returns true
      */
@@ -21215,9 +21941,11 @@ alert(t.getXType());  // alerts 'textfield'
     },
 
     /**
-     * <p>Find a container above this component at any level by xtype or class</p>
-     * <p>See also the {@link Ext.Component#up up} method.</p>
-     * @param {String/Class} xtype The xtype string for a component, or the class of the component directly
+     * Find a container above this component at any level by xtype or class
+     *
+     * See also the {@link Ext.Component#up up} method.
+     *
+     * @param {String/Ext.Class} xtype The xtype string for a component, or the class of the component directly
      * @return {Ext.container.Container} The first Container which matches the given xtype or class
      */
     findParentByType: function(xtype) {
@@ -21230,13 +21958,13 @@ alert(t.getXType());  // alerts 'textfield'
     },
 
     /**
-     * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current component. The arguments to the function
-     * will be the args provided or the current component. If the function returns false at any point,
-     * the bubble is stopped.
+     * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope
+     * (*this*) of function call will be the scope provided or the current component. The arguments to the function will
+     * be the args provided or the current component. If the function returns false at any point, the bubble is stopped.
+     *
      * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current component)
+     * @param {Object} [scope] The scope of the function. Defaults to current node.
+     * @param {Array} [args] The args to call the function with. Defaults to passing the current component.
      * @return {Ext.Component} this
      */
     bubble: function(fn, scope, args) {
@@ -21251,19 +21979,112 @@ alert(t.getXType());  // alerts 'textfield'
     },
 
     getProxy: function() {
-        if (!this.proxy) {
-            this.proxy = this.el.createProxy(Ext.baseCSSPrefix + 'proxy-el', Ext.getBody(), true);
+        var me = this,
+            target;
+
+        if (!me.proxy) {
+            target = Ext.getBody();
+            if (Ext.scopeResetCSS) {
+                me.proxyWrap = target = Ext.getBody().createChild({
+                    cls: Ext.baseCSSPrefix + 'reset'
+                });
+            }
+            me.proxy = me.el.createProxy(Ext.baseCSSPrefix + 'proxy-el', target, true);
         }
-        return this.proxy;
+        return me.proxy;
     }
 
 });
 
+/**
+ * @class Ext.layout.container.AbstractContainer
+ * @extends Ext.layout.Layout
+ * Please refer to sub classes documentation
+ * @private
+ */
+Ext.define('Ext.layout.container.AbstractContainer', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.layout.Layout',
+
+    /* End Definitions */
+
+    type: 'container',
+
+    /**
+     * @cfg {Boolean} bindToOwnerCtComponent
+     * Flag to notify the ownerCt Component on afterLayout of a change
+     */
+    bindToOwnerCtComponent: false,
+
+    /**
+     * @cfg {Boolean} bindToOwnerCtContainer
+     * Flag to notify the ownerCt Container on afterLayout of a change
+     */
+    bindToOwnerCtContainer: false,
+
+    /**
+     * @cfg {String} itemCls
+     * <p>An optional extra CSS class that will be added to the container. This can be useful for adding
+     * customized styles to the container or any of its children using standard CSS rules. See
+     * {@link Ext.Component}.{@link Ext.Component#componentCls componentCls} also.</p>
+     * </p>
+     */
+
+    /**
+    * Set the size of an item within the Container.  We should always use setCalculatedSize.
+    * @private
+    */
+    setItemSize: function(item, width, height) {
+        if (Ext.isObject(width)) {
+            height = width.height;
+            width = width.width;
+        }
+        item.setCalculatedSize(width, height, this.owner);
+    },
+
+    /**
+     * <p>Returns an array of child components either for a render phase (Performed in the beforeLayout method of the layout's
+     * base class), or the layout phase (onLayout).</p>
+     * @return {Ext.Component[]} of child components
+     */
+    getLayoutItems: function() {
+        return this.owner && this.owner.items && this.owner.items.items || [];
+    },
+
+    /**
+     * Containers should not lay out child components when collapsed.
+     */
+    beforeLayout: function() {
+        return !this.owner.collapsed && this.callParent(arguments);
+    },
+
+    afterLayout: function() {
+        this.owner.afterLayout(this);
+    },
+    /**
+     * Returns the owner component's resize element.
+     * @return {Ext.Element}
+     */
+     getTarget: function() {
+         return this.owner.getTargetEl();
+     },
+    /**
+     * <p>Returns the element into which rendering must take place. Defaults to the owner Container's target element.</p>
+     * May be overridden in layout managers which implement an inner element.
+     * @return {Ext.Element}
+     */
+     getRenderTarget: function() {
+         return this.owner.getTargetEl();
+     }
+});
+
 /**
 * @class Ext.layout.container.Container
 * @extends Ext.layout.container.AbstractContainer
-* <p>This class is intended to be extended or created via the <tt><b>{@link Ext.container.Container#layout layout}</b></tt>
-* configuration property.  See <tt><b>{@link Ext.container.Container#layout}</b></tt> for additional details.</p>
+* <p>This class is intended to be extended or created via the {@link Ext.container.Container#layout layout}
+* configuration property.  See {@link Ext.container.Container#layout} for additional details.</p>
 */
 Ext.define('Ext.layout.container.Container', {
 
@@ -21271,14 +22092,14 @@ Ext.define('Ext.layout.container.Container', {
 
     extend: 'Ext.layout.container.AbstractContainer',
     alternateClassName: 'Ext.layout.ContainerLayout',
-    
+
     /* End Definitions */
 
     layoutItem: function(item, box) {
-        box = box || {};
-        if (item.componentLayout.initialized !== true) {
-            this.setItemSize(item, box.width || item.width || undefined, box.height || item.height || undefined);
-            // item.doComponentLayout(box.width || item.width || undefined, box.height || item.height || undefined);
+        if (box) {
+            item.doComponentLayout(box.width, box.height);
+        } else {
+            item.doComponentLayout();
         }
     },
 
@@ -21360,32 +22181,32 @@ Ext.define('Ext.layout.container.Container', {
  * @class Ext.layout.container.Auto
  * @extends Ext.layout.container.Container
  *
- * <p>The AutoLayout is the default layout manager delegated by {@link Ext.container.Container} to
- * render any child Components when no <tt>{@link Ext.container.Container#layout layout}</tt> is configured into
- * a <tt>{@link Ext.container.Container Container}.</tt>.  AutoLayout provides only a passthrough of any layout calls
- * to any child containers.</p>
- * {@img Ext.layout.container.Auto/Ext.layout.container.Auto.png Ext.layout.container.Auto container layout}
- * Example usage:
-       Ext.create('Ext.Panel', {
-               width: 500,
-               height: 280,
-               title: "AutoLayout Panel",
-               layout: 'auto',
-               renderTo: document.body,
-               items: [{
-                       xtype: 'panel',
-                       title: 'Top Inner Panel',
-                       width: '75%',
-                       height: 90
-               },{
-                       xtype: 'panel',
-                       title: 'Bottom Inner Panel',
-                       width: '75%',
-                       height: 90
-               }]
-       });
+ * The AutoLayout is the default layout manager delegated by {@link Ext.container.Container} to
+ * render any child Components when no `{@link Ext.container.Container#layout layout}` is configured into
+ * a `{@link Ext.container.Container Container}.` AutoLayout provides only a passthrough of any layout calls
+ * to any child containers.
+ *
+ *     @example
+ *     Ext.create('Ext.Panel', {
+ *         width: 500,
+ *         height: 280,
+ *         title: "AutoLayout Panel",
+ *         layout: 'auto',
+ *         renderTo: document.body,
+ *         items: [{
+ *             xtype: 'panel',
+ *             title: 'Top Inner Panel',
+ *             width: '75%',
+ *             height: 90
+ *         },
+ *         {
+ *             xtype: 'panel',
+ *             title: 'Bottom Inner Panel',
+ *             width: '75%',
+ *             height: 90
+ *         }]
+ *     });
  */
-
 Ext.define('Ext.layout.container.Auto', {
 
     /* Begin Definitions */
@@ -21427,22 +22248,18 @@ Ext.define('Ext.layout.container.Auto', {
     },
 
     configureItem: function(item) {
+        this.callParent(arguments);
 
         // Auto layout does not manage any dimensions.
-        // We have to check our type, because this could be called as a superclass method in a subclass
-        if (this.type === 'autocontainer') {
-            item.layoutManagedHeight = 2;
-            item.layoutManagedWidth = 2;
-        }
-
-        this.callParent(arguments);
+        item.layoutManagedHeight = 2;
+        item.layoutManagedWidth = 2;
     }
 });
 /**
  * @class Ext.container.AbstractContainer
  * @extends Ext.Component
- * <p>An abstract base class which provides shared methods for Containers across the Sencha product line.</p>
- * Please refer to sub class's documentation
+ * An abstract base class which provides shared methods for Containers across the Sencha product line.
+ * @private
  */
 Ext.define('Ext.container.AbstractContainer', {
 
@@ -21459,10 +22276,10 @@ Ext.define('Ext.container.AbstractContainer', {
     /* End Definitions */
     /**
      * @cfg {String/Object} layout
-     * <p><b>*Important</b>: In order for child items to be correctly sized and
+     * <p><b>Important</b>: In order for child items to be correctly sized and
      * positioned, typically a layout manager <b>must</b> be specified through
      * the <code>layout</code> configuration option.</p>
-     * <br><p>The sizing and positioning of child {@link #items} is the responsibility of
+     * <p>The sizing and positioning of child {@link #items} is the responsibility of
      * the Container's layout manager which creates and manages the type of layout
      * you have in mind.  For example:</p>
      * <p>If the {@link #layout} configuration is not explicitly specified for
@@ -21470,9 +22287,8 @@ Ext.define('Ext.container.AbstractContainer', {
      * {@link Ext.layout.container.Auto default layout manager} will be used
      * which does nothing but render child components sequentially into the
      * Container (no sizing or positioning will be performed in this situation).</p>
-     * <br><p><b><code>layout</code></b> may be specified as either as an Object or
-     * as a String:</p><div><ul class="mdetail-params">
-     *
+     * <p><b><code>layout</code></b> may be specified as either as an Object or as a String:</p>
+     * <div><ul class="mdetail-params">
      * <li><u>Specify as an Object</u></li>
      * <div><ul class="mdetail-params">
      * <li>Example usage:</li>
@@ -21486,7 +22302,7 @@ layout: {
      * <li><code><b>type</b></code></li>
      * <br/><p>The layout type to be used for this container.  If not specified,
      * a default {@link Ext.layout.container.Auto} will be created and used.</p>
-     * <br/><p>Valid layout <code>type</code> values are:</p>
+     * <p>Valid layout <code>type</code> values are:</p>
      * <div class="sub-desc"><ul class="mdetail-params">
      * <li><code><b>{@link Ext.layout.container.Auto Auto}</b></code> &nbsp;&nbsp;&nbsp; <b>Default</b></li>
      * <li><code><b>{@link Ext.layout.container.Card card}</b></code></li>
@@ -21498,7 +22314,7 @@ layout: {
      * </ul></div>
      *
      * <li>Layout specific configuration properties</li>
-     * <br/><p>Additional layout specific configuration properties may also be
+     * <p>Additional layout specific configuration properties may also be
      * specified. For complete details regarding the valid config options for
      * each layout type, see the layout class corresponding to the <code>type</code>
      * specified.</p>
@@ -21509,16 +22325,12 @@ layout: {
      * <div><ul class="mdetail-params">
      * <li>Example usage:</li>
      * <pre><code>
-layout: {
-    type: 'vbox',
-    padding: '5',
-    align: 'left'
-}
+layout: 'vbox'
        </code></pre>
      * <li><code><b>layout</b></code></li>
-     * <br/><p>The layout <code>type</code> to be used for this container (see list
-     * of valid layout type values above).</p><br/>
-     * <br/><p>Additional layout specific configuration properties. For complete
+     * <p>The layout <code>type</code> to be used for this container (see list
+     * of valid layout type values above).</p>
+     * <p>Additional layout specific configuration properties. For complete
      * details regarding the valid config options for each layout type, see the
      * layout class corresponding to the <code>layout</code> specified.</p>
      * </ul></div></ul></div>
@@ -21532,7 +22344,7 @@ layout: {
      * items one at a time (like {@link Ext.layout.container.Card} and {@link Ext.layout.container.Fit}).
      */
     /**
-     * @cfg {Object/Array} items
+     * @cfg {Object/Object[]} items
      * <p>A single item, or an array of child Components to be added to this container</p>
      * <p><b>Unless configured with a {@link #layout}, a Container simply renders child Components serially into
      * its encapsulating element and performs no sizing or positioning upon them.</b><p>
@@ -21560,36 +22372,41 @@ layout: 'hbox', // The items are arranged horizontally
      * <p>Ext uses lazy rendering. Child Components will only be rendered
      * should it become necessary. Items are automatically laid out when they are first
      * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</p>
-     * <p>Do not specify <code>{@link Ext.panel.Panel#contentEl contentEl}</code> or 
+     * <p>Do not specify <code>{@link Ext.panel.Panel#contentEl contentEl}</code> or
      * <code>{@link Ext.panel.Panel#html html}</code> with <code>items</code>.</p>
      */
     /**
-     * @cfg {Object|Function} defaults
-     * <p>This option is a means of applying default settings to all added items whether added through the {@link #items}
-     * config or via the {@link #add} or {@link #insert} methods.</p>
-     * <p>If an added item is a config object, and <b>not</b> an instantiated Component, then the default properties are
-     * unconditionally applied. If the added item <b>is</b> an instantiated Component, then the default properties are
-     * applied conditionally so as not to override existing properties in the item.</p>
-     * <p>If the defaults option is specified as a function, then the function will be called using this Container as the
-     * scope (<code>this</code> reference) and passing the added item as the first parameter. Any resulting object
-     * from that call is then applied to the item as default properties.</p>
-     * <p>For example, to automatically apply padding to the body of each of a set of
-     * contained {@link Ext.panel.Panel} items, you could pass: <code>defaults: {bodyStyle:'padding:15px'}</code>.</p>
-     * <p>Usage:</p><pre><code>
-defaults: {               // defaults are applied to items, not the container
-    autoScroll:true
-},
-items: [
-    {
-        xtype: 'panel',   // defaults <b>do not</b> have precedence over
-        id: 'panel1',     // options in config objects, so the defaults
-        autoScroll: false // will not be applied here, panel1 will be autoScroll:false
-    },
-    new Ext.panel.Panel({       // defaults <b>do</b> have precedence over options
-        id: 'panel2',     // options in components, so the defaults
-        autoScroll: false // will be applied here, panel2 will be autoScroll:true.
-    })
-]</code></pre>
+     * @cfg {Object/Function} defaults
+     * This option is a means of applying default settings to all added items whether added through the {@link #items}
+     * config or via the {@link #add} or {@link #insert} methods.
+     *
+     * Defaults are applied to both config objects and instantiated components conditionally so as not to override
+     * existing properties in the item (see {@link Ext#applyIf}).
+     *
+     * If the defaults option is specified as a function, then the function will be called using this Container as the
+     * scope (`this` reference) and passing the added item as the first parameter. Any resulting object
+     * from that call is then applied to the item as default properties.
+     *
+     * For example, to automatically apply padding to the body of each of a set of
+     * contained {@link Ext.panel.Panel} items, you could pass: `defaults: {bodyStyle:'padding:15px'}`.
+     *
+     * Usage:
+     *
+     *     defaults: { // defaults are applied to items, not the container
+     *         autoScroll: true
+     *     },
+     *     items: [
+     *         // default will not be applied here, panel1 will be autoScroll: false
+     *         {
+     *             xtype: 'panel',
+     *             id: 'panel1',
+     *             autoScroll: false
+     *         },
+     *         // this component will have autoScroll: true
+     *         new Ext.panel.Panel({
+     *             id: 'panel2'
+     *         })
+     *     ]
      */
 
     /** @cfg {Boolean} suspendLayout
@@ -21614,16 +22431,24 @@ items: [
 
     isContainer : true,
 
+    /**
+     * The number of container layout calls made on this object.
+     * @property layoutCounter
+     * @type {Number}
+     * @private
+     */
+    layoutCounter : 0,
+
     baseCls: Ext.baseCSSPrefix + 'container',
 
     /**
-     * @cfg {Array} bubbleEvents
+     * @cfg {String[]} bubbleEvents
      * <p>An array of events that, when fired, should be bubbled to any parent container.
      * See {@link Ext.util.Observable#enableBubble}.
      * Defaults to <code>['add', 'remove']</code>.
      */
     bubbleEvents: ['add', 'remove'],
-    
+
     // @private
     initComponent : function(){
         var me = this;
@@ -21632,7 +22457,7 @@ items: [
              * @event afterlayout
              * Fires when the components in this container are arranged by the associated layout manager.
              * @param {Ext.container.Container} this
-             * @param {ContainerLayout} layout The ContainerLayout implementation for this container
+             * @param {Ext.layout.container.Container} layout The ContainerLayout implementation for this container
              */
             'afterlayout',
             /**
@@ -21668,35 +22493,7 @@ items: [
              * @param {Ext.container.Container} this
              * @param {Ext.Component} component The component that was removed
              */
-            'remove',
-            /**
-             * @event beforecardswitch
-             * Fires before this container switches the active card. This event
-             * is only available if this container uses a CardLayout. Note that
-             * TabPanel and Carousel both get a CardLayout by default, so both
-             * will have this event.
-             * A handler can return false to cancel the card switch.
-             * @param {Ext.container.Container} this
-             * @param {Ext.Component} newCard The card that will be switched to
-             * @param {Ext.Component} oldCard The card that will be switched from
-             * @param {Number} index The index of the card that will be switched to
-             * @param {Boolean} animated True if this cardswitch will be animated
-             */
-            'beforecardswitch',
-            /**
-             * @event cardswitch
-             * Fires after this container switches the active card. If the card
-             * is switched using an animation, this event will fire after the
-             * animation has finished. This event is only available if this container
-             * uses a CardLayout. Note that TabPanel and Carousel both get a CardLayout
-             * by default, so both will have this event.
-             * @param {Ext.container.Container} this
-             * @param {Ext.Component} newCard The card that has been switched to
-             * @param {Ext.Component} oldCard The card that has been switched from
-             * @param {Number} index The index of the card that has been switched to
-             * @param {Boolean} animated True if this cardswitch was animated
-             */
-            'cardswitch'
+            'remove'
         );
 
         // layoutOnShow stack
@@ -21732,6 +22529,20 @@ items: [
         this.callParent();
     },
 
+    renderChildren: function () {
+        var me = this,
+            layout = me.getLayout();
+
+        me.callParent();
+        // this component's elements exist, so now create the child components' elements
+
+        if (layout) {
+            me.suspendLayout = true;
+            layout.renderChildren();
+            delete me.suspendLayout;
+        }
+    },
+
     // @private
     setLayout : function(layout) {
         var currentLayout = this.layout;
@@ -21759,7 +22570,7 @@ items: [
     },
 
     /**
-     * Manually force this container's layout to be recalculated.  The framwork uses this internally to refresh layouts
+     * Manually force this container's layout to be recalculated. The framework uses this internally to refresh layouts
      * form most cases.
      * @return {Ext.container.Container} this
      */
@@ -21792,6 +22603,7 @@ items: [
 
     // @private
     afterLayout : function(layout) {
+        ++this.layoutCounter;
         this.fireEvent('afterlayout', this, layout);
     },
 
@@ -21827,12 +22639,8 @@ items: [
 
             if (Ext.isString(config)) {
                 config = Ext.ComponentManager.get(config);
-                Ext.applyIf(config, defaults);
-            } else if (!config.isComponent) {
-                Ext.applyIf(config, defaults);
-            } else {
-                Ext.applyIf(config, defaults);
             }
+            Ext.applyIf(config, defaults);
         }
 
         return config;
@@ -21888,17 +22696,17 @@ If adding multiple new child Components, pass them as an array to the `add` meth
     });  // toolbar is rendered
     tb.add([{text:'Button 1'}, {text:'Button 2'}]); // add multiple items. ({@link #defaultType} for {@link Ext.toolbar.Toolbar Toolbar} is 'button')
 
-##Warning:## 
+##Warning:##
 
 Components directly managed by the BorderLayout layout manager
 may not be removed or added.  See the Notes for {@link Ext.layout.container.Border BorderLayout}
 for more details.
 
-     * @param {...Object/Array} Component
+     * @param {Ext.Component[]/Ext.Component...} component
      * Either one or more Components to add or an Array of Components to add.
      * See `{@link #items}` for additional information.
      *
-     * @return {Ext.Component/Array} The Components that were added.
+     * @return {Ext.Component[]/Ext.Component} The Components that were added.
      * @markdown
      */
     add : function() {
@@ -21925,13 +22733,13 @@ for more details.
             me.suspendLayout = true;
             for (i = 0, ln = items.length; i < ln; i++) {
                 item = items[i];
-                
+
                 //<debug>
                 if (!item) {
                     Ext.Error.raise("Trying to add a null item as a child of Container with itemId/id: " + me.getItemId());
                 }
                 //</debug>
-                
+
                 if (index != -1) {
                     item = me.add(index + i, item);
                 } else {
@@ -21965,22 +22773,6 @@ for more details.
         return cmp;
     },
 
-    /**
-     * @private
-     * <p>Called by Component#doAutoRender</p>
-     * <p>Register a Container configured <code>floating: true</code> with this Container's {@link Ext.ZIndexManager ZIndexManager}.</p>
-     * <p>Components added in ths way will not participate in the layout, but will be rendered
-     * upon first show in the way that {@link Ext.window.Window Window}s are.</p>
-     * <p></p>
-     */
-    registerFloatingItem: function(cmp) {
-        var me = this;
-        if (!me.floatingItems) {
-            me.floatingItems = Ext.create('Ext.ZIndexManager', me);
-        }
-        me.floatingItems.register(cmp);
-    },
-
     onAdd : Ext.emptyFn,
     onRemove : Ext.emptyFn,
 
@@ -22027,7 +22819,7 @@ for more details.
     // @private
     onBeforeAdd : function(item) {
         var me = this;
-        
+
         if (item.ownerCt) {
             item.ownerCt.remove(item, false);
         }
@@ -22040,7 +22832,7 @@ for more details.
     /**
      * Removes a component from this container.  Fires the {@link #beforeremove} event before removing, then fires
      * the {@link #remove} event after the component has been removed.
-     * @param {Component/String} component The component reference or id to remove.
+     * @param {Ext.Component/String} component The component reference or id to remove.
      * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
      * Defaults to the value of this Container's {@link #autoDestroy} config.
      * @return {Ext.Component} component The Component that was removed.
@@ -22094,7 +22886,7 @@ for more details.
      * Removes all components from this container.
      * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
      * Defaults to the value of this Container's {@link #autoDestroy} config.
-     * @return {Array} Array of the destroyed components
+     * @return {Ext.Component[]} Array of the destroyed components
      */
     removeAll : function(autoDestroy) {
         var me = this,
@@ -22163,8 +22955,8 @@ for more details.
      * will be the args provided or the current component. If the function returns false at any point,
      * the cascade is stopped on that branch.
      * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current component)
-     * @param {Array} args (optional) The args to call the function with. The current component always passed as the last argument.
+     * @param {Object} [scope] The scope of the function (defaults to current component)
+     * @param {Array} [args] The args to call the function with. The current component always passed as the last argument.
      * @return {Ext.Container} this
      */
     cascade : function(fn, scope, origArgs){
@@ -22214,27 +23006,32 @@ for more details.
     /**
      * Retrieves all descendant components which match the passed selector.
      * Executes an Ext.ComponentQuery.query using this container as its root.
-     * @param {String} selector Selector complying to an Ext.ComponentQuery selector
-     * @return {Array} Ext.Component's which matched the selector
+     * @param {String} selector (optional) Selector complying to an Ext.ComponentQuery selector.
+     * If no selector is specified all items will be returned.
+     * @return {Ext.Component[]} Components which matched the selector
      */
     query : function(selector) {
+        selector = selector || '*';
         return Ext.ComponentQuery.query(selector, this);
     },
 
     /**
      * Retrieves the first direct child of this container which matches the passed selector.
      * The passed in selector must comply with an Ext.ComponentQuery selector.
-     * @param {String} selector An Ext.ComponentQuery selector
+     * @param {String} selector (optional) An Ext.ComponentQuery selector. If no selector is
+     * specified, the first child will be returned.
      * @return Ext.Component
      */
     child : function(selector) {
+        selector = selector || '';
         return this.query('> ' + selector)[0] || null;
     },
 
     /**
      * Retrieves the first descendant of this container which matches the passed selector.
      * The passed in selector must comply with an Ext.ComponentQuery selector.
-     * @param {String} selector An Ext.ComponentQuery selector
+     * @param {String} selector (optional) An Ext.ComponentQuery selector. If no selector is
+     * specified, the first child will be returned.
      * @return Ext.Component
      */
     down : function(selector) {
@@ -22266,20 +23063,20 @@ for more details.
             }
         }
         layoutCollection.clear();
-    },    
-    
+    },
+
     //@private
     // Enable all immediate children that was previously disabled
     onEnable: function() {
         Ext.Array.each(this.query('[isFormField]'), function(item) {
             if (item.resetDisable) {
                 item.enable();
-                delete item.resetDisable;             
+                delete item.resetDisable;
             }
         });
         this.callParent();
     },
-    
+
     // @private
     // Disable all immediate children that was previously disabled
     onDisable: function() {
@@ -22313,165 +23110,157 @@ for more details.
         }
 
         Ext.destroy(
-            me.layout,
-            me.floatingItems
+            me.layout
         );
         me.callParent();
     }
 });
-/**
- * @class Ext.container.Container
- * @extends Ext.container.AbstractContainer
- * <p>Base class for any {@link Ext.Component} that may contain other Components. Containers handle the
- * basic behavior of containing items, namely adding, inserting and removing items.</p>
- *
- * <p>The most commonly used Container classes are {@link Ext.panel.Panel}, {@link Ext.window.Window} and {@link Ext.tab.Panel}.
- * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
- * Container to be encapsulated by an HTML element to your specifications by using the
- * <code><b>{@link Ext.Component#autoEl autoEl}</b></code> config option.</p>
- *
- * {@img Ext.Container/Ext.Container.png Ext.Container component} 
- * <p>The code below illustrates how to explicitly create a Container:<pre><code>
-// explicitly create a Container
-Ext.create('Ext.container.Container', {
-    layout: {
-        type: 'hbox'
-    },
-    width: 400,
-    renderTo: Ext.getBody(),
-    border: 1,
-    style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
-    defaults: {
-        labelWidth: 80,
-        // implicitly create Container by specifying xtype
-        xtype: 'datefield',
-        flex: 1,
-        style: {
-            padding: '10px'
-        }
-    },
-    items: [{
-        xtype: 'datefield',
-        name: 'startDate',
-        fieldLabel: 'Start date'
-    },{
-        xtype: 'datefield',
-        name: 'endDate',
-        fieldLabel: 'End date'
-    }]
-});
-</code></pre></p>
- *
- * <p><u><b>Layout</b></u></p>
- * <p>Container classes delegate the rendering of child Components to a layout
- * manager class which must be configured into the Container using the
- * <code><b>{@link #layout}</b></code> configuration property.</p>
- * <p>When either specifying child <code>{@link #items}</code> of a Container,
- * or dynamically {@link #add adding} Components to a Container, remember to
- * consider how you wish the Container to arrange those child elements, and
- * whether those child elements need to be sized using one of Ext's built-in
- * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the
- * {@link Ext.layout.container.Auto Auto} scheme which only
- * renders child components, appending them one after the other inside the
- * Container, and <b>does not apply any sizing</b> at all.</p>
- * <p>A common mistake is when a developer neglects to specify a
- * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
- * TreePanels are added to Containers for which no <code><b>{@link #layout}</b></code>
- * has been specified). If a Container is left to use the default
- * {Ext.layout.container.Auto Auto} scheme, none of its
- * child components will be resized, or changed in any way when the Container
- * is resized.</p>
- * <p>Certain layout managers allow dynamic addition of child components.
- * Those that do include {@link Ext.layout.container.Card},
- * {@link Ext.layout.container.Anchor}, {@link Ext.layout.container.VBox}, {@link Ext.layout.container.HBox}, and
- * {@link Ext.layout.container.Table}. For example:<pre><code>
-//  Create the GridPanel.
-var myNewGrid = new Ext.grid.Panel({
-    store: myStore,
-    headers: myHeaders,
-    title: 'Results', // the title becomes the title of the tab
-});
 
-myTabPanel.add(myNewGrid); // {@link Ext.tab.Panel} implicitly uses {@link Ext.layout.container.Card Card}
-myTabPanel.{@link Ext.tab.Panel#setActiveTab setActiveTab}(myNewGrid);
- * </code></pre></p>
- * <p>The example above adds a newly created GridPanel to a TabPanel. Note that
- * a TabPanel uses {@link Ext.layout.container.Card} as its layout manager which
- * means all its child items are sized to {@link Ext.layout.container.Fit fit}
- * exactly into its client area.
- * <p><b><u>Overnesting is a common problem</u></b>.
- * An example of overnesting occurs when a GridPanel is added to a TabPanel
- * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
- * <code><b>{@link #layout}</b></code> specified) and then add that wrapping Panel
- * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
- * Component which can be added directly to a Container. If the wrapping Panel
- * has no <code><b>{@link #layout}</b></code> configuration, then the overnested
- * GridPanel will not be sized as expected.<p>
- *
- * <p><u><b>Adding via remote configuration</b></u></p>
- *
- * <p>A server side script can be used to add Components which are generated dynamically on the server.
- * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
- * based on certain parameters:
- * </p><pre><code>
-// execute an Ajax request to invoke server side script:
-Ext.Ajax.request({
-    url: 'gen-invoice-grid.php',
-    // send additional parameters to instruct server script
-    params: {
-        startDate: Ext.getCmp('start-date').getValue(),
-        endDate: Ext.getCmp('end-date').getValue()
-    },
-    // process the response object to add it to the TabPanel:
-    success: function(xhr) {
-        var newComponent = eval(xhr.responseText); // see discussion below
-        myTabPanel.add(newComponent); // add the component to the TabPanel
-        myTabPanel.setActiveTab(newComponent);
-    },
-    failure: function() {
-        Ext.Msg.alert("Grid create failed", "Server communication failure");
-    }
-});
-</code></pre>
- * <p>The server script needs to return a JSON representation of a configuration object, which, when decoded
- * will return a config object with an {@link Ext.Component#xtype xtype}. The server might return the following
- * JSON:</p><pre><code>
-{
-    "xtype": 'grid',
-    "title": 'Invoice Report',
-    "store": {
-        "model": 'Invoice',
-        "proxy": {
-            "type": 'ajax',
-            "url": 'get-invoice-data.php',
-            "reader": {
-                "type": 'json'
-                "record": 'transaction',
-                "idProperty": 'id',
-                "totalRecords": 'total'
-            })
-        },
-        "autoLoad": {
-            "params": {
-                "startDate": '01/01/2008',
-                "endDate": '01/31/2008'
-            }
-        }
-    },
-    "headers": [
-        {"header": "Customer", "width": 250, "dataIndex": 'customer', "sortable": true},
-        {"header": "Invoice Number", "width": 120, "dataIndex": 'invNo', "sortable": true},
-        {"header": "Invoice Date", "width": 100, "dataIndex": 'date', "renderer": Ext.util.Format.dateRenderer('M d, y'), "sortable": true},
-        {"header": "Value", "width": 120, "dataIndex": 'value', "renderer": 'usMoney', "sortable": true}
-    ]
-}
-</code></pre>
- * <p>When the above code fragment is passed through the <code>eval</code> function in the success handler
- * of the Ajax request, the result will be a config object which, when added to a Container, will cause instantiation
- * of a GridPanel. <b>Be sure that the Container is configured with a layout which sizes and positions the child items to your requirements.</b></p>
- * <p>Note: since the code above is <i>generated</i> by a server script, the <code>autoLoad</code> params for
- * the Store, the user's preferred date format, the metadata to allow generation of the Model layout, and the ColumnModel
- * can all be generated into the code since these are all known on the server.</p>
+/**
+ * Base class for any Ext.Component that may contain other Components. Containers handle the basic behavior of
+ * containing items, namely adding, inserting and removing items.
+ *
+ * The most commonly used Container classes are Ext.panel.Panel, Ext.window.Window and
+ * Ext.tab.Panel. If you do not need the capabilities offered by the aforementioned classes you can create a
+ * lightweight Container to be encapsulated by an HTML element to your specifications by using the
+ * {@link Ext.Component#autoEl autoEl} config option.
+ *
+ * The code below illustrates how to explicitly create a Container:
+ *
+ *     @example
+ *     // Explicitly create a Container
+ *     Ext.create('Ext.container.Container', {
+ *         layout: {
+ *             type: 'hbox'
+ *         },
+ *         width: 400,
+ *         renderTo: Ext.getBody(),
+ *         border: 1,
+ *         style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
+ *         defaults: {
+ *             labelWidth: 80,
+ *             // implicitly create Container by specifying xtype
+ *             xtype: 'datefield',
+ *             flex: 1,
+ *             style: {
+ *                 padding: '10px'
+ *             }
+ *         },
+ *         items: [{
+ *             xtype: 'datefield',
+ *             name: 'startDate',
+ *             fieldLabel: 'Start date'
+ *         },{
+ *             xtype: 'datefield',
+ *             name: 'endDate',
+ *             fieldLabel: 'End date'
+ *         }]
+ *     });
+ *
+ * ## Layout
+ *
+ * Container classes delegate the rendering of child Components to a layout manager class which must be configured into
+ * the Container using the `{@link #layout}` configuration property.
+ *
+ * When either specifying child `{@link #items}` of a Container, or dynamically {@link #add adding} Components to a
+ * Container, remember to consider how you wish the Container to arrange those child elements, and whether those child
+ * elements need to be sized using one of Ext's built-in `{@link #layout}` schemes. By default, Containers use the
+ * {@link Ext.layout.container.Auto Auto} scheme which only renders child components, appending them one after the other
+ * inside the Container, and **does not apply any sizing** at all.
+ *
+ * A common mistake is when a developer neglects to specify a `{@link #layout}` (e.g. widgets like GridPanels or
+ * TreePanels are added to Containers for which no `{@link #layout}` has been specified). If a Container is left to
+ * use the default {@link Ext.layout.container.Auto Auto} scheme, none of its child components will be resized, or changed in
+ * any way when the Container is resized.
+ *
+ * Certain layout managers allow dynamic addition of child components. Those that do include
+ * Ext.layout.container.Card, Ext.layout.container.Anchor, Ext.layout.container.VBox,
+ * Ext.layout.container.HBox, and Ext.layout.container.Table. For example:
+ *
+ *     //  Create the GridPanel.
+ *     var myNewGrid = new Ext.grid.Panel({
+ *         store: myStore,
+ *         headers: myHeaders,
+ *         title: 'Results', // the title becomes the title of the tab
+ *     });
+ *
+ *     myTabPanel.add(myNewGrid); // {@link Ext.tab.Panel} implicitly uses {@link Ext.layout.container.Card Card}
+ *     myTabPanel.{@link Ext.tab.Panel#setActiveTab setActiveTab}(myNewGrid);
+ *
+ * The example above adds a newly created GridPanel to a TabPanel. Note that a TabPanel uses {@link
+ * Ext.layout.container.Card} as its layout manager which means all its child items are sized to {@link
+ * Ext.layout.container.Fit fit} exactly into its client area.
+ *
+ * **_Overnesting is a common problem_**. An example of overnesting occurs when a GridPanel is added to a TabPanel by
+ * wrapping the GridPanel _inside_ a wrapping Panel (that has no `{@link #layout}` specified) and then add that
+ * wrapping Panel to the TabPanel. The point to realize is that a GridPanel **is** a Component which can be added
+ * directly to a Container. If the wrapping Panel has no `{@link #layout}` configuration, then the overnested
+ * GridPanel will not be sized as expected.
+ *
+ * ## Adding via remote configuration
+ *
+ * A server side script can be used to add Components which are generated dynamically on the server. An example of
+ * adding a GridPanel to a TabPanel where the GridPanel is generated by the server based on certain parameters:
+ *
+ *     // execute an Ajax request to invoke server side script:
+ *     Ext.Ajax.request({
+ *         url: 'gen-invoice-grid.php',
+ *         // send additional parameters to instruct server script
+ *         params: {
+ *             startDate: Ext.getCmp('start-date').getValue(),
+ *             endDate: Ext.getCmp('end-date').getValue()
+ *         },
+ *         // process the response object to add it to the TabPanel:
+ *         success: function(xhr) {
+ *             var newComponent = eval(xhr.responseText); // see discussion below
+ *             myTabPanel.add(newComponent); // add the component to the TabPanel
+ *             myTabPanel.setActiveTab(newComponent);
+ *         },
+ *         failure: function() {
+ *             Ext.Msg.alert("Grid create failed", "Server communication failure");
+ *         }
+ *     });
+ *
+ * The server script needs to return a JSON representation of a configuration object, which, when decoded will return a
+ * config object with an {@link Ext.Component#xtype xtype}. The server might return the following JSON:
+ *
+ *     {
+ *         "xtype": 'grid',
+ *         "title": 'Invoice Report',
+ *         "store": {
+ *             "model": 'Invoice',
+ *             "proxy": {
+ *                 "type": 'ajax',
+ *                 "url": 'get-invoice-data.php',
+ *                 "reader": {
+ *                     "type": 'json'
+ *                     "record": 'transaction',
+ *                     "idProperty": 'id',
+ *                     "totalRecords": 'total'
+ *                 })
+ *             },
+ *             "autoLoad": {
+ *                 "params": {
+ *                     "startDate": '01/01/2008',
+ *                     "endDate": '01/31/2008'
+ *                 }
+ *             }
+ *         },
+ *         "headers": [
+ *             {"header": "Customer", "width": 250, "dataIndex": 'customer', "sortable": true},
+ *             {"header": "Invoice Number", "width": 120, "dataIndex": 'invNo', "sortable": true},
+ *             {"header": "Invoice Date", "width": 100, "dataIndex": 'date', "renderer": Ext.util.Format.dateRenderer('M d, y'), "sortable": true},
+ *             {"header": "Value", "width": 120, "dataIndex": 'value', "renderer": 'usMoney', "sortable": true}
+ *         ]
+ *     }
+ *
+ * When the above code fragment is passed through the `eval` function in the success handler of the Ajax request, the
+ * result will be a config object which, when added to a Container, will cause instantiation of a GridPanel. **Be sure
+ * that the Container is configured with a layout which sizes and positions the child items to your requirements.**
+ *
+ * **Note:** since the code above is _generated_ by a server script, the `autoLoad` params for the Store, the user's
+ * preferred date format, the metadata to allow generation of the Model layout, and the ColumnModel can all be generated
+ * into the code since these are all known on the server.
  */
 Ext.define('Ext.container.Container', {
     extend: 'Ext.container.AbstractContainer',
@@ -22480,8 +23269,8 @@ Ext.define('Ext.container.Container', {
 
     /**
      * Return the immediate child Component in which the passed element is located.
-     * @param el The element to test.
-     * @return {Component} The child item which contains the passed element.
+     * @param {Ext.Element/HTMLElement/String} el The element to test (or ID of element).
+     * @return {Ext.Component} The child item which contains the passed element.
      */
     getChildByElement: function(el) {
         var item,
@@ -22503,28 +23292,21 @@ Ext.define('Ext.container.Container', {
 });
 
 /**
- * @class Ext.toolbar.Fill
- * @extends Ext.Component
- *
  * A non-rendering placeholder item which instructs the Toolbar's Layout to begin using
  * the right-justified button container.
  *
- * {@img Ext.toolbar.Fill/Ext.toolbar.Fill.png Toolbar Fill}
- *
- * ## Example
- *
+ *     @example
  *     Ext.create('Ext.panel.Panel', {
  *          title: 'Toolbar Fill Example',
  *          width: 300,
  *          height: 200,
  *          tbar : [
  *              'Item 1',
- *              {xtype: 'tbfill'}, // or '->'
+ *              { xtype: 'tbfill' },
  *              'Item 2'
  *          ],
  *          renderTo: Ext.getBody()
  *      });
- *
  */
 Ext.define('Ext.toolbar.Fill', {
     extend: 'Ext.Component',
@@ -22553,25 +23335,20 @@ Ext.define('Ext.toolbar.Item', {
 /**
  * @class Ext.toolbar.Separator
  * @extends Ext.toolbar.Item
- * A simple class that adds a vertical separator bar between toolbar items
- * (css class:<tt>'x-toolbar-separator'</tt>). 
- *
- * {@img Ext.toolbar.Separator/Ext.toolbar.Separator.png Toolbar Separator}
- *
- * ## Example
+ * A simple class that adds a vertical separator bar between toolbar items (css class: 'x-toolbar-separator').
  *
+ *     @example
  *     Ext.create('Ext.panel.Panel', {
  *         title: 'Toolbar Seperator Example',
  *         width: 300,
  *         height: 200,
  *         tbar : [
  *             'Item 1',
- *             {xtype: 'tbseparator'}, // or '-'
+ *             { xtype: 'tbseparator' },
  *             'Item 2'
  *         ],
  *         renderTo: Ext.getBody()
- *     }); 
- *
+ *     });
  */
 Ext.define('Ext.toolbar.Separator', {
     extend: 'Ext.toolbar.Item',
@@ -22682,10 +23459,16 @@ Ext.define('Ext.menu.Manager', {
     onMouseDown: function(e) {
         var me = this,
             active = me.active,
-            lastShow = me.lastShow;
+            lastShow = me.lastShow,
+            target = e.target;
 
         if (Ext.Date.getElapsed(lastShow) > 50 && active.length > 0 && !e.getTarget('.' + Ext.baseCSSPrefix + 'menu')) {
             me.hideAll();
+            // in IE, if we mousedown on a focusable element, the focus gets cancelled and the focus event is never
+            // fired on the element, so we'll focus it here
+            if (Ext.isIE && Ext.fly(target).focusable()) {
+                target.focus();
+            }
         }
     },
 
@@ -22792,134 +23575,276 @@ Ext.define('Ext.menu.Manager', {
     }
 });
 /**
- * @class Ext.button.Button
- * @extends Ext.Component
+ * Component layout for buttons
+ * @class Ext.layout.component.Button
+ * @extends Ext.layout.component.Component
+ * @private
+ */
+Ext.define('Ext.layout.component.Button', {
 
-Create simple buttons with this component. Customisations include {@link #iconAlign aligned}
-{@link #iconCls icons}, {@link #menu dropdown menus}, {@link #tooltip tooltips}
-and {@link #scale sizing options}. Specify a {@link #handler handler} to run code when
-a user clicks the button, or use {@link #listeners listeners} for other events such as
-{@link #mouseover mouseover}.
+    /* Begin Definitions */
 
-{@img Ext.button.Button/Ext.button.Button1.png Ext.button.Button component}
-Example usage:
+    alias: ['layout.button'],
 
-    Ext.create('Ext.Button', {
-        text: 'Click me',
-        renderTo: Ext.getBody(),        
-        handler: function() {
-            alert('You clicked the button!')
-        }
-    });
+    extend: 'Ext.layout.component.Component',
 
-The {@link #handler} configuration can also be updated dynamically using the {@link #setHandler} method.
-Example usage:
-
-    Ext.create('Ext.Button', {
-        text    : 'Dyanmic Handler Button',
-        renderTo: Ext.getBody(),
-        handler : function() {
-            //this button will spit out a different number every time you click it.
-            //so firstly we must check if that number is already set:
-            if (this.clickCount) {
-                //looks like the property is already set, so lets just add 1 to that number and alert the user
-                this.clickCount++;
-                alert('You have clicked the button "' + this.clickCount + '" times.\n\nTry clicking it again..');
-            } else {
-                //if the clickCount property is not set, we will set it and alert the user
-                this.clickCount = 1;
-                alert('You just clicked the button for the first time!\n\nTry pressing it again..');
-            }
-        }
-    });
+    /* End Definitions */
 
-A button within a container:
+    type: 'button',
 
-    Ext.create('Ext.Container', {
-        renderTo: Ext.getBody(),
-        items   : [
-            {
-                xtype: 'button',
-                text : 'My Button'
-            }
-        ]
-    });
+    cellClsRE: /-btn-(tl|br)\b/,
+    htmlRE: /<.*>/,
 
-A useful option of Button is the {@link #scale} configuration. This configuration has three different options:
-* `'small'`
-* `'medium'`
-* `'large'`
+    beforeLayout: function() {
+        return this.callParent(arguments) || this.lastText !== this.owner.text;
+    },
 
-{@img Ext.button.Button/Ext.button.Button2.png Ext.button.Button component}
-Example usage:
+    /**
+     * Set the dimensions of the inner &lt;button&gt; element to match the
+     * component dimensions.
+     */
+    onLayout: function(width, height) {
+        var me = this,
+            isNum = Ext.isNumber,
+            owner = me.owner,
+            ownerEl = owner.el,
+            btnEl = owner.btnEl,
+            btnInnerEl = owner.btnInnerEl,
+            btnIconEl = owner.btnIconEl,
+            sizeIconEl = (owner.icon || owner.iconCls) && (owner.iconAlign == "top" || owner.iconAlign == "bottom"),
+            minWidth = owner.minWidth,
+            maxWidth = owner.maxWidth,
+            ownerWidth, btnFrameWidth, metrics;
 
-    Ext.create('Ext.Button', {
-        renderTo: document.body,
-        text    : 'Click me',
-        scale   : 'large'
-    });
+        me.getTargetInfo();
+        me.callParent(arguments);
 
-Buttons can also be toggled. To enable this, you simple set the {@link #enableToggle} property to `true`.
-{@img Ext.button.Button/Ext.button.Button3.png Ext.button.Button component}
-Example usage:
+        btnInnerEl.unclip();
+        me.setTargetSize(width, height);
 
-    Ext.create('Ext.Button', {
-        renderTo: Ext.getBody(),
-        text: 'Click Me',
-        enableToggle: true
-    });
+        if (!isNum(width)) {
+            // In IE7 strict mode button elements with width:auto get strange extra side margins within
+            // the wrapping table cell, but they go away if the width is explicitly set. So we measure
+            // the size of the text and set the width to match.
+            if (owner.text && (Ext.isIE6 || Ext.isIE7) && Ext.isStrict && btnEl && btnEl.getWidth() > 20) {
+                btnFrameWidth = me.btnFrameWidth;
+                metrics = Ext.util.TextMetrics.measure(btnInnerEl, owner.text);
+                ownerEl.setWidth(metrics.width + btnFrameWidth + me.adjWidth);
+                btnEl.setWidth(metrics.width + btnFrameWidth);
+                btnInnerEl.setWidth(metrics.width + btnFrameWidth);
 
-You can assign a menu to a button by using the {@link #menu} configuration. This standard configuration can either be a reference to a {@link Ext.menu.Menu menu}
-object, a {@link Ext.menu.Menu menu} id or a {@link Ext.menu.Menu menu} config blob. When assigning a menu to a button, an arrow is automatically added to the button.
-You can change the alignment of the arrow using the {@link #arrowAlign} configuration on button.
-{@img Ext.button.Button/Ext.button.Button4.png Ext.button.Button component}
-Example usage:
-
-    Ext.create('Ext.Button', {
-        text      : 'Menu button',
-        renderTo  : Ext.getBody(),        
-        arrowAlign: 'bottom',
-        menu      : [
-            {text: 'Item 1'},
-            {text: 'Item 2'},
-            {text: 'Item 3'},
-            {text: 'Item 4'}
-        ]
-    });
+                if (sizeIconEl) {
+                    btnIconEl.setWidth(metrics.width + btnFrameWidth);
+                }
+            } else {
+                // Remove any previous fixed widths
+                ownerEl.setWidth(null);
+                btnEl.setWidth(null);
+                btnInnerEl.setWidth(null);
+                btnIconEl.setWidth(null);
+            }
 
-Using listeners, you can easily listen to events fired by any component, using the {@link #listeners} configuration or using the {@link #addListener} method.
-Button has a variety of different listeners:
-* `click`
-* `toggle`
-* `mouseover`
-* `mouseout`
-* `mouseshow`
-* `menuhide`
-* `menutriggerover`
-* `menutriggerout`
-
-Example usage:
-
-    Ext.create('Ext.Button', {
-        text     : 'Button',
-        renderTo : Ext.getBody(),
-        listeners: {
-            click: function() {
-                //this == the button, as we are in the local scope
-                this.setText('I was clicked!');
-            },
-            mouseover: function() {
-                //set a new config which says we moused over, if not already set
-                if (!this.mousedOver) {
-                    this.mousedOver = true;
-                    alert('You moused over a button!\n\nI wont do this again.');
+            // Handle maxWidth/minWidth config
+            if (minWidth || maxWidth) {
+                ownerWidth = ownerEl.getWidth();
+                if (minWidth && (ownerWidth < minWidth)) {
+                    me.setTargetSize(minWidth, height);
+                }
+                else if (maxWidth && (ownerWidth > maxWidth)) {
+                    btnInnerEl.clip();
+                    me.setTargetSize(maxWidth, height);
                 }
             }
         }
-    });
 
- * @markdown
+        this.lastText = owner.text;
+    },
+
+    setTargetSize: function(width, height) {
+        var me = this,
+            owner = me.owner,
+            isNum = Ext.isNumber,
+            btnInnerEl = owner.btnInnerEl,
+            btnWidth = (isNum(width) ? width - me.adjWidth : width),
+            btnHeight = (isNum(height) ? height - me.adjHeight : height),
+            btnFrameHeight = me.btnFrameHeight,
+            text = owner.getText(),
+            textHeight;
+
+        me.callParent(arguments);
+        me.setElementSize(owner.btnEl, btnWidth, btnHeight);
+        me.setElementSize(btnInnerEl, btnWidth, btnHeight);
+        if (btnHeight >= 0) {
+            btnInnerEl.setStyle('line-height', btnHeight - btnFrameHeight + 'px');
+        }
+
+        // Button text may contain markup that would force it to wrap to more than one line (e.g. 'Button<br>Label').
+        // When this happens, we cannot use the line-height set above for vertical centering; we instead reset the
+        // line-height to normal, measure the rendered text height, and add padding-top to center the text block
+        // vertically within the button's height. This is more expensive than the basic line-height approach so
+        // we only do it if the text contains markup.
+        if (text && this.htmlRE.test(text)) {
+            btnInnerEl.setStyle('line-height', 'normal');
+            textHeight = Ext.util.TextMetrics.measure(btnInnerEl, text).height;
+            btnInnerEl.setStyle('padding-top', me.btnFrameTop + Math.max(btnInnerEl.getHeight() - btnFrameHeight - textHeight, 0) / 2 + 'px');
+            me.setElementSize(btnInnerEl, btnWidth, btnHeight);
+        }
+    },
+
+    getTargetInfo: function() {
+        var me = this,
+            owner = me.owner,
+            ownerEl = owner.el,
+            frameSize = me.frameSize,
+            frameBody = owner.frameBody,
+            btnWrap = owner.btnWrap,
+            innerEl = owner.btnInnerEl;
+
+        if (!('adjWidth' in me)) {
+            Ext.apply(me, {
+                // Width adjustment must take into account the arrow area. The btnWrap is the <em> which has padding to accommodate the arrow.
+                adjWidth: frameSize.left + frameSize.right + ownerEl.getBorderWidth('lr') + ownerEl.getPadding('lr') +
+                          btnWrap.getPadding('lr') + (frameBody ? frameBody.getFrameWidth('lr') : 0),
+                adjHeight: frameSize.top + frameSize.bottom + ownerEl.getBorderWidth('tb') + ownerEl.getPadding('tb') +
+                           btnWrap.getPadding('tb') + (frameBody ? frameBody.getFrameWidth('tb') : 0),
+                btnFrameWidth: innerEl.getFrameWidth('lr'),
+                btnFrameHeight: innerEl.getFrameWidth('tb'),
+                btnFrameTop: innerEl.getFrameWidth('t')
+            });
+        }
+
+        return me.callParent();
+    }
+});
+/**
  * @docauthor Robert Dougan <rob@sencha.com>
+ *
+ * Create simple buttons with this component. Customisations include {@link #iconAlign aligned}
+ * {@link #iconCls icons}, {@link #menu dropdown menus}, {@link #tooltip tooltips}
+ * and {@link #scale sizing options}. Specify a {@link #handler handler} to run code when
+ * a user clicks the button, or use {@link #listeners listeners} for other events such as
+ * {@link #mouseover mouseover}. Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.Button', {
+ *         text: 'Click me',
+ *         renderTo: Ext.getBody(),
+ *         handler: function() {
+ *             alert('You clicked the button!')
+ *         }
+ *     });
+ *
+ * The {@link #handler} configuration can also be updated dynamically using the {@link #setHandler}
+ * method.  Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.Button', {
+ *         text    : 'Dynamic Handler Button',
+ *         renderTo: Ext.getBody(),
+ *         handler : function() {
+ *             // this button will spit out a different number every time you click it.
+ *             // so firstly we must check if that number is already set:
+ *             if (this.clickCount) {
+ *                 // looks like the property is already set, so lets just add 1 to that number and alert the user
+ *                 this.clickCount++;
+ *                 alert('You have clicked the button "' + this.clickCount + '" times.\n\nTry clicking it again..');
+ *             } else {
+ *                 // if the clickCount property is not set, we will set it and alert the user
+ *                 this.clickCount = 1;
+ *                 alert('You just clicked the button for the first time!\n\nTry pressing it again..');
+ *             }
+ *         }
+ *     });
+ *
+ * A button within a container:
+ *
+ *     @example
+ *     Ext.create('Ext.Container', {
+ *         renderTo: Ext.getBody(),
+ *         items   : [
+ *             {
+ *                 xtype: 'button',
+ *                 text : 'My Button'
+ *             }
+ *         ]
+ *     });
+ *
+ * A useful option of Button is the {@link #scale} configuration. This configuration has three different options:
+ *
+ * - `'small'`
+ * - `'medium'`
+ * - `'large'`
+ *
+ * Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.Button', {
+ *         renderTo: document.body,
+ *         text    : 'Click me',
+ *         scale   : 'large'
+ *     });
+ *
+ * Buttons can also be toggled. To enable this, you simple set the {@link #enableToggle} property to `true`.
+ * Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.Button', {
+ *         renderTo: Ext.getBody(),
+ *         text: 'Click Me',
+ *         enableToggle: true
+ *     });
+ *
+ * You can assign a menu to a button by using the {@link #menu} configuration. This standard configuration
+ * can either be a reference to a {@link Ext.menu.Menu menu} object, a {@link Ext.menu.Menu menu} id or a
+ * {@link Ext.menu.Menu menu} config blob. When assigning a menu to a button, an arrow is automatically
+ * added to the button.  You can change the alignment of the arrow using the {@link #arrowAlign} configuration
+ * on button.  Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.Button', {
+ *         text      : 'Menu button',
+ *         renderTo  : Ext.getBody(),
+ *         arrowAlign: 'bottom',
+ *         menu      : [
+ *             {text: 'Item 1'},
+ *             {text: 'Item 2'},
+ *             {text: 'Item 3'},
+ *             {text: 'Item 4'}
+ *         ]
+ *     });
+ *
+ * Using listeners, you can easily listen to events fired by any component, using the {@link #listeners}
+ * configuration or using the {@link #addListener} method.  Button has a variety of different listeners:
+ *
+ * - `click`
+ * - `toggle`
+ * - `mouseover`
+ * - `mouseout`
+ * - `mouseshow`
+ * - `menuhide`
+ * - `menutriggerover`
+ * - `menutriggerout`
+ *
+ * Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.Button', {
+ *         text     : 'Button',
+ *         renderTo : Ext.getBody(),
+ *         listeners: {
+ *             click: function() {
+ *                 // this == the button, as we are in the local scope
+ *                 this.setText('I was clicked!');
+ *             },
+ *             mouseover: function() {
+ *                 // set a new config which says we moused over, if not already set
+ *                 if (!this.mousedOver) {
+ *                     this.mousedOver = true;
+ *                     alert('You moused over a button!\n\nI wont do this again.');
+ *                 }
+ *             }
+ *         }
+ *     });
  */
 Ext.define('Ext.button.Button', {
 
@@ -22942,274 +23867,289 @@ Ext.define('Ext.button.Button', {
     componentLayout: 'button',
 
     /**
-     * Read-only. True if this button is hidden
-     * @type Boolean
+     * @property {Boolean} hidden
+     * True if this button is hidden. Read-only.
      */
     hidden: false,
 
     /**
-     * Read-only. True if this button is disabled
-     * @type Boolean
+     * @property {Boolean} disabled
+     * True if this button is disabled. Read-only.
      */
     disabled: false,
 
     /**
-     * Read-only. True if this button is pressed (only if enableToggle = true)
-     * @type Boolean
+     * @property {Boolean} pressed
+     * True if this button is pressed (only if enableToggle = true). Read-only.
      */
     pressed: false,
 
     /**
-     * @cfg {String} text The button text to be used as innerHTML (html tags are accepted)
+     * @cfg {String} text
+     * The button text to be used as innerHTML (html tags are accepted).
      */
 
     /**
-     * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
-     * CSS property of the button by default, so if you want a mixed icon/text button, set cls:'x-btn-text-icon')
+     * @cfg {String} icon
+     * The path to an image to display in the button (the image will be set as the background-image CSS property of the
+     * button by default, so if you want a mixed icon/text button, set cls:'x-btn-text-icon')
      */
 
     /**
-     * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event).
-     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
-     * <li><code>b</code> : Button<div class="sub-desc">This Button.</div></li>
-     * <li><code>e</code> : EventObject<div class="sub-desc">The click event.</div></li>
-     * </ul></div>
+     * @cfg {Function} handler
+     * A function called when the button is clicked (can be used instead of click event).
+     * @cfg {Ext.button.Button} handler.button This button.
+     * @cfg {Ext.EventObject} handler.e The click event.
      */
 
     /**
-     * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width).
-     * See also {@link Ext.panel.Panel}.<tt>{@link Ext.panel.Panel#minButtonWidth minButtonWidth}</tt>.
+     * @cfg {Number} minWidth
+     * The minimum width for this button (used to give a set of buttons a common width).
+     * See also {@link Ext.panel.Panel}.{@link Ext.panel.Panel#minButtonWidth minButtonWidth}.
      */
 
     /**
-     * @cfg {String/Object} tooltip The tooltip for the button - can be a string to be used as innerHTML (html tags are accepted) or QuickTips config object
+     * @cfg {String/Object} tooltip
+     * The tooltip for the button - can be a string to be used as innerHTML (html tags are accepted) or
+     * QuickTips config object.
      */
 
     /**
-     * @cfg {Boolean} hidden True to start hidden (defaults to false)
+     * @cfg {Boolean} [hidden=false]
+     * True to start hidden.
      */
 
     /**
-     * @cfg {Boolean} disabled True to start disabled (defaults to false)
+     * @cfg {Boolean} [disabled=true]
+     * True to start disabled.
      */
 
     /**
-     * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
+     * @cfg {Boolean} [pressed=false]
+     * True to start pressed (only if enableToggle = true)
      */
 
     /**
-     * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed)
+     * @cfg {String} toggleGroup
+     * The group this toggle button is a member of (only 1 per group can be pressed)
      */
 
     /**
-     * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
-     * a {@link Ext.util.ClickRepeater ClickRepeater} config object (defaults to false).
+     * @cfg {Boolean/Object} [repeat=false]
+     * True to repeat fire the click event while the mouse is down. This can also be a
+     * {@link Ext.util.ClickRepeater ClickRepeater} config object.
      */
 
     /**
-     * @cfg {Number} tabIndex Set a DOM tabIndex for this button (defaults to undefined)
+     * @cfg {Number} tabIndex
+     * Set a DOM tabIndex for this button.
      */
 
     /**
-     * @cfg {Boolean} allowDepress
-     * False to not allow a pressed Button to be depressed (defaults to undefined). Only valid when {@link #enableToggle} is true.
+     * @cfg {Boolean} [allowDepress=true]
+     * False to not allow a pressed Button to be depressed. Only valid when {@link #enableToggle} is true.
      */
 
     /**
-     * @cfg {Boolean} enableToggle
-     * True to enable pressed/not pressed toggling (defaults to false)
+     * @cfg {Boolean} [enableToggle=false]
+     * True to enable pressed/not pressed toggling.
      */
     enableToggle: false,
 
     /**
      * @cfg {Function} toggleHandler
-     * Function called when a Button with {@link #enableToggle} set to true is clicked. Two arguments are passed:<ul class="mdetail-params">
-     * <li><b>button</b> : Ext.button.Button<div class="sub-desc">this Button object</div></li>
-     * <li><b>state</b> : Boolean<div class="sub-desc">The next state of the Button, true means pressed.</div></li>
-     * </ul>
+     * Function called when a Button with {@link #enableToggle} set to true is clicked.
+     * @cfg {Ext.button.Button} toggleHandler.button This button.
+     * @cfg {Boolean} toggleHandler.state The next state of the Button, true means pressed.
      */
 
     /**
-     * @cfg {Mixed} menu
-     * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
+     * @cfg {Ext.menu.Menu/String/Object} menu
+     * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob.
      */
 
     /**
      * @cfg {String} menuAlign
-     * The position to align the menu to (see {@link Ext.core.Element#alignTo} for more details, defaults to 'tl-bl?').
+     * The position to align the menu to (see {@link Ext.Element#alignTo} for more details).
      */
     menuAlign: 'tl-bl?',
 
     /**
-     * @cfg {String} overflowText If used in a {@link Ext.toolbar.Toolbar Toolbar}, the
-     * text to be used if this item is shown in the overflow menu. See also
-     * {@link Ext.toolbar.Item}.<code>{@link Ext.toolbar.Item#overflowText overflowText}</code>.
+     * @cfg {String} textAlign
+     * The text alignment for this button (center, left, right).
+     */
+    textAlign: 'center',
+
+    /**
+     * @cfg {String} overflowText
+     * If used in a {@link Ext.toolbar.Toolbar Toolbar}, the text to be used if this item is shown in the overflow menu.
+     * See also {@link Ext.toolbar.Item}.`{@link Ext.toolbar.Item#overflowText overflowText}`.
      */
 
     /**
      * @cfg {String} iconCls
-     * A css class which sets a background image to be used as the icon for this button
+     * A css class which sets a background image to be used as the icon for this button.
      */
 
     /**
      * @cfg {String} type
-     * submit, reset or button - defaults to 'button'
+     * The type of `<input>` to create: submit, reset or button.
      */
     type: 'button',
 
     /**
      * @cfg {String} clickEvent
      * The DOM event that will fire the handler of the button. This can be any valid event name (dblclick, contextmenu).
-     * Defaults to <tt>'click'</tt>.
      */
     clickEvent: 'click',
-    
+
     /**
      * @cfg {Boolean} preventDefault
-     * True to prevent the default action when the {@link #clickEvent} is processed. Defaults to true.
+     * True to prevent the default action when the {@link #clickEvent} is processed.
      */
     preventDefault: true,
 
     /**
      * @cfg {Boolean} handleMouseEvents
-     * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
+     * False to disable visual cues on mouseover, mouseout and mousedown.
      */
     handleMouseEvents: true,
 
     /**
      * @cfg {String} tooltipType
-     * The type of tooltip to use. Either 'qtip' (default) for QuickTips or 'title' for title attribute.
+     * The type of tooltip to use. Either 'qtip' for QuickTips or 'title' for title attribute.
      */
     tooltipType: 'qtip',
 
     /**
-     * @cfg {String} baseCls
-     * The base CSS class to add to all buttons. (Defaults to 'x-btn')
+     * @cfg {String} [baseCls='x-btn']
+     * The base CSS class to add to all buttons.
      */
     baseCls: Ext.baseCSSPrefix + 'btn',
 
     /**
      * @cfg {String} pressedCls
-     * The CSS class to add to a button when it is in the pressed state. (Defaults to 'x-btn-pressed')
+     * The CSS class to add to a button when it is in the pressed state.
      */
     pressedCls: 'pressed',
-    
+
     /**
      * @cfg {String} overCls
-     * The CSS class to add to a button when it is in the over (hovered) state. (Defaults to 'x-btn-over')
+     * The CSS class to add to a button when it is in the over (hovered) state.
      */
     overCls: 'over',
-    
+
     /**
      * @cfg {String} focusCls
-     * The CSS class to add to a button when it is in the focussed state. (Defaults to 'x-btn-focus')
+     * The CSS class to add to a button when it is in the focussed state.
      */
     focusCls: 'focus',
-    
+
     /**
      * @cfg {String} menuActiveCls
-     * The CSS class to add to a button when it's menu is active. (Defaults to 'x-btn-menu-active')
+     * The CSS class to add to a button when it's menu is active.
      */
     menuActiveCls: 'menu-active',
-    
+
+    /**
+     * @cfg {String} href
+     * The URL to visit when the button is clicked. Specifying this config is equivalent to specifying:
+     *
+     *     handler: function() { window.location = "http://www.sencha.com" }
+     */
+
     /**
      * @cfg {Object} baseParams
      * An object literal of parameters to pass to the url when the {@link #href} property is specified.
      */
-    
+
     /**
      * @cfg {Object} params
-     * An object literal of parameters to pass to the url when the {@link #href} property is specified.
-     * Any params override {@link #baseParams}. New params can be set using the {@link #setParams} method.
+     * An object literal of parameters to pass to the url when the {@link #href} property is specified. Any params
+     * override {@link #baseParams}. New params can be set using the {@link #setParams} method.
      */
 
     ariaRole: 'button',
 
     // inherited
     renderTpl:
-        '<em class="{splitCls}">' +
+        '<em id="{id}-btnWrap" class="{splitCls}">' +
             '<tpl if="href">' +
-                '<a href="{href}" target="{target}"<tpl if="tabIndex"> tabIndex="{tabIndex}"</tpl> role="link">' +
-                    '<span class="{baseCls}-inner">' +
+                '<a id="{id}-btnEl" href="{href}" target="{target}"<tpl if="tabIndex"> tabIndex="{tabIndex}"</tpl> role="link">' +
+                    '<span id="{id}-btnInnerEl" class="{baseCls}-inner">' +
                         '{text}' +
                     '</span>' +
-                        '<span class="{baseCls}-icon"></span>' +
+                        '<span id="{id}-btnIconEl" class="{baseCls}-icon"></span>' +
                 '</a>' +
             '</tpl>' +
             '<tpl if="!href">' +
-                '<button type="{type}" hidefocus="true"' +
+                '<button id="{id}-btnEl" type="{type}" hidefocus="true"' +
                     // the autocomplete="off" is required to prevent Firefox from remembering
                     // the button's disabled state between page reloads.
                     '<tpl if="tabIndex"> tabIndex="{tabIndex}"</tpl> role="button" autocomplete="off">' +
-                    '<span class="{baseCls}-inner" style="{innerSpanStyle}">' +
+                    '<span id="{id}-btnInnerEl" class="{baseCls}-inner" style="{innerSpanStyle}">' +
                         '{text}' +
                     '</span>' +
-                    '<span class="{baseCls}-icon"></span>' +
+                    '<span id="{id}-btnIconEl" class="{baseCls}-icon {iconCls}">&#160;</span>' +
                 '</button>' +
             '</tpl>' +
         '</em>' ,
 
     /**
      * @cfg {String} scale
-     * <p>(Optional) The size of the Button. Three values are allowed:</p>
-     * <ul class="mdetail-params">
-     * <li>'small'<div class="sub-desc">Results in the button element being 16px high.</div></li>
-     * <li>'medium'<div class="sub-desc">Results in the button element being 24px high.</div></li>
-     * <li>'large'<div class="sub-desc">Results in the button element being 32px high.</div></li>
-     * </ul>
-     * <p>Defaults to <b><tt>'small'</tt></b>.</p>
+     * The size of the Button. Three values are allowed:
+     *
+     * - 'small' - Results in the button element being 16px high.
+     * - 'medium' - Results in the button element being 24px high.
+     * - 'large' - Results in the button element being 32px high.
      */
     scale: 'small',
-    
+
     /**
-     * @private An array of allowed scales.
+     * @private
+     * An array of allowed scales.
      */
     allowedScales: ['small', 'medium', 'large'],
-    
+
     /**
-     * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the
-     * <code>{@link #handler}</code> and <code>{@link #toggleHandler}</code> is
-     * executed. Defaults to this Button.
+     * @cfg {Object} scope
+     * The scope (**this** reference) in which the `{@link #handler}` and `{@link #toggleHandler}` is executed.
+     * Defaults to this Button.
      */
 
     /**
      * @cfg {String} iconAlign
-     * <p>(Optional) The side of the Button box to render the icon. Four values are allowed:</p>
-     * <ul class="mdetail-params">
-     * <li>'top'<div class="sub-desc"></div></li>
-     * <li>'right'<div class="sub-desc"></div></li>
-     * <li>'bottom'<div class="sub-desc"></div></li>
-     * <li>'left'<div class="sub-desc"></div></li>
-     * </ul>
-     * <p>Defaults to <b><tt>'left'</tt></b>.</p>
+     * The side of the Button box to render the icon. Four values are allowed:
+     *
+     * - 'top'
+     * - 'right'
+     * - 'bottom'
+     * - 'left'
      */
     iconAlign: 'left',
 
     /**
      * @cfg {String} arrowAlign
-     * <p>(Optional) The side of the Button box to render the arrow if the button has an associated {@link #menu}.
-     * Two values are allowed:</p>
-     * <ul class="mdetail-params">
-     * <li>'right'<div class="sub-desc"></div></li>
-     * <li>'bottom'<div class="sub-desc"></div></li>
-     * </ul>
-     * <p>Defaults to <b><tt>'right'</tt></b>.</p>
+     * The side of the Button box to render the arrow if the button has an associated {@link #menu}. Two
+     * values are allowed:
+     *
+     * - 'right'
+     * - 'bottom'
      */
     arrowAlign: 'right',
 
     /**
      * @cfg {String} arrowCls
-     * <p>(Optional) The className used for the inner arrow element if the button has a menu.</p>
+     * The className used for the inner arrow element if the button has a menu.
      */
     arrowCls: 'arrow',
 
     /**
-     * @cfg {Ext.Template} template (Optional)
-     * <p>A {@link Ext.Template Template} used to create the Button's DOM structure.</p>
-     * Instances, or subclasses which need a different DOM structure may provide a different
-     * template layout in conjunction with an implementation of {@link #getTemplateArgs}.
-     * @type Ext.Template
-     * @property template
+     * @property {Ext.Template} template
+     * A {@link Ext.Template Template} used to create the Button's DOM structure.
+     *
+     * Instances, or subclasses which need a different DOM structure may provide a different template layout in
+     * conjunction with an implementation of {@link #getTemplateArgs}.
      */
 
     /**
@@ -23218,19 +24158,18 @@ Ext.define('Ext.button.Button', {
      */
 
     /**
-     * @property menu
-     * @type Menu
-     * The {@link Ext.menu.Menu Menu} object associated with this Button when configured with the {@link #menu} config option.
+     * @property {Ext.menu.Menu} menu
+     * The {@link Ext.menu.Menu Menu} object associated with this Button when configured with the {@link #menu} config
+     * option.
      */
 
     /**
      * @cfg {Boolean} autoWidth
-     * By default, if a width is not specified the button will attempt to stretch horizontally to fit its content.
-     * If the button is being managed by a width sizing layout (hbox, fit, anchor), set this to false to prevent
-     * the button from doing this automatic sizing.
-     * Defaults to <tt>undefined</tt>.
+     * By default, if a width is not specified the button will attempt to stretch horizontally to fit its content. If
+     * the button is being managed by a width sizing layout (hbox, fit, anchor), set this to false to prevent the button
+     * from doing this automatic sizing.
      */
-     
+
     maskOnDisable: false,
 
     // inherit docs
@@ -23242,15 +24181,15 @@ Ext.define('Ext.button.Button', {
             /**
              * @event click
              * Fires when this button is clicked
-             * @param {Button} this
-             * @param {EventObject} e The click event
+             * @param {Ext.button.Button} this
+             * @param {Event} e The click event
              */
             'click',
 
             /**
              * @event toggle
              * Fires when the 'pressed' state of this button changes (only if enableToggle = true)
-             * @param {Button} this
+             * @param {Ext.button.Button} this
              * @param {Boolean} pressed
              */
             'toggle',
@@ -23258,7 +24197,7 @@ Ext.define('Ext.button.Button', {
             /**
              * @event mouseover
              * Fires when the mouse hovers over the button
-             * @param {Button} this
+             * @param {Ext.button.Button} this
              * @param {Event} e The event object
              */
             'mouseover',
@@ -23266,7 +24205,7 @@ Ext.define('Ext.button.Button', {
             /**
              * @event mouseout
              * Fires when the mouse exits the button
-             * @param {Button} this
+             * @param {Ext.button.Button} this
              * @param {Event} e The event object
              */
             'mouseout',
@@ -23274,34 +24213,34 @@ Ext.define('Ext.button.Button', {
             /**
              * @event menushow
              * If this button has a menu, this event fires when it is shown
-             * @param {Button} this
-             * @param {Menu} menu
+             * @param {Ext.button.Button} this
+             * @param {Ext.menu.Menu} menu
              */
             'menushow',
 
             /**
              * @event menuhide
              * If this button has a menu, this event fires when it is hidden
-             * @param {Button} this
-             * @param {Menu} menu
+             * @param {Ext.button.Button} this
+             * @param {Ext.menu.Menu} menu
              */
             'menuhide',
 
             /**
              * @event menutriggerover
              * If this button has a menu, this event fires when the mouse enters the menu triggering element
-             * @param {Button} this
-             * @param {Menu} menu
-             * @param {EventObject} e
+             * @param {Ext.button.Button} this
+             * @param {Ext.menu.Menu} menu
+             * @param {Event} e
              */
             'menutriggerover',
 
             /**
              * @event menutriggerout
              * If this button has a menu, this event fires when the mouse leaves the menu triggering element
-             * @param {Button} this
-             * @param {Menu} menu
-             * @param {EventObject} e
+             * @param {Ext.button.Button} this
+             * @param {Ext.menu.Menu} menu
+             * @param {Event} e
              */
             'menutriggerout'
         );
@@ -23353,15 +24292,16 @@ Ext.define('Ext.button.Button', {
     // private
     setButtonCls: function() {
         var me = this,
-            el = me.el,
-            cls = [];
+            cls = [],
+            btnIconEl = me.btnIconEl,
+            hide = 'x-hide-display';
 
         if (me.useSetClass) {
             if (!Ext.isEmpty(me.oldCls)) {
                 me.removeClsWithUI(me.oldCls);
                 me.removeClsWithUI(me.pressedCls);
             }
-            
+
             // Check whether the button has an icon or not, and if it has an icon, what is th alignment
             if (me.iconCls || me.icon) {
                 if (me.text) {
@@ -23369,33 +24309,35 @@ Ext.define('Ext.button.Button', {
                 } else {
                     cls.push('icon');
                 }
-            } else if (me.text) {
-                cls.push('noicon');
+                if (btnIconEl) {
+                    btnIconEl.removeCls(hide);
+                }
+            } else {
+                if (me.text) {
+                    cls.push('noicon');
+                }
+                if (btnIconEl) {
+                    btnIconEl.addCls(hide);
+                }
             }
-            
+
             me.oldCls = cls;
             me.addClsWithUI(cls);
             me.addClsWithUI(me.pressed ? me.pressedCls : null);
         }
     },
-    
+
     // private
     onRender: function(ct, position) {
         // classNames for the button
         var me = this,
             repeater, btn;
-            
+
         // Apply the renderData to the template args
         Ext.applyIf(me.renderData, me.getTemplateArgs());
 
-        // Extract the button and the button wrapping element
-        Ext.applyIf(me.renderSelectors, {
-            btnEl  : me.href ? 'a' : 'button',
-            btnWrap: 'em',
-            btnInnerEl: '.' + me.baseCls + '-inner',
-            btnIconEl: '.'+ me.baseCls + '-icon'
-        });
-        
+        me.addChildEls('btnEl', 'btnWrap', 'btnInnerEl', 'btnIconEl');
+
         if (me.scale) {
             me.ui = me.ui + '-' + me.scale;
         }
@@ -23405,7 +24347,7 @@ Ext.define('Ext.button.Button', {
 
         // If it is a split button + has a toolip for the arrow
         if (me.split && me.arrowTooltip) {
-            me.arrowEl.dom[me.tooltipType] = me.arrowTooltip;
+            me.arrowEl.dom.setAttribute(me.getTipAttr(), me.arrowTooltip);
         }
 
         // Add listeners to the focus and blur events on the element
@@ -23430,6 +24372,10 @@ Ext.define('Ext.button.Button', {
             me.setTooltip(me.tooltip, true);
         }
 
+        if (me.textAlign) {
+            me.setTextAlign(me.textAlign);
+        }
+
         // Add the mouse events to the button
         if (me.handleMouseEvents) {
             me.mon(btn, {
@@ -23475,20 +24421,22 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * <p>This method returns an object which provides substitution parameters for the {@link #renderTpl XTemplate} used
-     * to create this Button's DOM structure.</p>
-     * <p>Instances or subclasses which use a different Template to create a different DOM structure may need to provide their
-     * own implementation of this method.</p>
-     * <p>The default implementation which provides data for the default {@link #template} returns an Object containing the
-     * following properties:</p><div class="mdetail-params"><ul>
-     * <li><code>type</code> : The &lt;button&gt;'s {@link #type}</li>
-     * <li><code>splitCls</code> : A CSS class to determine the presence and position of an arrow icon. (<code>'x-btn-arrow'</code> or <code>'x-btn-arrow-bottom'</code> or <code>''</code>)</li>
-     * <li><code>cls</code> : A CSS class name applied to the Button's main &lt;tbody&gt; element which determines the button's scale and icon alignment.</li>
-     * <li><code>text</code> : The {@link #text} to display ion the Button.</li>
-     * <li><code>tabIndex</code> : The tab index within the input flow.</li>
-     * </ul></div>
-     * @return {Array} Substitution data for a Template.
-    */
+     * This method returns an object which provides substitution parameters for the {@link #renderTpl XTemplate} used to
+     * create this Button's DOM structure.
+     *
+     * Instances or subclasses which use a different Template to create a different DOM structure may need to provide
+     * their own implementation of this method.
+     *
+     * @return {Object} Substitution data for a Template. The default implementation which provides data for the default
+     * {@link #template} returns an Object containing the following properties:
+     * @return {String} return.type The `<button>`'s {@link #type}
+     * @return {String} return.splitCls A CSS class to determine the presence and position of an arrow icon.
+     * (`'x-btn-arrow'` or `'x-btn-arrow-bottom'` or `''`)
+     * @return {String} return.cls A CSS class name applied to the Button's main `<tbody>` element which determines the
+     * button's scale and icon alignment.
+     * @return {String} return.text The {@link #text} to display ion the Button.
+     * @return {Number} return.tabIndex The tab index within the input flow.
+     */
     getTemplateArgs: function() {
         var me = this,
             persistentPadding = me.getPersistentBtnPadding(),
@@ -23507,6 +24455,7 @@ Ext.define('Ext.button.Button', {
             type     : me.type,
             splitCls : me.getSplitCls(),
             cls      : me.cls,
+            iconCls  : me.iconCls || '',
             text     : me.text || '&#160;',
             tabIndex : me.tabIndex,
             innerSpanStyle: innerSpanStyle
@@ -23521,15 +24470,17 @@ Ext.define('Ext.button.Button', {
     getHref: function() {
         var me = this,
             params = Ext.apply({}, me.baseParams);
-            
+
         // write baseParams first, then write any params
         params = Ext.apply(params, me.params);
         return me.href ? Ext.urlAppend(me.href, Ext.Object.toQueryString(params)) : false;
     },
 
     /**
-     * <p><b>Only valid if the Button was originally configured with a {@link #url}</b></p>
-     * <p>Sets the href of the link dynamically according to the params passed, and any {@link #baseParams} configured.</p>
+     * Sets the href of the link dynamically according to the params passed, and any {@link #baseParams} configured.
+     *
+     * **Only valid if the Button was originally configured with a {@link #href}**
+     *
      * @param {Object} params Parameters to use in the href URL.
      */
     setParams: function(params) {
@@ -23552,30 +24503,34 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * Sets the CSS class that provides a background image to use as the button's icon.  This method also changes
-     * the value of the {@link #iconCls} config internally.
+     * Sets the CSS class that provides a background image to use as the button's icon. This method also changes the
+     * value of the {@link #iconCls} config internally.
      * @param {String} cls The CSS class providing the icon image
      * @return {Ext.button.Button} this
      */
     setIconCls: function(cls) {
         var me = this,
-            btnIconEl = me.btnIconEl;
+            btnIconEl = me.btnIconEl,
+            oldCls = me.iconCls;
+            
+        me.iconCls = cls;
         if (btnIconEl) {
             // Remove the previous iconCls from the button
-            btnIconEl.removeCls(me.iconCls);
+            btnIconEl.removeCls(oldCls);
             btnIconEl.addCls(cls || '');
             me.setButtonCls();
         }
-        me.iconCls = cls;
         return me;
     },
 
     /**
      * Sets the tooltip for this Button.
-     * @param {String/Object} tooltip. This may be:<div class="mdesc-details"><ul>
-     * <li><b>String</b> : A string to be used as innerHTML (html tags are accepted) to show in a tooltip</li>
-     * <li><b>Object</b> : A configuration object for {@link Ext.tip.QuickTipManager#register}.</li>
-     * </ul></div>
+     *
+     * @param {String/Object} tooltip This may be:
+     *
+     *   - **String** : A string to be used as innerHTML (html tags are accepted) to show in a tooltip
+     *   - **Object** : A configuration object for {@link Ext.tip.QuickTipManager#register}.
+     *
      * @return {Ext.button.Button} this
      */
     setTooltip: function(tooltip, initial) {
@@ -23592,7 +24547,7 @@ Ext.define('Ext.button.Button', {
                 tooltip));
                 me.tooltip = tooltip;
             } else {
-                me.btnEl.dom.setAttribute('data-' + this.tooltipType, tooltip);
+                me.btnEl.dom.setAttribute(me.getTipAttr(), tooltip);
             }
         } else {
             me.tooltip = tooltip;
@@ -23600,11 +24555,31 @@ Ext.define('Ext.button.Button', {
         return me;
     },
 
+    /**
+     * Sets the text alignment for this button.
+     * @param {String} align The new alignment of the button text. See {@link #textAlign}.
+     */
+    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';
+    },
+
     // private
     getRefItems: function(deep){
         var menu = this.menu,
             items;
-
+        
         if (menu) {
             items = menu.getRefItems(deep);
             items.unshift(menu);
@@ -23626,9 +24601,10 @@ Ext.define('Ext.button.Button', {
             me.clearTip();
         }
         if (me.menu && me.destroyMenu !== false) {
-            Ext.destroy(me.btnEl, me.btnInnerEl, me.menu);
+            Ext.destroy(me.menu);
         }
-        Ext.destroy(me.repeater);
+        Ext.destroy(me.btnInnerEl, me.repeater);
+        me.callParent();
     },
 
     // private
@@ -23638,10 +24614,8 @@ Ext.define('Ext.button.Button', {
             me.doc.un('mouseover', me.monitorMouseOver, me);
             me.doc.un('mouseup', me.onMouseUp, me);
             delete me.doc;
-            delete me.btnEl;
-            delete me.btnInnerEl;
             Ext.ButtonToggleManager.unregister(me);
-            
+
             Ext.destroy(me.keyMap);
             delete me.keyMap;
         }
@@ -23651,7 +24625,7 @@ Ext.define('Ext.button.Button', {
     /**
      * Assigns this Button's click handler
      * @param {Function} handler The function to call when the button is clicked
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
+     * @param {Object} [scope] The scope (`this` reference) in which the handler function is executed.
      * Defaults to this Button.
      * @return {Ext.button.Button} this
      */
@@ -23678,17 +24652,18 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * Sets the background image (inline style) of the button.  This method also changes
-     * the value of the {@link #icon} config internally.
+     * Sets the background image (inline style) of the button. This method also changes the value of the {@link #icon}
+     * config internally.
      * @param {String} icon The path to an image to display in the button
      * @return {Ext.button.Button} this
      */
     setIcon: function(icon) {
         var me = this,
-            btnInnerEl = me.btnInnerEl;
+            iconEl = me.btnIconEl;
+            
         me.icon = icon;
-        if (btnInnerEl) {
-            btnInnerEl.setStyle('background-image', icon ? 'url(' + icon + ')': '');
+        if (iconEl) {
+            iconEl.setStyle('background-image', icon ? 'url(' + icon + ')': '');
             me.setButtonCls();
         }
         return me;
@@ -23704,13 +24679,13 @@ Ext.define('Ext.button.Button', {
 
     /**
      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
-     * @param {Boolean} state (optional) Force a particular state
-     * @param {Boolean} supressEvent (optional) True to stop events being fired when calling this method.
+     * @param {Boolean} [state] Force a particular state
+     * @param {Boolean} [suppressEvent=false] True to stop events being fired when calling this method.
      * @return {Ext.button.Button} this
      */
     toggle: function(state, suppressEvent) {
         var me = this;
-        state = state === undefined ? !me.pressed: !!state;
+        state = state === undefined ? !me.pressed : !!state;
         if (state !== me.pressed) {
             if (me.rendered) {
                 me[state ? 'addClsWithUI': 'removeClsWithUI'](me.pressedCls);
@@ -23724,14 +24699,21 @@ Ext.define('Ext.button.Button', {
         }
         return me;
     },
+    
+    maybeShowMenu: function(){
+        var me = this;
+        if (me.menu && !me.hasVisibleMenu() && !me.ignoreNextClick) {
+            me.showMenu();
+        }
+    },
 
     /**
-     * Show this button's menu (if it has one)
+     * Shows this button's menu (if it has one)
      */
     showMenu: function() {
         var me = this;
         if (me.rendered && me.menu) {
-            if (me.tooltip) {
+            if (me.tooltip && me.getTipAttr() != 'title') {
                 Ext.tip.QuickTipManager.getQuickTip().cancelShow(me.btnEl);
             }
             if (me.menu.isVisible()) {
@@ -23744,7 +24726,7 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * Hide this button's menu (if it has one)
+     * Hides this button's menu (if it has one)
      */
     hideMenu: function() {
         if (this.hasVisibleMenu()) {
@@ -23777,17 +24759,27 @@ Ext.define('Ext.button.Button', {
             return;
         }
         if (!me.disabled) {
-            if (me.enableToggle && (me.allowDepress !== false || !me.pressed)) {
-                me.toggle();
-            }
-            if (me.menu && !me.hasVisibleMenu() && !me.ignoreNextClick) {
-                me.showMenu();
-            }
-            me.fireEvent('click', me, e);
-            if (me.handler) {
-                me.handler.call(me.scope || me, me, e);
-            }
-            me.onBlur();
+            me.doToggle();
+            me.maybeShowMenu();
+            me.fireHandler(e);
+        }
+    },
+    
+    fireHandler: function(e){
+        var me = this,
+            handler = me.handler;
+            
+        me.fireEvent('click', me, e);
+        if (handler) {
+            handler.call(me.scope || me, me, e);
+        }
+        me.onBlur();
+    },
+    
+    doToggle: function(){
+        var me = this;
+        if (me.enableToggle && (me.allowDepress !== false || !me.pressed)) {
+            me.toggle();
         }
     },
 
@@ -23804,7 +24796,8 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private mouseout handler called when a mouseout event occurs anywhere within the encapsulating element -
+     * @private
+     * mouseout handler called when a mouseout event occurs anywhere within the encapsulating element -
      * or the mouse leaves the encapsulating element.
      * The targets are interrogated to see what is being exited to where.
      * @param e
@@ -23820,7 +24813,8 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private mousemove handler called when the mouse moves anywhere within the encapsulating element.
+     * @private
+     * mousemove handler called when the mouse moves anywhere within the encapsulating element.
      * The position is checked to determine if the mouse is entering or leaving the trigger area. Using
      * mousemove to check this is more resource intensive than we'd like, but it is necessary because
      * the trigger area does not line up exactly with sub-elements so we don't always get mouseover/out
@@ -23855,14 +24849,15 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private Measures the size of the trigger area for menu and split buttons. Will be a width for
+     * @private
+     * Measures the size of the trigger area for menu and split buttons. Will be a width for
      * a right-aligned trigger and a height for a bottom-aligned trigger. Cached after first measurement.
      */
     getTriggerSize: function() {
         var me = this,
             size = me.triggerSize,
             side, sideFirstLetter, undef;
-            
+
         if (size === undef) {
             side = me.arrowAlign;
             sideFirstLetter = side.charAt(0);
@@ -23872,7 +24867,8 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private virtual mouseenter handler called when it is detected that the mouseout event
+     * @private
+     * virtual mouseenter handler called when it is detected that the mouseout event
      * signified the mouse entering the encapsulating element.
      * @param e
      */
@@ -23883,7 +24879,8 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private virtual mouseleave handler called when it is detected that the mouseover event
+     * @private
+     * virtual mouseleave handler called when it is detected that the mouseover event
      * signified the mouse entering the encapsulating element.
      * @param e
      */
@@ -23894,7 +24891,8 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private virtual mouseenter handler called when it is detected that the mouseover event
+     * @private
+     * virtual mouseenter handler called when it is detected that the mouseover event
      * signified the mouse entering the arrow area of the button - the <em>.
      * @param e
      */
@@ -23905,7 +24903,8 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private virtual mouseleave handler called when it is detected that the mouseout event
+     * @private
+     * virtual mouseleave handler called when it is detected that the mouseout event
      * signified the mouse leaving the arrow area of the button - the <em>.
      * @param e
      */
@@ -23914,13 +24913,13 @@ Ext.define('Ext.button.Button', {
         delete me.overMenuTrigger;
         me.fireEvent('menutriggerout', me, me.menu, e);
     },
-    
+
     // inherit docs
     enable : function(silent) {
         var me = this;
 
         me.callParent(arguments);
-        
+
         me.removeClsWithUI('disabled');
 
         return me;
@@ -23929,14 +24928,15 @@ Ext.define('Ext.button.Button', {
     // inherit docs
     disable : function(silent) {
         var me = this;
-        
+
         me.callParent(arguments);
-        
+
         me.addClsWithUI('disabled');
+        me.removeClsWithUI(me.overCls);
 
         return me;
     },
-    
+
     /**
      * Method to change the scale of the button. See {@link #scale} for allowed configurations.
      * @param {String} scale The scale to change to.
@@ -23944,31 +24944,31 @@ Ext.define('Ext.button.Button', {
     setScale: function(scale) {
         var me = this,
             ui = me.ui.replace('-' + me.scale, '');
-        
+
         //check if it is an allowed 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);
     },
-    
+
     // inherit docs
     setUI: function(ui) {
         var me = this;
-        
+
         //we need to append the scale to the UI, if not already done
         if (me.scale && !ui.match(me.scale)) {
             ui = ui + '-' + me.scale;
         }
-        
+
         me.callParent([ui]);
-        
+
         // Set all the state classNames, as they need to include the UI
         // me.disabledCls += ' ' + me.baseCls + '-' + me.ui + '-disabled';
     },
-    
+
     // private
     onFocus: function(e) {
         var me = this;
@@ -24034,9 +25034,10 @@ Ext.define('Ext.button.Button', {
     },
 
     /**
-     * @private Some browsers (notably Safari and older Chromes on Windows) add extra "padding" inside the button
+     * @private
+     * Some browsers (notably Safari and older Chromes on Windows) add extra "padding" inside the button
      * element that cannot be removed. This method returns the size of that padding with a one-time detection.
-     * @return Array [top, right, bottom, left]
+     * @return {Number[]} [top, right, bottom, left]
      */
     getPersistentBtnPadding: function() {
         var cls = Ext.button.Button,
@@ -24071,10 +25072,10 @@ Ext.define('Ext.button.Button', {
     }
 
 }, function() {
-    var groups = {},
-        g, i, l;
+    var groups = {};
 
     function toggleGroup(btn, state) {
+        var g, i, l;
         if (state) {
             g = groups[btn.toggleGroup];
             for (i = 0, l = g.length; i < l; i++) {
@@ -24084,7 +25085,11 @@ Ext.define('Ext.button.Button', {
             }
         }
     }
-    // Private utility class used by Button
+
+    /**
+     * Private utility class used by Button
+     * @hide
+     */
     Ext.ButtonToggleManager = {
         register: function(btn) {
             if (!btn.toggleGroup) {
@@ -24110,10 +25115,10 @@ Ext.define('Ext.button.Button', {
         },
 
         /**
-        * Gets the pressed button in the passed group or null
-        * @param {String} group
-        * @return Button
-        */
+         * Gets the pressed button in the passed group or null
+         * @param {String} group
+         * @return {Ext.button.Button}
+         */
         getPressed: function(group) {
             var g = groups[group],
                 i = 0,
@@ -24406,7 +25411,7 @@ Ext.define('Ext.layout.container.boxOverflow.Menu', {
              */
             me.menuTrigger = Ext.create('Ext.button.Button', {
                 ownerCt : me.layout.owner, // To enable the Menu to ascertain a valid zIndexManager owner in the same tree
-                iconCls : Ext.baseCSSPrefix + layout.owner.getXType() + '-more-icon',
+                iconCls : me.layout.owner.menuTriggerCls,
                 ui      : layout.owner instanceof Ext.toolbar.Toolbar ? 'default-toolbar' : 'default',
                 menu    : me.menu,
                 getSplitCls: function() { return '';},
@@ -24432,7 +25437,7 @@ Ext.define('Ext.layout.container.boxOverflow.Menu', {
      * @private
      * Creates the beforeCt, innerCt and afterCt elements if they have not already been created
      * @param {Ext.container.Container} container The Container attached to this Layout instance
-     * @param {Ext.core.Element} target The target Element
+     * @param {Ext.Element} target The target Element
      */
     createInnerElements: function() {
         var me = this,
@@ -24452,14 +25457,11 @@ Ext.define('Ext.layout.container.boxOverflow.Menu', {
     }
 });
 /**
- * @class Ext.util.Region
- * @extends Object
+ * This class represents a rectangular region in X,Y space, and performs geometric
+ * transformations or tests upon the region.
  *
- * <p>This class represents a rectangular region in X,Y space, and performs geometric
- * transformations or tests upon the region.</p>
- * <p>This class may be used to compare the document regions occupied by elements.</p>
+ * This class may be used to compare the document regions occupied by elements.
  */
-
 Ext.define('Ext.util.Region', {
 
     /* Begin Definitions */
@@ -24470,7 +25472,7 @@ Ext.define('Ext.util.Region', {
         /**
          * @static
          * Retrieves an Ext.util.Region for a particular element.
-         * @param {Mixed} el An element ID, htmlElement or Ext.core.Element representing an element in the document.
+         * @param {String/HTMLElement/Ext.Element} el An element ID, htmlElement or Ext.Element representing an element in the document.
          * @returns {Ext.util.Region} region
          */
         getRegion: function(el) {
@@ -24479,8 +25481,8 @@ Ext.define('Ext.util.Region', {
 
         /**
          * @static
-         * Creates a Region from a "box" Object which contains four numeric properties <code>top</code>, <code>right</code>, <code>bottom</code> and <code>left</code>.
-         * @param {Object} o An object with <code>top</code>, <code>right</code>, <code>bottom</code> and <code>left</code> properties.
+         * Creates a Region from a "box" Object which contains four numeric properties `top`, `right`, `bottom` and `left`.
+         * @param {Object} o An object with `top`, `right`, `bottom` and `left` properties.
          * @return {Ext.util.Region} region The Region constructed based on the passed object
          */
         from: function(o) {
@@ -24508,6 +25510,7 @@ Ext.define('Ext.util.Region', {
     /**
      * Checks if this region completely contains the region that is passed in.
      * @param {Ext.util.Region} region
+     * @return {Boolean}
      */
     contains : function(region) {
         var me = this;
@@ -24541,6 +25544,7 @@ Ext.define('Ext.util.Region', {
     /**
      * Returns the smallest region that contains the current AND targetRegion.
      * @param {Ext.util.Region} region
+     * @return {Ext.util.Region} a new region
      */
     union : function(region) {
         var me = this,
@@ -24555,6 +25559,7 @@ Ext.define('Ext.util.Region', {
     /**
      * Modifies the current region to be constrained to the targetRegion.
      * @param {Ext.util.Region} targetRegion
+     * @return {Ext.util.Region} this
      */
     constrainTo : function(r) {
         var me = this,
@@ -24572,6 +25577,7 @@ Ext.define('Ext.util.Region', {
      * @param {Number} right right offset
      * @param {Number} bottom bottom offset
      * @param {Number} left left offset
+     * @return {Ext.util.Region} this
      */
     adjust : function(t, r, b, l) {
         var me = this;
@@ -24584,8 +25590,8 @@ Ext.define('Ext.util.Region', {
 
     /**
      * Get the offset amount of a point outside the region
-     * @param {String} axis optional
-     * @param {Ext.util.Point} p the point
+     * @param {String} [axis]
+     * @param {Ext.util.Point} [p] the point
      * @return {Ext.util.Offset}
      */
     getOutOfBoundOffset: function(axis, p) {
@@ -24637,8 +25643,8 @@ Ext.define('Ext.util.Region', {
 
     /**
      * Check whether the point / offset is out of bound
-     * @param {String} axis optional
-     * @param {Ext.util.Point/Number} p the point / offset
+     * @param {String} [axis]
+     * @param {Ext.util.Point/Number} [p] the point / offset
      * @return {Boolean}
      */
     isOutOfBound: function(axis, p) {
@@ -24672,12 +25678,13 @@ Ext.define('Ext.util.Region', {
         return (p < this.y || p > this.bottom);
     },
 
-    /*
+    /**
      * Restrict a point within the region by a certain factor.
-     * @param {String} axis Optional
-     * @param {Ext.util.Point/Ext.util.Offset/Object} p
-     * @param {Number} factor
+     * @param {String} [axis]
+     * @param {Ext.util.Point/Ext.util.Offset/Object} [p]
+     * @param {Number} [factor]
      * @return {Ext.util.Point/Ext.util.Offset/Object/Number}
+     * @private
      */
     restrict: function(axis, p, factor) {
         if (Ext.isObject(axis)) {
@@ -24708,11 +25715,12 @@ Ext.define('Ext.util.Region', {
         }
     },
 
-    /*
+    /**
      * Restrict an offset within the region by a certain factor, on the x-axis
      * @param {Number} p
-     * @param {Number} factor The factor, optional, defaults to 1
-     * @return
+     * @param {Number} [factor=1] The factor.
+     * @return {Number}
+     * @private
      */
     restrictX : function(p, factor) {
         if (!factor) {
@@ -24728,10 +25736,12 @@ Ext.define('Ext.util.Region', {
         return p;
     },
 
-    /*
+    /**
      * Restrict an offset within the region by a certain factor, on the y-axis
      * @param {Number} p
-     * @param {Number} factor The factor, optional, defaults to 1
+     * @param {Number} [factor] The factor, defaults to 1
+     * @return {Number}
+     * @private
      */
     restrictY : function(p, factor) {
         if (!factor) {
@@ -24747,9 +25757,10 @@ Ext.define('Ext.util.Region', {
         return p;
     },
 
-    /*
+    /**
      * Get the width / height of this region
      * @return {Object} an object with width and height properties
+     * @private
      */
     getSize: function() {
         return {
@@ -24768,7 +25779,7 @@ Ext.define('Ext.util.Region', {
 
     /**
      * Copy the values of another Region to this Region
-     * @param {Region} The region to copy from.
+     * @param {Ext.util.Region} p The region to copy from.
      * @return {Ext.util.Region} This Region
      */
     copyFrom: function(p) {
@@ -24791,9 +25802,9 @@ Ext.define('Ext.util.Region', {
 
     /**
      * Translate this region by the given offset amount
-     * @param {Ext.util.Offset/Object} offset Object containing the <code>x</code> and <code>y</code> properties.
+     * @param {Ext.util.Offset/Object} x Object containing the `x` and `y` properties.
      * Or the x value is using the two argument form.
-     * @param {Number} The y value unless using an Offset object.
+     * @param {Number} The y value unless using an Offset object.
      * @return {Ext.util.Region} this This Region
      */
     translateBy: function(x, y) {
@@ -24860,7 +25871,7 @@ Ext.define('Ext.dd.DragDropManager', {
 
     // shorter ClassName, to save bytes and use internally
     alternateClassName: ['Ext.dd.DragDropMgr', 'Ext.dd.DDM'],
-    
+
     /**
      * Two dimensional Array of registered DragDrop objects.  The first
      * dimension is the DragDrop item group, the second the DragDrop
@@ -24868,7 +25879,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * @property ids
      * @type String[]
      * @private
-     * @static
      */
     ids: {},
 
@@ -24879,43 +25889,36 @@ Ext.define('Ext.dd.DragDropManager', {
      * @property handleIds
      * @type String[]
      * @private
-     * @static
      */
     handleIds: {},
 
     /**
      * the DragDrop object that is currently being dragged
-     * @property dragCurrent
-     * @type DragDrop
+     * @property {Ext.dd.DragDrop} dragCurrent
      * @private
-     * @static
      **/
     dragCurrent: null,
 
     /**
      * the DragDrop object(s) that are being hovered over
-     * @property dragOvers
-     * @type Array
+     * @property {Ext.dd.DragDrop[]} dragOvers
      * @private
-     * @static
      */
     dragOvers: {},
 
     /**
      * the X distance between the cursor and the object being dragged
      * @property deltaX
-     * @type int
+     * @type Number
      * @private
-     * @static
      */
     deltaX: 0,
 
     /**
      * the Y distance between the cursor and the object being dragged
      * @property deltaY
-     * @type int
+     * @type Number
      * @private
-     * @static
      */
     deltaY: 0,
 
@@ -24924,8 +25927,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * events we define. By default this is true, but this can be set to
      * false if you need the default behavior (not recommended)
      * @property preventDefault
-     * @type boolean
-     * @static
+     * @type Boolean
      */
     preventDefault: true,
 
@@ -24935,8 +25937,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * false if the html element contains other features that require the
      * mouse click.
      * @property stopPropagation
-     * @type boolean
-     * @static
+     * @type Boolean
      */
     stopPropagation: true,
 
@@ -24945,7 +25946,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * intialized
      * @property initialized
      * @private
-     * @static
      */
     initialized: false,
 
@@ -24953,7 +25953,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * All drag and drop can be disabled.
      * @property locked
      * @private
-     * @static
      */
     locked: false,
 
@@ -24961,7 +25960,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * Called the first time an element is registered.
      * @method init
      * @private
-     * @static
      */
     init: function() {
         this.initialized = true;
@@ -24971,8 +25969,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * In point mode, drag and drop interaction is defined by the
      * location of the cursor during the drag/drop
      * @property POINT
-     * @type int
-     * @static
+     * @type Number
      */
     POINT: 0,
 
@@ -24980,16 +25977,14 @@ Ext.define('Ext.dd.DragDropManager', {
      * In intersect mode, drag and drop interaction is defined by the
      * overlap of two or more drag and drop objects.
      * @property INTERSECT
-     * @type int
-     * @static
+     * @type Number
      */
     INTERSECT: 1,
 
     /**
      * The current drag and drop mode.  Default: POINT
      * @property mode
-     * @type int
-     * @static
+     * @type Number
      */
     mode: 0,
 
@@ -24997,7 +25992,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * Runs method on all drag and drop objects
      * @method _execOnAll
      * @private
-     * @static
      */
     _execOnAll: function(sMethod, args) {
         for (var i in this.ids) {
@@ -25015,7 +26009,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * Drag and drop initialization.  Sets up the global event handlers
      * @method _onLoad
      * @private
-     * @static
      */
     _onLoad: function() {
 
@@ -25034,7 +26027,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * Reset constraints on all drag and drop objs
      * @method _onResize
      * @private
-     * @static
      */
     _onResize: function(e) {
         this._execOnAll("resetConstraints", []);
@@ -25043,22 +26035,19 @@ Ext.define('Ext.dd.DragDropManager', {
     /**
      * Lock all drag and drop functionality
      * @method lock
-     * @static
      */
     lock: function() { this.locked = true; },
 
     /**
      * Unlock all drag and drop functionality
      * @method unlock
-     * @static
      */
     unlock: function() { this.locked = false; },
 
     /**
      * Is drag and drop locked?
      * @method isLocked
-     * @return {boolean} True if drag and drop is locked, false otherwise.
-     * @static
+     * @return {Boolean} True if drag and drop is locked, false otherwise.
      */
     isLocked: function() { return this.locked; },
 
@@ -25067,7 +26056,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * initiated, cleared when the drag is finished.
      * @property locationCache
      * @private
-     * @static
      */
     locationCache: {},
 
@@ -25075,8 +26063,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * Set useCache to false if you want to force object the lookup of each
      * drag and drop linked element constantly during a drag.
      * @property useCache
-     * @type boolean
-     * @static
+     * @type Boolean
      */
     useCache: true,
 
@@ -25084,8 +26071,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * The number of pixels that the mouse needs to move after the
      * mousedown before the drag is initiated.  Default=3;
      * @property clickPixelThresh
-     * @type int
-     * @static
+     * @type Number
      */
     clickPixelThresh: 3,
 
@@ -25093,8 +26079,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * The number of milliseconds after the mousedown event to initiate the
      * drag if we don't get a mouseup event. Default=350
      * @property clickTimeThresh
-     * @type int
-     * @static
+     * @type Number
      */
     clickTimeThresh: 350,
 
@@ -25102,9 +26087,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * Flag that indicates that either the drag pixel threshold or the
      * mousdown time threshold has been met
      * @property dragThreshMet
-     * @type boolean
+     * @type Boolean
      * @private
-     * @static
      */
     dragThreshMet: false,
 
@@ -25113,7 +26097,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * @property clickTimeout
      * @type Object
      * @private
-     * @static
      */
     clickTimeout: null,
 
@@ -25121,9 +26104,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * The X position of the mousedown event stored for later use when a
      * drag threshold is met.
      * @property startX
-     * @type int
+     * @type Number
      * @private
-     * @static
      */
     startX: 0,
 
@@ -25131,9 +26113,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * The Y position of the mousedown event stored for later use when a
      * drag threshold is met.
      * @property startY
-     * @type int
+     * @type Number
      * @private
-     * @static
      */
     startY: 0,
 
@@ -25141,9 +26122,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * Each DragDrop instance must be registered with the DragDropManager.
      * This is executed in DragDrop.init()
      * @method regDragDrop
-     * @param {DragDrop} oDD the DragDrop object to register
+     * @param {Ext.dd.DragDrop} oDD the DragDrop object to register
      * @param {String} sGroup the name of the group this element belongs to
-     * @static
      */
     regDragDrop: function(oDD, sGroup) {
         if (!this.initialized) { this.init(); }
@@ -25159,7 +26139,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * by DragDrop.removeFromGroup, so don't call this function directly.
      * @method removeDDFromGroup
      * @private
-     * @static
      */
     removeDDFromGroup: function(oDD, sGroup) {
         if (!this.ids[sGroup]) {
@@ -25177,7 +26156,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * DragDrop.unreg, use that method instead of calling this directly.
      * @method _remove
      * @private
-     * @static
      */
     _remove: function(oDD) {
         for (var g in oDD.groups) {
@@ -25195,7 +26173,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * @param {String} sDDId the DragDrop id this element is a handle for
      * @param {String} sHandleId the id of the element that is the drag
      * handle
-     * @static
      */
     regHandle: function(sDDId, sHandleId) {
         if (!this.handleIds[sDDId]) {
@@ -25209,9 +26186,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * registered as a drag drop item.
      * @method isDragDrop
      * @param {String} id the element id to check
-     * @return {boolean} true if this element is a DragDrop item,
+     * @return {Boolean} true if this element is a DragDrop item,
      * false otherwise
-     * @static
      */
     isDragDrop: function(id) {
         return ( this.getDDById(id) ) ? true : false;
@@ -25221,10 +26197,9 @@ Ext.define('Ext.dd.DragDropManager', {
      * Returns the drag and drop instances that are in all groups the
      * passed in instance belongs to.
      * @method getRelated
-     * @param {DragDrop} p_oDD the obj to get related data for
-     * @param {boolean} bTargetsOnly if true, only return targetable objs
-     * @return {DragDrop[]} the related instances
-     * @static
+     * @param {Ext.dd.DragDrop} p_oDD the obj to get related data for
+     * @param {Boolean} bTargetsOnly if true, only return targetable objs
+     * @return {Ext.dd.DragDrop[]} the related instances
      */
     getRelated: function(p_oDD, bTargetsOnly) {
         var oDDs = [];
@@ -25247,11 +26222,10 @@ Ext.define('Ext.dd.DragDropManager', {
      * Returns true if the specified dd target is a legal target for
      * the specifice drag obj
      * @method isLegalTarget
-     * @param {DragDrop} oDD the drag obj
-     * @param {DragDrop} oTargetDD the target
-     * @return {boolean} true if the target is a legal target for the
+     * @param {Ext.dd.DragDrop} oDD the drag obj
+     * @param {Ext.dd.DragDrop} oTargetDD the target
+     * @return {Boolean} true if the target is a legal target for the
      * dd obj
-     * @static
      */
     isLegalTarget: function (oDD, oTargetDD) {
         var targets = this.getRelated(oDD, true);
@@ -25272,8 +26246,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * evaluates a well-known variable in DragDrop.
      * @method isTypeOfDD
      * @param {Object} the object to evaluate
-     * @return {boolean} true if typeof oDD = DragDrop
-     * @static
+     * @return {Boolean} true if typeof oDD = DragDrop
      */
     isTypeOfDD: function (oDD) {
         return (oDD && oDD.__ygDragDrop);
@@ -25284,9 +26257,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * registered as a drag drop handle for the given Drag Drop object.
      * @method isHandle
      * @param {String} id the element id to check
-     * @return {boolean} true if this element is a DragDrop handle, false
+     * @return {Boolean} true if this element is a DragDrop handle, false
      * otherwise
-     * @static
      */
     isHandle: function(sDDId, sHandleId) {
         return ( this.handleIds[sDDId] &&
@@ -25297,8 +26269,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * Returns the DragDrop instance for a given id
      * @method getDDById
      * @param {String} id the id of the DragDrop object
-     * @return {DragDrop} the drag drop object, null if it is not found
-     * @static
+     * @return {Ext.dd.DragDrop} the drag drop object, null if it is not found
      */
     getDDById: function(id) {
         for (var i in this.ids) {
@@ -25314,9 +26285,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * Sets up the events required to track the object being dragged
      * @method handleMouseDown
      * @param {Event} e the event
-     * @param oDD the DragDrop object being dragged
+     * @param {Ext.dd.DragDrop} oDD the DragDrop object being dragged
      * @private
-     * @static
      */
     handleMouseDown: function(e, oDD) {
         if(Ext.tip.QuickTipManager){
@@ -25327,7 +26297,7 @@ Ext.define('Ext.dd.DragDropManager', {
             // so clean up first to avoid breaking the next drag
             this.handleMouseUp(e);
         }
-        
+
         this.currentTarget = e.getTarget();
         this.dragCurrent = oDD;
 
@@ -25354,9 +26324,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * Fired when either the drag pixel threshol or the mousedown hold
      * time threshold has been met.
      * @method startDrag
-     * @param x {int} the X position of the original mousedown
-     * @param y {int} the Y position of the original mousedown
-     * @static
+     * @param {Number} x the X position of the original mousedown
+     * @param {Number} y the Y position of the original mousedown
      */
     startDrag: function(x, y) {
         clearTimeout(this.clickTimeout);
@@ -25373,11 +26342,10 @@ Ext.define('Ext.dd.DragDropManager', {
      * @method handleMouseUp
      * @param {Event} e the event
      * @private
-     * @static
      */
     handleMouseUp: function(e) {
 
-        if(Ext.tip.QuickTipManager){
+        if(Ext.tip && Ext.tip.QuickTipManager){
             Ext.tip.QuickTipManager.ddEnable();
         }
         if (! this.dragCurrent) {
@@ -25401,7 +26369,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * features are turned on.
      * @method stopEvent
      * @param {Event} e the event as returned by this.getEvent()
-     * @static
      */
     stopEvent: function(e){
         if(this.stopPropagation) {
@@ -25419,7 +26386,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * @method stopDrag
      * @param {Event} e the event
      * @private
-     * @static
      */
     stopDrag: function(e) {
         // Fire the drag end event for the item that was dragged
@@ -25448,7 +26414,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * @method handleMouseMove
      * @param {Event} e the event
      * @private
-     * @static
      */
     handleMouseMove: function(e) {
         if (! this.dragCurrent) {
@@ -25489,9 +26454,8 @@ Ext.define('Ext.dd.DragDropManager', {
      * hovering over or dropping on
      * @method fireEvents
      * @param {Event} e the event
-     * @param {boolean} isDrop is this a drop op or a mouseover op?
+     * @param {Boolean} isDrop is this a drop op or a mouseover op?
      * @private
-     * @static
      */
     fireEvents: function(e, isDrop) {
         var dc = this.dragCurrent;
@@ -25627,10 +26591,9 @@ Ext.define('Ext.dd.DragDropManager', {
      * cursor is over, or the object that has the greatest overlap with
      * the dragged element.
      * @method getBestMatch
-     * @param  {DragDrop[]} dds The array of drag and drop objects
+     * @param  {Ext.dd.DragDrop[]} dds The array of drag and drop objects
      * targeted
-     * @return {DragDrop}       The best single match
-     * @static
+     * @return {Ext.dd.DragDrop}       The best single match
      */
     getBestMatch: function(dds) {
         var winner = null;
@@ -25683,7 +26646,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * method could accept both.
      * @method refreshCache
      * @param {Object} groups an associative array of groups to refresh
-     * @static
      */
     refreshCache: function(groups) {
         for (var sGroup in groups) {
@@ -25716,8 +26678,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * error' when trying to access the offsetParent of such an element
      * @method verifyEl
      * @param {HTMLElement} el the element to check
-     * @return {boolean} true if the element looks usable
-     * @static
+     * @return {Boolean} true if the element looks usable
      */
     verifyEl: function(el) {
         if (el) {
@@ -25741,12 +26702,10 @@ Ext.define('Ext.dd.DragDropManager', {
      * Returns a Region object containing the drag and drop element's position
      * and size, including the padding configured for it
      * @method getLocation
-     * @param {DragDrop} oDD the drag and drop object to get the
-     *                       location for
+     * @param {Ext.dd.DragDrop} oDD the drag and drop object to get the location for.
      * @return {Ext.util.Region} a Region object representing the total area
-     *                             the element occupies, including any padding
-     *                             the instance is configured for.
-     * @static
+     * the element occupies, including any padding
+     * the instance is configured for.
      */
     getLocation: function(oDD) {
         if (! this.isTypeOfDD(oDD)) {
@@ -25762,7 +26721,7 @@ Ext.define('Ext.dd.DragDropManager', {
         var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
 
         try {
-            pos= Ext.core.Element.getXY(el);
+            pos= Ext.Element.getXY(el);
         } catch (e) { }
 
         if (!pos) {
@@ -25786,10 +26745,9 @@ Ext.define('Ext.dd.DragDropManager', {
      * Checks the cursor location to see if it over the target
      * @method isOverTarget
      * @param {Ext.util.Point} pt The point to evaluate
-     * @param {DragDrop} oTarget the DragDrop object we are inspecting
-     * @return {boolean} true if the mouse is over the target
+     * @param {Ext.dd.DragDrop} oTarget the DragDrop object we are inspecting
+     * @return {Boolean} true if the mouse is over the target
      * @private
-     * @static
      */
     isOverTarget: function(pt, oTarget, intersect) {
         // use cache if available
@@ -25845,7 +26803,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * unload event handler
      * @method _onUnload
      * @private
-     * @static
      */
     _onUnload: function(e, me) {
         Ext.dd.DragDropManager.unregAll();
@@ -25855,7 +26812,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * Cleans up the drag and drop events and objects.
      * @method unregAll
      * @private
-     * @static
      */
     unregAll: function() {
 
@@ -25878,7 +26834,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * A cache of DOM elements
      * @property elementCache
      * @private
-     * @static
      */
     elementCache: {},
 
@@ -25886,10 +26841,9 @@ Ext.define('Ext.dd.DragDropManager', {
      * Get the wrapper for the DOM element specified
      * @method getElWrapper
      * @param {String} id the id of the element to get
-     * @return {Ext.dd.DDM.ElementWrapper} the wrapped element
+     * @return {Ext.dd.DragDropManager.ElementWrapper} the wrapped element
      * @private
      * @deprecated This wrapper isn't that useful
-     * @static
      */
     getElWrapper: function(id) {
         var oWrapper = this.elementCache[id];
@@ -25906,7 +26860,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * @param {String} id the id of the elment to get
      * @return {Object} The element
      * @deprecated use Ext.lib.Ext.getDom instead
-     * @static
      */
     getElement: function(id) {
         return Ext.getDom(id);
@@ -25918,7 +26871,6 @@ Ext.define('Ext.dd.DragDropManager', {
      * @method getCss
      * @param {String} id the id of the elment to get
      * @return {Object} The style property of the element
-     * @static
      */
     getCss: function(id) {
         var el = Ext.getDom(id);
@@ -25926,60 +26878,55 @@ Ext.define('Ext.dd.DragDropManager', {
     },
 
     /**
-     * Inner class for cached elements
      * @class Ext.dd.DragDropManager.ElementWrapper
-     * @for DragDropManager
+     * Inner class for cached elements
      * @private
      * @deprecated
      */
     ElementWrapper: function(el) {
-            /**
-             * The element
-             * @property el
-             */
-            this.el = el || null;
-            /**
-             * The element id
-             * @property id
-             */
-            this.id = this.el && el.id;
-            /**
-             * A reference to the style property
-             * @property css
-             */
-            this.css = this.el && el.style;
-        },
+        /**
+         * The element
+         * @property el
+         */
+        this.el = el || null;
+        /**
+         * The element id
+         * @property id
+         */
+        this.id = this.el && el.id;
+        /**
+         * A reference to the style property
+         * @property css
+         */
+        this.css = this.el && el.style;
+    },
+
+    // The DragDropManager class continues
+    /** @class Ext.dd.DragDropManager */
 
     /**
      * Returns the X position of an html element
-     * @method getPosX
-     * @param el the element for which to get the position
-     * @return {int} the X coordinate
-     * @for DragDropManager
-     * @static
+     * @param {HTMLElement} el the element for which to get the position
+     * @return {Number} the X coordinate
      */
     getPosX: function(el) {
-        return Ext.core.Element.getX(el);
+        return Ext.Element.getX(el);
     },
 
     /**
      * Returns the Y position of an html element
-     * @method getPosY
-     * @param el the element for which to get the position
-     * @return {int} the Y coordinate
-     * @static
+     * @param {HTMLElement} el the element for which to get the position
+     * @return {Number} the Y coordinate
      */
     getPosY: function(el) {
-        return Ext.core.Element.getY(el);
+        return Ext.Element.getY(el);
     },
 
     /**
      * Swap two nodes.  In IE, we use the native method, for others we
      * emulate the IE behavior
-     * @method swapNode
-     * @param n1 the first node to swap
-     * @param n2 the other node to swap
-     * @static
+     * @param {HTMLElement} n1 the first node to swap
+     * @param {HTMLElement} n2 the other node to swap
      */
     swapNode: function(n1, n2) {
         if (n1.swapNode) {
@@ -26001,9 +26948,7 @@ Ext.define('Ext.dd.DragDropManager', {
 
     /**
      * Returns the current scroll position
-     * @method getScroll
      * @private
-     * @static
      */
     getScroll: function () {
         var doc   = window.document,
@@ -26011,7 +26956,7 @@ Ext.define('Ext.dd.DragDropManager', {
             body  = doc.body,
             top   = 0,
             left  = 0;
-            
+
         if (Ext.isGecko4) {
             top  = window.scrollYOffset;
             left = window.scrollXOffset;
@@ -26022,7 +26967,7 @@ Ext.define('Ext.dd.DragDropManager', {
             } else if (body) {
                 top  = body.scrollTop;
                 left = body.scrollLeft;
-            } 
+            }
         }
         return {
             top: top,
@@ -26032,11 +26977,9 @@ Ext.define('Ext.dd.DragDropManager', {
 
     /**
      * Returns the specified element style property
-     * @method getStyle
      * @param {HTMLElement} el          the element
-     * @param {string}      styleProp   the style property
-     * @return {string} The value of the style property
-     * @static
+     * @param {String}      styleProp   the style property
+     * @return {String} The value of the style property
      */
     getStyle: function(el, styleProp) {
         return Ext.fly(el).getStyle(styleProp);
@@ -26044,9 +26987,7 @@ Ext.define('Ext.dd.DragDropManager', {
 
     /**
      * Gets the scrollTop
-     * @method getScrollTop
-     * @return {int} the document's scrollTop
-     * @static
+     * @return {Number} the document's scrollTop
      */
     getScrollTop: function () {
         return this.getScroll().top;
@@ -26054,9 +26995,7 @@ Ext.define('Ext.dd.DragDropManager', {
 
     /**
      * Gets the scrollLeft
-     * @method getScrollLeft
-     * @return {int} the document's scrollTop
-     * @static
+     * @return {Number} the document's scrollTop
      */
     getScrollLeft: function () {
         return this.getScroll().left;
@@ -26065,20 +27004,19 @@ Ext.define('Ext.dd.DragDropManager', {
     /**
      * Sets the x/y position of an element to the location of the
      * target element.
-     * @method moveToEl
      * @param {HTMLElement} moveEl      The element to move
      * @param {HTMLElement} targetEl    The position reference element
-     * @static
      */
     moveToEl: function (moveEl, targetEl) {
-        var aCoord = Ext.core.Element.getXY(targetEl);
-        Ext.core.Element.setXY(moveEl, aCoord);
+        var aCoord = Ext.Element.getXY(targetEl);
+        Ext.Element.setXY(moveEl, aCoord);
     },
 
     /**
      * Numeric array sort function
-     * @method numericSort
-     * @static
+     * @param {Number} a
+     * @param {Number} b
+     * @returns {Number} positive, negative or 0
      */
     numericSort: function(a, b) {
         return (a - b);
@@ -26086,18 +27024,15 @@ Ext.define('Ext.dd.DragDropManager', {
 
     /**
      * Internal counter
-     * @property _timeoutCount
+     * @property {Number} _timeoutCount
      * @private
-     * @static
      */
     _timeoutCount: 0,
 
     /**
      * Trying to make the load order less important.  Without this we get
      * an error if this file is loaded before the Event Utility.
-     * @method _addListeners
      * @private
-     * @static
      */
     _addListeners: function() {
         if ( document ) {
@@ -26117,9 +27052,7 @@ Ext.define('Ext.dd.DragDropManager', {
      * Recursively searches the immediate parent and all child nodes for
      * the handle element in order to determine wheter or not it was
      * clicked.
-     * @method handleWasClicked
-     * @param node the html element to inspect
-     * @static
+     * @param {HTMLElement} node the html element to inspect
      */
     handleWasClicked: function(node, id) {
         if (this.isHandle(id, node.id)) {
@@ -26156,7 +27089,7 @@ 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',
@@ -26168,7 +27101,7 @@ Ext.define('Ext.layout.container.Box', {
     /* End Definitions */
 
     /**
-     * @cfg {Mixed} animate
+     * @cfg {Boolean/Number/Object} animate
      * <p>If truthy, child Component are <i>animated</i> into position whenever the Container
      * is layed out. If this option is numeric, it is used as the animation duration in milliseconds.</p>
      * <p>May be set as a property at any time.</p>
@@ -26199,9 +27132,6 @@ Ext.define('Ext.layout.container.Box', {
      * <li>If there are four values, they apply to the top, right, bottom, and
      * left, respectively.</li>
      * </ul></div>
-     * <p>Defaults to:</p><pre><code>
-     * {top:0, right:0, bottom:0, left:0}
-     * </code></pre>
      */
     defaultMargins: {
         top: 0,
@@ -26225,7 +27155,6 @@ Ext.define('Ext.layout.container.Box', {
      * <li>If there are four values, they apply to the top, right, bottom, and
      * left, respectively.</li>
      * </ul></div>
-     * <p>Defaults to: <code>"0"</code></p>
      */
     padding: '0',
     // documented in subclasses
@@ -26264,10 +27193,18 @@ Ext.define('Ext.layout.container.Box', {
     // availableSpaceOffset is used to adjust the availableWidth, typically used
     // to reserve space for a scrollbar
     availableSpaceOffset: 0,
-    
+
     // whether or not to reserve the availableSpaceOffset in layout calculations
     reserveOffset: true,
-    
+
+    /**
+     * @cfg {Boolean} shrinkToFit
+     * True (the default) to allow fixed size components to shrink (limited to their
+     * minimum size) to avoid overflow. False to preserve fixed sizes even if they cause
+     * overflow.
+     */
+    shrinkToFit: true,
+
     /**
      * @cfg {Boolean} clearInnerCtOnLayout
      */
@@ -26304,7 +27241,7 @@ Ext.define('Ext.layout.container.Box', {
     /**
      * @private
      * Returns the current size and positioning of the passed child item.
-     * @param {Component} child The child Component to calculate the box for
+     * @param {Ext.Component} child The child Component to calculate the box for
      * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
      */
     getChildBox: function(child) {
@@ -26321,7 +27258,7 @@ Ext.define('Ext.layout.container.Box', {
     /**
      * @private
      * Calculates the size and positioning of the passed child item.
-     * @param {Component} child The child Component to calculate the box for
+     * @param {Ext.Component} child The child Component to calculate the box for
      * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
      */
     calculateChildBox: function(child) {
@@ -26372,7 +27309,7 @@ Ext.define('Ext.layout.container.Box', {
             availPerpendicularSize = mmax(0, perpendicularSize - paddingPerpendicular),
 
             innerCtBorderWidth = me.innerCt.getBorderWidth(me.perpendicularLT + me.perpendicularRB),
-            
+
             isStart = me.pack == 'start',
             isCenter = me.pack == 'center',
             isEnd = me.pack == 'end',
@@ -26388,16 +27325,21 @@ Ext.define('Ext.layout.container.Box', {
             minSizes = [],
             calculatedWidth,
 
-            i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall, 
-            tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff, 
-            flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset, 
+            i, child, childParallel, childPerpendicular, childMargins, childSize, minParallel, tmpObj, shortfall,
+            tooNarrow, availableSpace, minSize, item, length, itemIndex, box, oldSize, newSize, reduction, diff,
+            flexedBoxes, remainingSpace, remainingFlex, flexedSize, parallelMargins, calcs, offset,
             perpendicularMargins, stretchSize;
 
         //gather the total flex of all flexed items and the width taken up by fixed width items
         for (i = 0; i < visibleCount; i++) {
             child = visibleItems[i];
             childPerpendicular = child[perpendicularPrefix];
-            me.layoutItem(child);
+            if (!child.flex || !(me.align == 'stretch' || me.align == 'stretchmax')) {
+                if (child.componentLayout.initialized !== true) {
+                    me.layoutItem(child);
+                }
+            }
+
             childMargins = child.margins;
             parallelMargins = childMargins[me.parallelBefore] + childMargins[me.parallelAfter];
 
@@ -26433,14 +27375,20 @@ Ext.define('Ext.layout.container.Box', {
             }
 
             // Track the maximum perpendicular size for use by the stretch and stretchmax align config values.
-            maxSize = mmax(maxSize, childPerpendicular + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
+            // Ensure that the tracked maximum perpendicular size takes into account child min[Width|Height] settings!
+            maxSize = mmax(maxSize, mmax(childPerpendicular, child[perpendicularMinString]||0) + childMargins[me.perpendicularLeftTop] + childMargins[me.perpendicularRightBottom]);
 
             tmpObj[parallelPrefix] = childParallel || undefinedValue;
+            tmpObj.dirtySize = child.componentLayout.lastComponentSize ? (tmpObj[parallelPrefix] !== child.componentLayout.lastComponentSize[parallelPrefix]) : false;
             tmpObj[perpendicularPrefix] = childPerpendicular || undefinedValue;
             boxes.push(tmpObj);
         }
-        shortfall = desiredSize - parallelSize;
-        tooNarrow = minimumSize > parallelSize;
+
+        // Only calculate parallel overflow indicators if we are not auto sizing
+        if (!me.autoSize) {
+            shortfall = desiredSize - parallelSize;
+            tooNarrow = minimumSize > parallelSize;
+        }
 
         //the space available to the flexed items
         availableSpace = mmax(0, parallelSize - nonFlexSize - paddingParallel - (me.reserveOffset ? me.availableSpaceOffset : 0));
@@ -26472,8 +27420,7 @@ Ext.define('Ext.layout.container.Box', {
                         box = boxes[i];
                         box.dirtySize = box.dirtySize || box[parallelPrefix] != minSize;
                         box[parallelPrefix] = minSize;
-                    }
-                    else {
+                    } else if (me.shrinkToFit) {
                         minSizes.push({
                             minSize: minSize,
                             available: boxes[i][parallelPrefix] - minSize,
@@ -26509,6 +27456,7 @@ Ext.define('Ext.layout.container.Box', {
                     box[parallelPrefix] = newSize;
                     shortfall -= reduction;
                 }
+                tooNarrow = (shortfall > 0);
             }
             else {
                 remainingSpace = availableSpace;
@@ -26621,7 +27569,7 @@ Ext.define('Ext.layout.container.Box', {
             }
         };
     },
-    
+
     onRemove: function(comp){
         this.callParent(arguments);
         if (this.overflowHandler) {
@@ -26722,10 +27670,12 @@ Ext.define('Ext.layout.container.Box', {
         me.updateChildBoxes(boxes);
         me.handleTargetOverflow(targetSize);
     },
+    
+    animCallback: Ext.emptyFn,
 
     /**
      * Resizes and repositions each child component
-     * @param {Array} boxes The box measurements
+     * @param {Object[]} boxes The box measurements
      */
     updateChildBoxes: function(boxes) {
         var me = this,
@@ -26813,6 +27763,7 @@ Ext.define('Ext.layout.container.Box', {
                 // When we've animated all changed boxes into position, clear our busy flag and call the callback.
                 length -= 1;
                 if (!length) {
+                    me.animCallback(anim);
                     me.layoutBusy = false;
                     if (Ext.isFunction(animCallback)) {
                         animCallback();
@@ -26855,7 +27806,7 @@ Ext.define('Ext.layout.container.Box', {
      * again immediately afterwards, giving a performance hit.
      * Subclasses should provide an implementation.
      * @param {Object} currentSize The current height and width of the innerCt
-     * @param {Array} calculations The new box calculations of all items to be laid out
+     * @param {Object} calculations The new box calculations of all items to be laid out
      */
     updateInnerCtSize: function(tSize, calcs) {
         var me = this,
@@ -26909,7 +27860,7 @@ Ext.define('Ext.layout.container.Box', {
      * target. Having a Box layout inside such a target is therefore not recommended.
      * @param {Object} previousTargetSize The size and height of the layout target before we just laid out
      * @param {Ext.container.Container} container The container
-     * @param {Ext.core.Element} target The target element
+     * @param {Ext.Element} target The target element
      * @return True if the layout overflowed, and was reflowed in a secondary onLayout call.
      */
     handleTargetOverflow: function(previousTargetSize) {
@@ -26975,6 +27926,8 @@ Ext.define('Ext.layout.container.Box', {
         margins.right  += itemEl.getMargin('r');
         margins.bottom += itemEl.getMargin('b');
         margins.left   += itemEl.getMargin('l');
+        margins.height  = margins.top  + margins.bottom;
+        margins.width   = margins.left + margins.right;
         style.marginTop = style.marginRight = style.marginBottom = style.marginLeft = '0';
 
         // Item must reference calculated margins.
@@ -26985,41 +27938,40 @@ Ext.define('Ext.layout.container.Box', {
      * @private
      */
     destroy: function() {
-        Ext.destroy(this.overflowHandler);
+        Ext.destroy(this.innerCt, this.overflowHandler);
         this.callParent(arguments);
     }
 });
 /**
- * @class Ext.layout.container.HBox
- * @extends Ext.layout.container.Box
- * <p>A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
- * space between child items containing a numeric <code>flex</code> configuration.</p>
+ * A layout that arranges items horizontally across a Container. This layout optionally divides available horizontal
+ * space between child items containing a numeric `flex` configuration.
+ *
  * This layout may also be used to set the heights of child items by configuring it with the {@link #align} option.
- * {@img Ext.layout.container.HBox/Ext.layout.container.HBox.png Ext.layout.container.HBox container layout}
- * Example usage:
-    Ext.create('Ext.Panel', {
-        width: 500,
-        height: 300,
-        title: "HBoxLayout Panel",
-        layout: {
-            type: 'hbox',
-            align: 'stretch'
-        },
-        renderTo: document.body,
-        items: [{
-            xtype: 'panel',
-            title: 'Inner Panel One',
-            flex: 2
-        },{
-            xtype: 'panel',
-            title: 'Inner Panel Two',
-            flex: 1
-        },{
-            xtype: 'panel',
-            title: 'Inner Panel Three',
-            flex: 1
-        }]
-    });
+ *
+ *     @example
*     Ext.create('Ext.Panel', {
*         width: 500,
*         height: 300,
*         title: "HBoxLayout Panel",
*         layout: {
*             type: 'hbox',
*             align: 'stretch'
*         },
*         renderTo: document.body,
*         items: [{
*             xtype: 'panel',
*             title: 'Inner Panel One',
*             flex: 2
*         },{
*             xtype: 'panel',
*             title: 'Inner Panel Two',
*             flex: 1
*         },{
*             xtype: 'panel',
*             title: 'Inner Panel Three',
*             flex: 1
*         }]
*     });
  */
 Ext.define('Ext.layout.container.HBox', {
 
@@ -27028,23 +27980,17 @@ Ext.define('Ext.layout.container.HBox', {
     alias: ['layout.hbox'],
     extend: 'Ext.layout.container.Box',
     alternateClassName: 'Ext.layout.HBoxLayout',
-    
+
     /* End Definitions */
 
     /**
      * @cfg {String} align
-     * Controls how the child items of the container are aligned. Acceptable configuration values for this
-     * property are:
-     * <div class="mdetail-params"><ul>
-     * <li><b><tt>top</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned vertically
-     * at the <b>top</b> of the container</div></li>
-     * <li><b><tt>middle</tt></b> : <div class="sub-desc">child items are aligned vertically in the
-     * <b>middle</b> of the container</div></li>
-     * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched vertically to fill
-     * the height of the container</div></li>
-     * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched vertically to
-     * the height of the largest item.</div></li>
-     * </ul></div>
+     * Controls how the child items of the container are aligned. Acceptable configuration values for this property are:
+     *
+     * - **top** : **Default** child items are aligned vertically at the **top** of the container
+     * - **middle** : child items are aligned vertically in the **middle** of the container
+     * - **stretch** : child items are stretched vertically to fill the height of the container
+     * - **stretchmax** : child items are stretched vertically to the height of the largest item.
      */
     align: 'top', // top, middle, stretch, strechmax
 
@@ -27091,39 +28037,40 @@ Ext.define('Ext.layout.container.HBox', {
     }
 });
 /**
- * @class Ext.layout.container.VBox
- * @extends Ext.layout.container.Box
- * <p>A layout that arranges items vertically down a Container. This layout optionally divides available vertical
- * space between child items containing a numeric <code>flex</code> configuration.</p>
+ * A layout that arranges items vertically down a Container. This layout optionally divides available vertical space
+ * between child items containing a numeric `flex` configuration.
+ *
  * This layout may also be used to set the widths of child items by configuring it with the {@link #align} option.
- * {@img Ext.layout.container.VBox/Ext.layout.container.VBox.png Ext.layout.container.VBox container layout}
- * Example usage:
-       Ext.create('Ext.Panel', {
-               width: 500,
-               height: 400,
-               title: "VBoxLayout Panel",
-               layout: {                        
-                       type: 'vbox',
-                       align: 'center'
-               },
-               renderTo: document.body,
-               items: [{                        
-                       xtype: 'panel',
-                       title: 'Inner Panel One',
-                       width: 250,
-                       flex: 2                      
-               },{
-                       xtype: 'panel',
-                       title: 'Inner Panel Two',
-                       width: 250,                     
-                       flex: 4
-               },{
-                       xtype: 'panel',
-                       title: 'Inner Panel Three',
-                       width: '50%',                   
-                       flex: 4
-               }]
-       });
+ *
+ *     @example
+ *     Ext.create('Ext.Panel', {
+ *         width: 500,
+ *         height: 400,
+ *         title: "VBoxLayout Panel",
+ *         layout: {
+ *             type: 'vbox',
+ *             align: 'center'
+ *         },
+ *         renderTo: document.body,
+ *         items: [{
+ *             xtype: 'panel',
+ *             title: 'Inner Panel One',
+ *             width: 250,
+ *             flex: 2
+ *         },
+ *         {
+ *             xtype: 'panel',
+ *             title: 'Inner Panel Two',
+ *             width: 250,
+ *             flex: 4
+ *         },
+ *         {
+ *             xtype: 'panel',
+ *             title: 'Inner Panel Three',
+ *             width: '50%',
+ *             flex: 4
+ *         }]
+ *     });
  */
 Ext.define('Ext.layout.container.VBox', {
 
@@ -27132,23 +28079,17 @@ Ext.define('Ext.layout.container.VBox', {
     alias: ['layout.vbox'],
     extend: 'Ext.layout.container.Box',
     alternateClassName: 'Ext.layout.VBoxLayout',
-    
+
     /* End Definitions */
 
     /**
      * @cfg {String} align
-     * Controls how the child items of the container are aligned. Acceptable configuration values for this
-     * property are:
-     * <div class="mdetail-params"><ul>
-     * <li><b><tt>left</tt></b> : <b>Default</b><div class="sub-desc">child items are aligned horizontally
-     * at the <b>left</b> side of the container</div></li>
-     * <li><b><tt>center</tt></b> : <div class="sub-desc">child items are aligned horizontally at the
-     * <b>mid-width</b> of the container</div></li>
-     * <li><b><tt>stretch</tt></b> : <div class="sub-desc">child items are stretched horizontally to fill
-     * the width of the container</div></li>
-     * <li><b><tt>stretchmax</tt></b> : <div class="sub-desc">child items are stretched horizontally to
-     * the size of the largest item.</div></li>
-     * </ul></div>
+     * Controls how the child items of the container are aligned. Acceptable configuration values for this property are:
+     *
+     * - **left** : **Default** child items are aligned horizontally at the **left** side of the container
+     * - **center** : child items are aligned horizontally at the **mid-width** of the container
+     * - **stretch** : child items are stretched horizontally to fill the width of the container
+     * - **stretchmax** : child items are stretched horizontally to the size of the largest item.
      */
     align : 'left', // left, center, stretch, strechmax
 
@@ -27203,8 +28144,8 @@ The FocusManager is responsible for globally:
 2. Providing basic keyboard navigation
 3. (optional) Provide a visual cue for focused components, in the form of a focus ring/frame.
 
-To activate the FocusManager, simply call {@link #enable `Ext.FocusManager.enable();`}. In turn, you may
-deactivate the FocusManager by subsequently calling {@link #disable `Ext.FocusManager.disable();`}.  The
+To activate the FocusManager, simply call `Ext.FocusManager.enable();`. In turn, you may
+deactivate the FocusManager by subsequently calling `Ext.FocusManager.disable();.  The
 FocusManager is disabled by default.
 
 To enable the optional focus frame, pass `true` or `{focusFrame: true}` to {@link #enable}.
@@ -27215,7 +28156,6 @@ call {@link #subscribe Ext.FocusManager.subscribe} to take advantage of this fea
 {@link #unsubscribe Ext.FocusManager.unsubscribe} to turn the navigation off.
 
  * @singleton
- * @markdown
  * @author Jarred Nicholls <jarred@sencha.com>
  * @docauthor Jarred Nicholls <jarred@sencha.com>
  */
@@ -27243,7 +28183,6 @@ Ext.define('Ext.FocusManager', {
     /**
      * @property {Ext.Component} focusedCmp
      * The currently focused component. Defaults to `undefined`.
-     * @markdown
      */
 
     focusElementCls: Ext.baseCSSPrefix + 'focus-element',
@@ -27251,7 +28190,7 @@ Ext.define('Ext.FocusManager', {
     focusFrameCls: Ext.baseCSSPrefix + 'focus-frame',
 
     /**
-     * @property {Array} whitelist
+     * @property {String[]} whitelist
      * A list of xtypes that should ignore certain navigation input keys and
      * allow for the default browser event/behavior. These input keys include:
      *
@@ -27265,9 +28204,6 @@ Ext.define('Ext.FocusManager', {
      * The FocusManager will not attempt to navigate when a component is an xtype (or descendents thereof)
      * that belongs to this whitelist. E.g., an {@link Ext.form.field.Text} should allow
      * the user to move the input cursor left and right, and to delete characters, etc.
-     *
-     * This whitelist currently defaults to `['textfield']`.
-     * @markdown
      */
     whitelist: [
         'textfield'
@@ -27299,7 +28235,6 @@ Ext.define('Ext.FocusManager', {
              * @param {Ext.Component} cmp The component that is being focused
              * @param {Ext.Component} previousCmp The component that was previously focused,
              * or `undefined` if there was no previously focused component.
-             * @markdown
              */
             'beforecomponentfocus',
 
@@ -27310,7 +28245,6 @@ Ext.define('Ext.FocusManager', {
              * @param {Ext.Component} cmp The component that has been focused
              * @param {Ext.Component} previousCmp The component that was previously focused,
              * or `undefined` if there was no previously focused component.
-             * @markdown
              */
             'componentfocus',
 
@@ -27424,7 +28358,7 @@ Ext.define('Ext.FocusManager', {
 
     /**
      * Adds the specified xtype to the {@link #whitelist}.
-     * @param {String/Array} xtype Adds the xtype(s) to the {@link #whitelist}.
+     * @param {String/String[]} xtype Adds the xtype(s) to the {@link #whitelist}.
      */
     addXTypeToWhitelist: function(xtype) {
         var me = this;
@@ -27569,8 +28503,8 @@ Ext.define('Ext.FocusManager', {
                 ],
                 style: 'top: -100px; left: -100px;'
             });
-            me.focusFrame.setVisibilityMode(Ext.core.Element.DISPLAY);
-            me.focusFrameWidth = me.focusFrame.child('.' + cls + '-top').getHeight();
+            me.focusFrame.setVisibilityMode(Ext.Element.DISPLAY);
+            me.focusFrameWidth = 2;
             me.focusFrame.hide().setLeftTop(0, 0);
         }
     },
@@ -27742,10 +28676,10 @@ Ext.define('Ext.FocusManager', {
                 fl = ff.child(cls + 'left'),
                 fr = ff.child(cls + 'right');
 
-            ft.setWidth(bw - 2).setLeftTop(bl + 1, bt);
-            fb.setWidth(bw - 2).setLeftTop(bl + 1, bt + bh - fw);
-            fl.setHeight(bh - 2).setLeftTop(bl, bt + 1);
-            fr.setHeight(bh - 2).setLeftTop(bl + bw - fw, bt + 1);
+            ft.setWidth(bw).setLeftTop(bl, bt);
+            fb.setWidth(bw).setLeftTop(bl, bt + bh - fw);
+            fl.setHeight(bh - fw - fw).setLeftTop(bl, bt + fw);
+            fr.setHeight(bh - fw - fw).setLeftTop(bl + bw - fw, bt + fw);
 
             ff.show();
         }
@@ -27799,7 +28733,7 @@ Ext.define('Ext.FocusManager', {
 
     /**
      * Removes the specified xtype from the {@link #whitelist}.
-     * @param {String/Array} xtype Removes the xtype(s) from the {@link #whitelist}.
+     * @param {String/String[]} xtype Removes the xtype(s) from the {@link #whitelist}.
      */
     removeXTypeFromWhitelist: function(xtype) {
         var me = this;
@@ -27949,26 +28883,25 @@ Ext.define('Ext.FocusManager', {
     /**
      * Subscribes an {@link Ext.container.Container} to provide basic keyboard focus navigation between its child {@link Ext.Component}'s.
      * @param {Ext.container.Container} container A reference to the {@link Ext.container.Container} on which to enable keyboard functionality and focus management.
-     * @param {Boolean/Object} options An object of the following options:
-        - keys : Array/Object
-            An array containing the string names of navigation keys to be supported. The allowed values are:
-
-            - 'left'
-            - 'right'
-            - 'up'
-            - 'down'
-
-            Or, an object containing those key names as keys with `true` or a callback function as their value. A scope may also be passed. E.g.:
-
-                {
-                    left: this.onLeftKey,
-                    right: this.onRightKey,
-                    scope: this
-                }
-
-        - focusFrame : Boolean (optional)
-            `true` to show the focus frame around a component when it is focused. Defaults to `false`.
-     * @markdown
+     * @param {Boolean/Object} options An object of the following options
+     * @param {Array/Object} options.keys
+     * An array containing the string names of navigation keys to be supported. The allowed values are:
+     *
+     *   - 'left'
+     *   - 'right'
+     *   - 'up'
+     *   - 'down'
+     *
+     * Or, an object containing those key names as keys with `true` or a callback function as their value. A scope may also be passed. E.g.:
+     *
+     *     {
+     *         left: this.onLeftKey,
+     *         right: this.onRightKey,
+     *         scope: this
+     *     }
+     *
+     * @param {Boolean} options.focusFrame
+     * `true` to show the focus frame around a component when it is focused. Defaults to `false`.
      */
     subscribe: function(container, options) {
         var me = this,
@@ -28024,7 +28957,6 @@ Ext.define('Ext.FocusManager', {
     /**
      * Unsubscribes an {@link Ext.container.Container} from keyboard focus management.
      * @param {Ext.container.Container} container A reference to the {@link Ext.container.Container} to unsubscribe from the FocusManager.
-     * @markdown
      */
     unsubscribe: function(container) {
         var me = this,
@@ -28058,199 +28990,189 @@ Ext.define('Ext.FocusManager', {
     }
 });
 /**
- * @class Ext.toolbar.Toolbar
- * @extends Ext.container.Container
-
-Basic Toolbar class. Although the {@link Ext.container.Container#defaultType defaultType} for Toolbar is {@link Ext.button.Button button}, Toolbar 
-elements (child items for the Toolbar container) may be virtually any type of Component. Toolbar elements can be created explicitly via their 
-constructors, or implicitly via their xtypes, and can be {@link #add}ed dynamically.
-
-__Some items have shortcut strings for creation:__
-
-| Shortcut | xtype         | Class                         | Description                                        |
-|:---------|:--------------|:------------------------------|:---------------------------------------------------|
-| `->`     | `tbspacer`    | {@link Ext.toolbar.Fill}      | begin using the right-justified button container   |
-| `-`      | `tbseparator` | {@link Ext.toolbar.Separator} | add a vertical separator bar between toolbar items |
-| ` `      | `tbspacer`    | {@link Ext.toolbar.Spacer}    | add horiztonal space between elements              |
-
-{@img Ext.toolbar.Toolbar/Ext.toolbar.Toolbar1.png Toolbar component}
-Example usage:
-
-    Ext.create('Ext.toolbar.Toolbar', {
-        renderTo: document.body,
-        width   : 500,
-        items: [
-            {
-                // xtype: 'button', // default for Toolbars
-                text: 'Button'
-            },
-            {
-                xtype: 'splitbutton',
-                text : 'Split Button'
-            },
-            // begin using the right-justified button container
-            '->', // same as {xtype: 'tbfill'}, // Ext.toolbar.Fill
-            {
-                xtype    : 'textfield',
-                name     : 'field1',
-                emptyText: 'enter search term'
-            },
-            // add a vertical separator bar between toolbar items
-            '-', // same as {xtype: 'tbseparator'} to create Ext.toolbar.Separator
-            'text 1', // same as {xtype: 'tbtext', text: 'text1'} to create Ext.toolbar.TextItem
-            {xtype: 'tbspacer'},// same as ' ' to create Ext.toolbar.Spacer
-            'text 2',
-            {xtype: 'tbspacer', width: 50}, // add a 50px space
-            'text 3'
-        ]
-    });
-
-Toolbars have {@link #enable} and {@link #disable} methods which when called, will enable/disable all items within your toolbar.
-
-{@img Ext.toolbar.Toolbar/Ext.toolbar.Toolbar2.png Toolbar component}
-Example usage:
-
-    Ext.create('Ext.toolbar.Toolbar', {
-        renderTo: document.body,
-        width   : 400,
-        items: [
-            {
-                text: 'Button'
-            },
-            {
-                xtype: 'splitbutton',
-                text : 'Split Button'
-            },
-            '->',
-            {
-                xtype    : 'textfield',
-                name     : 'field1',
-                emptyText: 'enter search term'
-            }
-        ]
-    });
-
-{@img Ext.toolbar.Toolbar/Ext.toolbar.Toolbar3.png Toolbar component}
-Example usage:
-    
-    var enableBtn = Ext.create('Ext.button.Button', {
-        text    : 'Enable All Items',
-        disabled: true,
-        scope   : this,
-        handler : function() {
-            //disable the enable button and enable the disable button
-            enableBtn.disable();
-            disableBtn.enable();
-            
-            //enable the toolbar
-            toolbar.enable();
-        }
-    });
-    
-    var disableBtn = Ext.create('Ext.button.Button', {
-        text    : 'Disable All Items',
-        scope   : this,
-        handler : function() {
-            //enable the enable button and disable button
-            disableBtn.disable();
-            enableBtn.enable();
-            
-            //disable the toolbar
-            toolbar.disable();
-        }
-    });
-    
-    var toolbar = Ext.create('Ext.toolbar.Toolbar', {
-        renderTo: document.body,
-        width   : 400,
-        margin  : '5 0 0 0',
-        items   : [enableBtn, disableBtn]
-    });
-
-Adding items to and removing items from a toolbar is as simple as calling the {@link #add} and {@link #remove} methods. There is also a {@link #removeAll} method 
-which remove all items within the toolbar.
-
-{@img Ext.toolbar.Toolbar/Ext.toolbar.Toolbar4.png Toolbar component}
-Example usage:
-
-    var toolbar = Ext.create('Ext.toolbar.Toolbar', {
-        renderTo: document.body,
-        width   : 700,
-        items: [
-            {
-                text: 'Example Button'
-            }
-        ]
-    });
-    
-    var addedItems = [];
-    
-    Ext.create('Ext.toolbar.Toolbar', {
-        renderTo: document.body,
-        width   : 700,
-        margin  : '5 0 0 0',
-        items   : [
-            {
-                text   : 'Add a button',
-                scope  : this,
-                handler: function() {
-                    var text = prompt('Please enter the text for your button:');
-                    addedItems.push(toolbar.add({
-                        text: text
-                    }));
-                }
-            },
-            {
-                text   : 'Add a text item',
-                scope  : this,
-                handler: function() {
-                    var text = prompt('Please enter the text for your item:');
-                    addedItems.push(toolbar.add(text));
-                }
-            },
-            {
-                text   : 'Add a toolbar seperator',
-                scope  : this,
-                handler: function() {
-                    addedItems.push(toolbar.add('-'));
-                }
-            },
-            {
-                text   : 'Add a toolbar spacer',
-                scope  : this,
-                handler: function() {
-                    addedItems.push(toolbar.add('->'));
-                }
-            },
-            '->',
-            {
-                text   : 'Remove last inserted item',
-                scope  : this,
-                handler: function() {
-                    if (addedItems.length) {
-                        toolbar.remove(addedItems.pop());
-                    } else if (toolbar.items.length) {
-                        toolbar.remove(toolbar.items.last());
-                    } else {
-                        alert('No items in the toolbar');
-                    }
-                }
-            },
-            {
-                text   : 'Remove all items',
-                scope  : this,
-                handler: function() {
-                    toolbar.removeAll();
-                }
-            }
-        ]
-    });
-
+ * Basic Toolbar class. Although the {@link Ext.container.Container#defaultType defaultType} for Toolbar is {@link Ext.button.Button button}, Toolbar
+ * elements (child items for the Toolbar container) may be virtually any type of Component. Toolbar elements can be created explicitly via their
+ * constructors, or implicitly via their xtypes, and can be {@link #add}ed dynamically.
+ *
+ * ## Some items have shortcut strings for creation:
+ *
+ * | Shortcut | xtype         | Class                         | Description
+ * |:---------|:--------------|:------------------------------|:---------------------------------------------------
+ * | `->`     | `tbfill`      | {@link Ext.toolbar.Fill}      | begin using the right-justified button container
+ * | `-`      | `tbseparator` | {@link Ext.toolbar.Separator} | add a vertical separator bar between toolbar items
+ * | ` `      | `tbspacer`    | {@link Ext.toolbar.Spacer}    | add horiztonal space between elements
+ *
+ *     @example
+ *     Ext.create('Ext.toolbar.Toolbar', {
+ *         renderTo: document.body,
+ *         width   : 500,
+ *         items: [
+ *             {
+ *                 // xtype: 'button', // default for Toolbars
+ *                 text: 'Button'
+ *             },
+ *             {
+ *                 xtype: 'splitbutton',
+ *                 text : 'Split Button'
+ *             },
+ *             // begin using the right-justified button container
+ *             '->', // same as { xtype: 'tbfill' }
+ *             {
+ *                 xtype    : 'textfield',
+ *                 name     : 'field1',
+ *                 emptyText: 'enter search term'
+ *             },
+ *             // add a vertical separator bar between toolbar items
+ *             '-', // same as {xtype: 'tbseparator'} to create Ext.toolbar.Separator
+ *             'text 1', // same as {xtype: 'tbtext', text: 'text1'} to create Ext.toolbar.TextItem
+ *             { xtype: 'tbspacer' },// same as ' ' to create Ext.toolbar.Spacer
+ *             'text 2',
+ *             { xtype: 'tbspacer', width: 50 }, // add a 50px space
+ *             'text 3'
+ *         ]
+ *     });
+ *
+ * Toolbars have {@link #enable} and {@link #disable} methods which when called, will enable/disable all items within your toolbar.
+ *
+ *     @example
+ *     Ext.create('Ext.toolbar.Toolbar', {
+ *         renderTo: document.body,
+ *         width   : 400,
+ *         items: [
+ *             {
+ *                 text: 'Button'
+ *             },
+ *             {
+ *                 xtype: 'splitbutton',
+ *                 text : 'Split Button'
+ *             },
+ *             '->',
+ *             {
+ *                 xtype    : 'textfield',
+ *                 name     : 'field1',
+ *                 emptyText: 'enter search term'
+ *             }
+ *         ]
+ *     });
+ *
+ * Example
+ *
+ *     @example
+ *     var enableBtn = Ext.create('Ext.button.Button', {
+ *         text    : 'Enable All Items',
+ *         disabled: true,
+ *         scope   : this,
+ *         handler : function() {
+ *             //disable the enable button and enable the disable button
+ *             enableBtn.disable();
+ *             disableBtn.enable();
+ *
+ *             //enable the toolbar
+ *             toolbar.enable();
+ *         }
+ *     });
+ *
+ *     var disableBtn = Ext.create('Ext.button.Button', {
+ *         text    : 'Disable All Items',
+ *         scope   : this,
+ *         handler : function() {
+ *             //enable the enable button and disable button
+ *             disableBtn.disable();
+ *             enableBtn.enable();
+ *
+ *             //disable the toolbar
+ *             toolbar.disable();
+ *         }
+ *     });
+ *
+ *     var toolbar = Ext.create('Ext.toolbar.Toolbar', {
+ *         renderTo: document.body,
+ *         width   : 400,
+ *         margin  : '5 0 0 0',
+ *         items   : [enableBtn, disableBtn]
+ *     });
+ *
+ * Adding items to and removing items from a toolbar is as simple as calling the {@link #add} and {@link #remove} methods. There is also a {@link #removeAll} method
+ * which remove all items within the toolbar.
+ *
+ *     @example
+ *     var toolbar = Ext.create('Ext.toolbar.Toolbar', {
+ *         renderTo: document.body,
+ *         width   : 700,
+ *         items: [
+ *             {
+ *                 text: 'Example Button'
+ *             }
+ *         ]
+ *     });
+ *
+ *     var addedItems = [];
+ *
+ *     Ext.create('Ext.toolbar.Toolbar', {
+ *         renderTo: document.body,
+ *         width   : 700,
+ *         margin  : '5 0 0 0',
+ *         items   : [
+ *             {
+ *                 text   : 'Add a button',
+ *                 scope  : this,
+ *                 handler: function() {
+ *                     var text = prompt('Please enter the text for your button:');
+ *                     addedItems.push(toolbar.add({
+ *                         text: text
+ *                     }));
+ *                 }
+ *             },
+ *             {
+ *                 text   : 'Add a text item',
+ *                 scope  : this,
+ *                 handler: function() {
+ *                     var text = prompt('Please enter the text for your item:');
+ *                     addedItems.push(toolbar.add(text));
+ *                 }
+ *             },
+ *             {
+ *                 text   : 'Add a toolbar seperator',
+ *                 scope  : this,
+ *                 handler: function() {
+ *                     addedItems.push(toolbar.add('-'));
+ *                 }
+ *             },
+ *             {
+ *                 text   : 'Add a toolbar spacer',
+ *                 scope  : this,
+ *                 handler: function() {
+ *                     addedItems.push(toolbar.add('->'));
+ *                 }
+ *             },
+ *             '->',
+ *             {
+ *                 text   : 'Remove last inserted item',
+ *                 scope  : this,
+ *                 handler: function() {
+ *                     if (addedItems.length) {
+ *                         toolbar.remove(addedItems.pop());
+ *                     } else if (toolbar.items.length) {
+ *                         toolbar.remove(toolbar.items.last());
+ *                     } else {
+ *                         alert('No items in the toolbar');
+ *                     }
+ *                 }
+ *             },
+ *             {
+ *                 text   : 'Remove all items',
+ *                 scope  : this,
+ *                 handler: function() {
+ *                     toolbar.removeAll();
+ *                 }
+ *             }
+ *         ]
+ *     });
+ *
  * @constructor
  * Creates a new Toolbar
- * @param {Object/Array} config A config object or an array of buttons to <code>{@link #add}</code>
+ * @param {Object/Object[]} config A config object or an array of buttons to <code>{@link #add}</code>
  * @docauthor Robert Dougan <rob@sencha.com>
- * @markdown
  */
 Ext.define('Ext.toolbar.Toolbar', {
     extend: 'Ext.container.Container',
@@ -28265,24 +29187,23 @@ Ext.define('Ext.toolbar.Toolbar', {
     ],
     alias: 'widget.toolbar',
     alternateClassName: 'Ext.Toolbar',
-    
+
     isToolbar: true,
     baseCls  : Ext.baseCSSPrefix + 'toolbar',
     ariaRole : 'toolbar',
-    
+
     defaultType: 'button',
-    
+
     /**
      * @cfg {Boolean} vertical
      * Set to `true` to make the toolbar vertical. The layout will become a `vbox`.
-     * (defaults to `false`)
      */
     vertical: false,
 
     /**
      * @cfg {String/Object} layout
-     * This class assigns a default layout (<code>layout:'<b>hbox</b>'</code>).
-     * Developers <i>may</i> override this configuration option if another layout
+     * This class assigns a default layout (`layout: 'hbox'`).
+     * Developers _may_ override this configuration option if another layout
      * is required (the constructor must be passed a configuration object in this
      * case instead of an array).
      * See {@link Ext.container.Container#layout} for additional information.
@@ -28290,16 +29211,22 @@ Ext.define('Ext.toolbar.Toolbar', {
 
     /**
      * @cfg {Boolean} enableOverflow
-     * Defaults to false. Configure <code>true</code> to make the toolbar provide a button
-     * which activates a dropdown Menu to show items which overflow the Toolbar's width.
+     * Configure true to make the toolbar provide a button which activates a dropdown Menu to show
+     * items which overflow the Toolbar's width.
      */
     enableOverflow: false,
+
+    /**
+     * @cfg {String} menuTriggerCls
+     * Configure the icon class of the overflow button.
+     */
+    menuTriggerCls: Ext.baseCSSPrefix + 'toolbar-more-icon',
     
     // private
     trackMenus: true,
-    
+
     itemCls: Ext.baseCSSPrefix + 'toolbar-item',
-    
+
     initComponent: function() {
         var me = this,
             keys;
@@ -28308,7 +29235,7 @@ Ext.define('Ext.toolbar.Toolbar', {
         if (!me.layout && me.enableOverflow) {
             me.layout = { overflowHandler: 'Menu' };
         }
-        
+
         if (me.dock === 'right' || me.dock === 'left') {
             me.vertical = true;
         }
@@ -28320,16 +29247,16 @@ Ext.define('Ext.toolbar.Toolbar', {
             align: me.vertical ? 'stretchmax' : 'middle',
             clearInnerCtOnLayout: true
         });
-        
+
         if (me.vertical) {
             me.addClsWithUI('vertical');
         }
-        
+
         // @TODO: remove this hack and implement a more general solution
         if (me.ui === 'footer') {
             me.ignoreBorderManagement = true;
         }
-        
+
         me.callParent();
 
         /**
@@ -28339,7 +29266,7 @@ Ext.define('Ext.toolbar.Toolbar', {
          * @param {Boolean} lastOverflow overflow state
          */
         me.addEvents('overflowchange');
-        
+
         // Subscribe to Ext.FocusManager for key navigation
         keys = me.vertical ? ['up', 'down'] : ['left', 'right'];
         Ext.FocusManager.subscribe(me, {
@@ -28347,24 +29274,38 @@ Ext.define('Ext.toolbar.Toolbar', {
         });
     },
 
+    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;
+    },
+
     /**
-     * <p>Adds element(s) to the toolbar -- this function takes a variable number of
-     * arguments of mixed type and adds them to the toolbar.</p>
-     * <br><p><b>Note</b>: See the notes within {@link Ext.container.Container#add}.</p>
-     * @param {Mixed} arg1 The following types of arguments are all valid:<br />
-     * <ul>
-     * <li>{@link Ext.button.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
-     * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
-     * <li>Field: Any form field (equivalent to {@link #addField})</li>
-     * <li>Item: Any subclass of {@link Ext.toolbar.Item} (equivalent to {@link #addItem})</li>
-     * <li>String: Any generic string (gets wrapped in a {@link Ext.toolbar.TextItem}, equivalent to {@link #addText}).
-     * Note that there are a few special strings that are treated differently as explained next.</li>
-     * <li>'-': Creates a separator element (equivalent to {@link #addSeparator})</li>
-     * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
-     * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
-     * </ul>
-     * @param {Mixed} arg2
-     * @param {Mixed} etc.
+     * Adds element(s) to the toolbar -- this function takes a variable number of
+     * arguments of mixed type and adds them to the toolbar.
+     *
+     * **Note**: See the notes within {@link Ext.container.Container#add}.
+     *
+     * @param {Object...} args The following types of arguments are all valid:
+     *  - `{@link Ext.button.Button config}`: A valid button config object
+     *  - `HtmlElement`: Any standard HTML element
+     *  - `Field`: Any form field
+     *  - `Item`: Any subclass of {@link Ext.toolbar.Item}
+     *  - `String`: Any generic string (gets wrapped in a {@link Ext.toolbar.TextItem}).
+     *  Note that there are a few special strings that are treated differently as explained next.
+     *  - `'-'`: Creates a separator element
+     *  - `' '`: Creates a spacer element
+     *  - `'->'`: Creates a fill element
+     *
      * @method add
      */
 
@@ -28408,7 +29349,7 @@ Ext.define('Ext.toolbar.Toolbar', {
             var method = remove ? 'mun' : 'mon',
                 me = this;
 
-            me[method](item, 'menutriggerover', me.onButtonTriggerOver, me);
+            me[method](item, 'mouseover', me.onButtonOver, me);
             me[method](item, 'menushow', me.onButtonMenuShow, me);
             me[method](item, 'menuhide', me.onButtonMenuHide, me);
         }
@@ -28424,12 +29365,12 @@ Ext.define('Ext.toolbar.Toolbar', {
         if (component.is('field') || (component.is('button') && this.ui != 'footer')) {
             component.ui = component.ui + '-toolbar';
         }
-        
+
         // Any separators needs to know if is vertical or not
         if (component instanceof Ext.toolbar.Separator) {
             component.setUI((this.vertical) ? 'vertical' : 'horizontal');
         }
-        
+
         this.callParent(arguments);
     },
 
@@ -28450,7 +29391,7 @@ Ext.define('Ext.toolbar.Toolbar', {
     },
 
     // private
-    onButtonTriggerOver: function(btn){
+    onButtonOver: function(btn){
         if (this.activeMenuBtn && this.activeMenuBtn != btn) {
             this.activeMenuBtn.hideMenu();
             btn.showMenu();
@@ -28477,8 +29418,8 @@ Ext.define('Ext.toolbar.Toolbar', {
 /**
  * @class Ext.panel.AbstractPanel
  * @extends Ext.container.Container
- * <p>A base class which provides methods common to Panel classes across the Sencha product range.</p>
- * <p>Please refer to sub class's documentation</p>
+ * A base class which provides methods common to Panel classes across the Sencha product range.
+ * @private
  */
 Ext.define('Ext.panel.AbstractPanel', {
 
@@ -28486,13 +29427,13 @@ Ext.define('Ext.panel.AbstractPanel', {
 
     extend: 'Ext.container.Container',
 
-    requires: ['Ext.util.MixedCollection', 'Ext.core.Element', 'Ext.toolbar.Toolbar'],
+    requires: ['Ext.util.MixedCollection', 'Ext.Element', 'Ext.toolbar.Toolbar'],
 
     /* End Definitions */
 
     /**
-     * @cfg {String} baseCls
-     * The base CSS class to apply to this panel's element (defaults to <code>'x-panel'</code>).
+     * @cfg {String} [baseCls='x-panel']
+     * The base CSS class to apply to this panel's element.
      */
     baseCls : Ext.baseCSSPrefix + 'panel',
 
@@ -28500,13 +29441,12 @@ Ext.define('Ext.panel.AbstractPanel', {
      * @cfg {Number/String} bodyPadding
      * A shortcut for setting a padding style on the body element. The value can either be
      * a number to be applied to all sides, or a normal css string describing padding.
-     * Defaults to <code>undefined</code>.
      */
 
     /**
      * @cfg {Boolean} bodyBorder
-     * A shortcut to add or remove the border on the body of a panel. This only applies to a panel which has the {@link #frame} configuration set to `true`.
-     * Defaults to <code>undefined</code>.
+     * A shortcut to add or remove the border on the body of a panel. This only applies to a panel
+     * which has the {@link #frame} configuration set to `true`.
      */
 
     /**
@@ -28524,7 +29464,7 @@ bodyStyle: {
      */
 
     /**
-     * @cfg {String/Array} bodyCls
+     * @cfg {String/String[]} bodyCls
      * A CSS class, space-delimited string of classes, or array of classes to be applied to the panel's body element.
      * The following examples are all valid:<pre><code>
 bodyCls: 'foo'
@@ -28542,7 +29482,7 @@ bodyCls: ['foo', 'bar']
      * This object holds the default weights applied to dockedItems that have no weight. These start with a
      * weight of 1, to allow negative weights to insert before top items and are odd numbers
      * so that even weights can be used to get between different dock orders.
-     * 
+     *
      * To make default docking order match border layout, do this:
      * <pre><code>
 Ext.panel.AbstractPanel.prototype.defaultDockWeights = { top: 1, bottom: 3, left: 5, right: 7 };</code></pre>
@@ -28567,11 +29507,17 @@ initComponent: function () {
      */
     defaultDockWeights: { top: 1, left: 3, right: 5, bottom: 7 },
 
-    renderTpl: ['<div 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>></div>'],
+    renderTpl: [
+        '<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>>',
+        '</div>'
+    ],
 
     // TODO: Move code examples into product-specific files. The code snippet below is Touch only.
     /**
-     * @cfg {Object/Array} dockedItems
+     * @cfg {Object/Object[]} dockedItems
      * A component or series of components to be added as docked items to this panel.
      * The docked items can be docked to either the top, right, left or bottom of a panel.
      * This is typically used for things like toolbars or tab bars:
@@ -28608,9 +29554,7 @@ var panel = new Ext.panel.Panel({
             // 'deactivate'
         );
 
-        Ext.applyIf(me.renderSelectors, {
-            body: '.' + me.baseCls + '-body'
-        });
+        me.addChildEls('body');
 
         //!frame
         //!border
@@ -28651,7 +29595,7 @@ var panel = new Ext.panel.Panel({
 
     /**
      * Attempts a default component lookup (see {@link Ext.container.Container#getComponent}). If the component is not found in the normal
-     * items, the dockedItems are searched and the matched component (if any) returned (see {@loink #getDockedComponent}). Note that docked
+     * items, the dockedItems are searched and the matched component (if any) returned (see {@link #getDockedComponent}). Note that docked
      * items will only be matched by component id or itemId -- if you pass a numeric index only non-docked child components will be searched.
      * @param {String/Number} comp The component id, itemId or position to find
      * @return {Ext.Component} The component (if found)
@@ -28675,7 +29619,7 @@ var panel = new Ext.panel.Panel({
         var me = this,
             bodyStyle = me.bodyStyle,
             styles = [],
-            Element = Ext.core.Element,
+            Element = Ext.Element,
             prop;
 
         if (Ext.isFunction(bodyStyle)) {
@@ -28738,7 +29682,7 @@ var panel = new Ext.panel.Panel({
 
     /**
      * Adds docked item(s) to the panel.
-     * @param {Object/Array} component The Component or array of components to add. The components
+     * @param {Object/Object[]} component The Component or array of components to add. The components
      * must include a 'dock' parameter on each component to indicate where it should be docked ('top', 'right',
      * 'bottom', 'left').
      * @param {Number} pos (optional) The index at which the Component will be added
@@ -28785,7 +29729,7 @@ var panel = new Ext.panel.Panel({
     /**
      * Inserts docked item(s) to the panel at the indicated position.
      * @param {Number} pos The index at which the Component will be inserted
-     * @param {Object/Array} component. The Component or array of components to add. The components
+     * @param {Object/Object[]} component. The Component or array of components to add. The components
      * must include a 'dock' paramater on each component to indicate where it should be docked ('top', 'right',
      * 'bottom', 'left').
      */
@@ -28820,10 +29764,9 @@ var panel = new Ext.panel.Panel({
 
         if (autoDestroy === true || (autoDestroy !== false && me.autoDestroy)) {
             item.destroy();
-        }
-
-        if (hasLayout && !autoDestroy) {
-            layout.afterRemove(item);
+        } else if (hasLayout) {
+            // not destroying, make any layout related removals
+            layout.afterRemove(item);    
         }
 
 
@@ -28839,7 +29782,7 @@ var panel = new Ext.panel.Panel({
     /**
      * Retrieve an array of all currently docked Components.
      * @param {String} cqSelector A {@link Ext.ComponentQuery ComponentQuery} selector string to filter the returned items.
-     * @return {Array} An array of components.
+     * @return {Ext.Component[]} An array of components.
      */
     getDockedItems : function(cqSelector) {
         var me = this,
@@ -29045,10 +29988,26 @@ Ext.define('Ext.panel.Header', {
     indicateDrag   : false,
     weight         : -1,
 
-    renderTpl: ['<div class="{baseCls}-body<tpl if="bodyCls"> {bodyCls}</tpl><tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>'],
+    renderTpl: [
+        '<div id="{id}-body" class="{baseCls}-body<tpl if="bodyCls"> {bodyCls}</tpl>',
+        '<tpl if="uiCls">',
+            '<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl>',
+        '</tpl>"',
+        '<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>'],
+
+    /**
+     * @cfg {String} title
+     * The title text to display
+     */
+
+    /**
+     * @cfg {String} iconCls
+     * CSS class for icon in header. Used for displaying an icon to the left of a title.
+     */
 
     initComponent: function() {
         var me = this,
+            ruleStyle,
             rule,
             style,
             titleTextEl,
@@ -29066,9 +30025,7 @@ Ext.define('Ext.panel.Header', {
         me.addClsWithUI(me.orientation);
         me.addClsWithUI(me.dock);
 
-        Ext.applyIf(me.renderSelectors, {
-            body: '.' + me.baseCls + '-body'
-        });
+        me.addChildEls('body');
 
         // Add Icon
         if (!Ext.isEmpty(me.iconCls)) {
@@ -29103,7 +30060,11 @@ Ext.define('Ext.panel.Header', {
             if (Ext.isArray(ui)) {
                 ui = ui[0];
             }
-            rule = Ext.util.CSS.getRule('.' + me.baseCls + '-text-' + ui);
+            ruleStyle = '.' + me.baseCls + '-text-' + ui;
+            if (Ext.scopeResetCSS) {
+                ruleStyle = '.' + Ext.baseCSSPrefix + 'reset ' + ruleStyle;
+            }
+            rule = Ext.util.CSS.getRule(ruleStyle);
             if (rule) {
                 style = rule.style;
             }
@@ -29123,6 +30084,8 @@ Ext.define('Ext.panel.Header', {
                 autoSize: true,
                 margins: '5 0 0 0',
                 items: [ me.textConfig ],
+                // this is a bit of a cheat: we are not selecting an element of titleCmp
+                // but rather of titleCmp.items[0] (so we cannot use childEls)
                 renderSelectors: {
                     textEl: '.' + me.baseCls + '-text'
                 }
@@ -29139,15 +30102,16 @@ Ext.define('Ext.panel.Header', {
                 ariaRole  : 'heading',
                 focusable: false,
                 flex : 1,
-                renderTpl : ['<span class="{cls}-text {cls}-text-{ui}">{title}</span>'],
+                cls: me.baseCls + '-text-container',
+                renderTpl : [
+                    '<span id="{id}-textEl" class="{cls}-text {cls}-text-{ui}">{title}</span>'
+                ],
                 renderData: {
                     title: me.title,
                     cls  : me.baseCls,
                     ui   : me.ui
                 },
-                renderSelectors: {
-                    textEl: '.' + me.baseCls + '-text'
-                }
+                childEls: ['textEl']
             });
         }
         me.items.push(me.titleCmp);
@@ -29160,16 +30124,16 @@ Ext.define('Ext.panel.Header', {
     initIconCmp: function() {
         this.iconCmp = Ext.create('Ext.Component', {
             focusable: false,
-            renderTpl : ['<img alt="" src="{blank}" class="{cls}-icon {iconCls}"/>'],
+            renderTpl : [
+                '<img id="{id}-iconEl" alt="" src="{blank}" class="{cls}-icon {iconCls}"/>'
+            ],
             renderData: {
                 blank  : Ext.BLANK_IMAGE_URL,
                 cls    : this.baseCls,
                 iconCls: this.iconCls,
                 orientation: this.orientation
             },
-            renderSelectors: {
-                iconEl: '.' + this.baseCls + '-icon'
-            },
+            childEls: ['iconEl'],
             iconCls: this.iconCls
         });
     },
@@ -29226,7 +30190,7 @@ Ext.define('Ext.panel.Header', {
                 me.bodyCls = classes.join(' ');
             }
         }
+
         return result;
     },
 
@@ -29377,24 +30341,25 @@ Ext.define('Ext.panel.Header', {
     },
 
     /**
-     * Sets the CSS class that provides the icon image for this panel.  This method will replace any existing
-     * icon class if one has already been set and fire the {@link #iconchange} event after completion.
+     * Sets the CSS class that provides the icon image for this header.  This method will replace any existing
+     * icon class if one has already been set.
      * @param {String} cls The new CSS class name
      */
     setIconCls: function(cls) {
-        this.iconCls = cls;
-        if (!this.iconCmp) {
-            this.initIconCmp();
-            this.insert(0, this.iconCmp);
-        }
-        else {
-            if (!cls || !cls.length) {
-                this.iconCmp.destroy();
-            }
-            else {
-                var iconCmp = this.iconCmp,
-                    el      = iconCmp.iconEl;
-
+        var me = this,
+            isEmpty = !cls || !cls.length,
+            iconCmp = me.iconCmp,
+            el;
+        
+        me.iconCls = cls;
+        if (!me.iconCmp && !isEmpty) {
+            me.initIconCmp();
+            me.insert(0, me.iconCmp);
+        } else if (iconCmp) {
+            if (isEmpty) {
+                me.iconCmp.destroy();
+            } else {
+                el = iconCmp.iconEl;
                 el.removeCls(iconCmp.iconCls);
                 el.addCls(cls);
                 iconCmp.iconCls = cls;
@@ -29430,8 +30395,8 @@ Ext.define('Ext.panel.Header', {
  * @class Ext.fx.target.Element
  * @extends Ext.fx.target.Target
  * 
- * This class represents a animation target for an {@link Ext.core.Element}. In general this class will not be
- * created directly, the {@link Ext.core.Element} will be passed to the animation and
+ * This class represents a animation target for an {@link Ext.Element}. In general this class will not be
+ * created directly, the {@link Ext.Element} will be passed to the animation and
  * and the appropriate target will be created.
  */
 Ext.define('Ext.fx.target.Element', {
@@ -29516,7 +30481,7 @@ Ext.define('Ext.fx.target.Element', {
  * @extends Ext.fx.target.Element
  * 
  * This class represents a animation target for a {@link Ext.CompositeElement}. It allows
- * each {@link Ext.core.Element} in the group to be animated as a whole. In general this class will not be
+ * each {@link Ext.Element} in the group to be animated as a whole. In general this class will not be
  * created directly, the {@link Ext.CompositeElement} will be passed to the animation and
  * and the appropriate target will be created.
  */
@@ -29853,60 +30818,60 @@ Ext.define('Ext.fx.Manager', {
 
 /**
  * @class Ext.fx.Animator
- * Animation instance
-
-This class is used to run keyframe based animations, which follows the CSS3 based animation structure. 
-Keyframe animations differ from typical from/to animations in that they offer the ability to specify values 
-at various points throughout the animation.
-
-__Using Keyframes__
-The {@link #keyframes} option is the most important part of specifying an animation when using this 
-class. A key frame is a point in a particular animation. We represent this as a percentage of the
-total animation duration. At each key frame, we can specify the target values at that time. Note that
-you *must* specify the values at 0% and 100%, the start and ending values. There is also a {@link #keyframe}
-event that fires after each key frame is reached.
-
-__Example Usage__
-In the example below, we modify the values of the element at each fifth throughout the animation.
-
-    Ext.create('Ext.fx.Animator', {
-        target: Ext.getBody().createChild({
           style: {
-                width: '100px',
-                height: '100px',
-                'background-color': 'red'
-            }
-        }),
-        duration: 10000, // 10 seconds
-        keyframes: {
-            0: {
-                opacity: 1,
-                backgroundColor: 'FF0000'
           },
-            20: {
               x: 30,
-                opacity: 0.5    
           },
-            40: {
               x: 130,
-                backgroundColor: '0000FF'    
           },
-            60: {
               y: 80,
-                opacity: 0.3    
           },
-            80: {
               width: 200,
-                y: 200    
           },
-            100: {
               opacity: 1,
-                backgroundColor: '00FF00'
-            }
-        }
-    });
-
- * @markdown
+ *
+ * This class is used to run keyframe based animations, which follows the CSS3 based animation structure.
+ * Keyframe animations differ from typical from/to animations in that they offer the ability to specify values
+ * at various points throughout the animation.
+ *
+ * ## Using Keyframes
+ *
+ * The {@link #keyframes} option is the most important part of specifying an animation when using this
+ * class. A key frame is a point in a particular animation. We represent this as a percentage of the
+ * total animation duration. At each key frame, we can specify the target values at that time. Note that
+ * you *must* specify the values at 0% and 100%, the start and ending values. There is also a {@link #keyframe}
+ * event that fires after each key frame is reached.
+ *
+ * ## Example
+ *
+ * In the example below, we modify the values of the element at each fifth throughout the animation.
+ *
+ *     @example
*     Ext.create('Ext.fx.Animator', {
+ *         target: Ext.getBody().createChild({
+ *             style: {
+ *                 width: '100px',
+ *                 height: '100px',
+ *                 'background-color': 'red'
+ *             }
+ *         }),
+ *         duration: 10000, // 10 seconds
+ *         keyframes: {
+ *             0: {
*                 opacity: 1,
+ *                 backgroundColor: 'FF0000'
*             },
+ *             20: {
*                 x: 30,
+ *                 opacity: 0.5
*             },
+ *             40: {
*                 x: 130,
+ *                 backgroundColor: '0000FF'
*             },
+ *             60: {
*                 y: 80,
+ *                 opacity: 0.3
*             },
+ *             80: {
*                 width: 200,
+ *                 y: 200
*             },
+ *             100: {
+ *                 opacity: 1,
+ *                 backgroundColor: '00FF00'
+ *             }
+ *         }
+ *     });
  */
 Ext.define('Ext.fx.Animator', {
 
@@ -29945,36 +30910,34 @@ Ext.define('Ext.fx.Animator', {
 
     /**
      * @cfg {String} easing
-
-This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
-speed over its duration. 
-
-- backIn
-- backOut
-- bounceIn
-- bounceOut
-- ease
-- easeIn
-- easeOut
-- easeInOut
-- elasticIn
-- elasticOut
-- cubic-bezier(x1, y1, x2, y2)
-
-Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
-specification.  The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
-be in the range [0, 1] or the definition is invalid.
-
-[0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
-
-     * @markdown
+     *
+     * This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
+     * speed over its duration.
+     *
+     *  - backIn
+     *  - backOut
+     *  - bounceIn
+     *  - bounceOut
+     *  - ease
+     *  - easeIn
+     *  - easeOut
+     *  - easeInOut
+     *  - elasticIn
+     *  - elasticOut
+     *  - cubic-bezier(x1, y1, x2, y2)
+     *
+     * Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
+     * specification.  The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
+     * be in the range [0, 1] or the definition is invalid.
+     *
+     * [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
      */
     easing: 'ease',
 
     /**
      * Flag to determine if the animation has started
      * @property running
-     * @type boolean
+     * @type Boolean
      */
     running: false,
 
@@ -29982,7 +30945,7 @@ be in the range [0, 1] or the definition is invalid.
      * Flag to determine if the animation is paused. Only set this to true if you need to
      * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
      * @property paused
-     * @type boolean
+     * @type Boolean
      */
     paused: false,
 
@@ -30000,7 +30963,7 @@ be in the range [0, 1] or the definition is invalid.
     /**
      * Current iteration the animation is running.
      * @property currentIteration
-     * @type int
+     * @type Number
      */
     currentIteration: 0,
 
@@ -30017,7 +30980,7 @@ be in the range [0, 1] or the definition is invalid.
     animKeyFramesRE: /^(from|to|\d+%?)$/,
 
     /**
-     * @cfg {Ext.fx.target} target
+     * @cfg {Ext.fx.target.Target} target
      * The Ext.fx.target to apply the animation to.  If not specified during initialization, this can be passed to the applyAnimator
      * method to apply the same animation to many targets.
      */
@@ -30138,7 +31101,7 @@ keyframes : {
      * Applies animation to the Ext.fx.target
      * @private
      * @param target
-     * @type string/object
+     * @type String/Object
      */
     applyAnimator: function(target) {
         var me = this,
@@ -30184,7 +31147,7 @@ keyframes : {
         }
     },
 
-    /*
+    /**
      * @private
      * Fires beforeanimate and sets the running flag.
      */
@@ -30216,7 +31179,7 @@ keyframes : {
         }
     },
 
-    /*
+    /**
      * @private
      * Perform lastFrame cleanup and handle iterations
      * @returns a hash of the new attributes.
@@ -30240,7 +31203,7 @@ keyframes : {
         }
     },
 
-    /*
+    /**
      * Fire afteranimate event and end the animation. Usually called automatically when the
      * animation reaches its final frame, but can also be called manually to pre-emptively
      * stop and destroy the running animation.
@@ -30252,31 +31215,30 @@ keyframes : {
 });
 /**
  * @class Ext.fx.Easing
- * 
-This class contains a series of function definitions used to modify values during an animation.
-They describe how the intermediate values used during a transition will be calculated. It allows for a transition to change
-speed over its duration. The following options are available: 
-
-- linear The default easing type
-- backIn
-- backOut
-- bounceIn
-- bounceOut
-- ease
-- easeIn
-- easeOut
-- easeInOut
-- elasticIn
-- elasticOut
-- cubic-bezier(x1, y1, x2, y2)
-
-Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
-specification.  The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
-be in the range [0, 1] or the definition is invalid.
-
-[0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
-
- * @markdown
+ *
+ * This class contains a series of function definitions used to modify values during an animation.
+ * They describe how the intermediate values used during a transition will be calculated. It allows for a transition to change
+ * speed over its duration. The following options are available: 
+ *
+ * - linear The default easing type
+ * - backIn
+ * - backOut
+ * - bounceIn
+ * - bounceOut
+ * - ease
+ * - easeIn
+ * - easeOut
+ * - easeInOut
+ * - elasticIn
+ * - elasticOut
+ * - cubic-bezier(x1, y1, x2, y2)
+ *
+ * Note that cubic-bezier will create a custom easing curve following the CSS3 [transition-timing-function][0]
+ * specification.  The four values specify points P1 and P2 of the curve as (x1, y1, x2, y2). All values must
+ * be in the range [0, 1] or the definition is invalid.
+ *
+ * [0]: http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
+ *
  * @singleton
  */
 Ext.ns('Ext.fx');
@@ -31170,12 +32132,12 @@ Ext.define('Ext.draw.Draw', {
      * @param {Number} nextX X coordinate of the next point in the path
      * @param {Number} nextY Y coordinate of the next point in the path
      * @param {Number} value A value to control the smoothness of the curve; this is used to
-     *                 divide the distance between points, so a value of 2 corresponds to
-     *                 half the distance between points (a very smooth line) while higher values
-     *                 result in less smooth curves. Defaults to 4.
+     * divide the distance between points, so a value of 2 corresponds to
+     * half the distance between points (a very smooth line) while higher values
+     * result in less smooth curves. Defaults to 4.
      * @return {Object} Object containing x1, y1, x2, y2 bezier control anchor points; x1 and y1
-     *                  are the control point for the curve toward the previous path point, and
-     *                  x2 and y2 are the control point for the curve toward the next path point.
+     * are the control point for the curve toward the previous path point, and
+     * x2 and y2 are the control point for the curve toward the next path point.
      */
     getAnchors: function (prevX, prevY, curX, curY, nextX, nextY, value) {
         value = value || 4;
@@ -31314,7 +32276,25 @@ Ext.define('Ext.draw.Draw', {
         };
     },
 
+    /**
+     * A utility method to deduce an appropriate tick configuration for the data set of given
+     * feature.
+     * 
+     * @param {Number/Date} from The minimum value in the data
+     * @param {Number/Date} to The maximum value in the data
+     * @param {Number} stepsMax The maximum number of ticks
+     * @return {Object} The calculated step and ends info; When `from` and `to` are Dates, refer to the
+     * return value of {@link #snapEndsByDate}. For numerical `from` and `to` the return value contains:
+     * @return {Number} return.from The result start value, which may be lower than the original start value
+     * @return {Number} return.to The result end value, which may be higher than the original end value
+     * @return {Number} return.power The calculate power.
+     * @return {Number} return.step The value size of each step
+     * @return {Number} return.steps The number of steps.
+     */
     snapEnds: function (from, to, stepsMax) {
+        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),
@@ -31352,6 +32332,119 @@ Ext.define('Ext.draw.Draw', {
         };
     },
 
+    /**
+     * A utility method to deduce an appropriate tick configuration for the data set of given
+     * feature when data is Dates. Refer to {@link #snapEnds} for numeric data.
+     *
+     * @param {Date} from The minimum value in the data
+     * @param {Date} to The maximum value in the data
+     * @param {Number} stepsMax The maximum number of ticks
+     * @param {Boolean} lockEnds If true, the 'from' and 'to' parameters will be used as fixed end values
+     * and will not be adjusted
+     * @return {Object} The calculated step and ends info; properties are:
+     * @return {Date} return.from The result start value, which may be lower than the original start value
+     * @return {Date} return.to The result end value, which may be higher than the original end value
+     * @return {Number} return.step The value size of each step
+     * @return {Number} return.steps The number of steps.
+     * NOTE: the steps may not divide the from/to range perfectly evenly;
+     * there may be a smaller distance between the last step and the end value than between prior
+     * steps, particularly when the `endsLocked` param is true. Therefore it is best to not use
+     * the `steps` result when finding the axis tick points, instead use the `step`, `to`, and
+     * `from` to find the correct point for each tick.
+     */
+    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]]
+            ], j, yearDiff;
+
+        // Find the most desirable scale
+        Ext.each(scales, function(scale, i) {
+            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]];
+                    return false;
+                }
+            }
+        });
+        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);
+    },
+
+
+    /**
+     * A utility method to deduce an appropriate tick configuration for the data set of given
+     * feature and specific step size.
+     * @param {Date} from The minimum value in the data
+     * @param {Date} to The maximum value in the data
+     * @param {Array} step An array with two components: The first is the unit of the step (day, month, year, etc).
+     * The second one is the number of units for the step (1, 2, etc.).
+     * @param {Boolean} lockEnds If true, the 'from' and 'to' parameters will be used as fixed end values
+     * and will not be adjusted
+     * @return {Object} See the return value of {@link #snapEndsByDate}.
+     */
+    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: // Ext.Date.YEAR
+                    testFrom = new Date(Math.floor(fromStat[0] / step[1]) * step[1], 0, 1, 0, 0, 0, 0);
+                    break;
+            }
+        }
+
+        testTo = testFrom;
+        // TODO(zhangbei) : We can do it better somehow...
+        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;
     },
@@ -31432,6 +32525,7 @@ Ext.define('Ext.draw.Draw', {
     }
 });
 
+
 /**
  * @class Ext.fx.PropertyHandler
  * @ignore
@@ -31766,36 +32860,37 @@ Ext.define('Ext.fx.PropertyHandler', {
 });
 /**
  * @class Ext.fx.Anim
- * 
+ *
  * This class manages animation for a specific {@link #target}. The animation allows
  * animation of various properties on the target, such as size, position, color and others.
- * 
+ *
  * ## Starting Conditions
  * The starting conditions for the animation are provided by the {@link #from} configuration.
  * Any/all of the properties in the {@link #from} configuration can be specified. If a particular
  * property is not defined, the starting value for that property will be read directly from the target.
- * 
+ *
  * ## End Conditions
  * The ending conditions for the animation are provided by the {@link #to} configuration. These mark
  * the final values once the animations has finished. The values in the {@link #from} can mirror
  * those in the {@link #to} configuration to provide a starting point.
- * 
+ *
  * ## Other Options
  *  - {@link #duration}: Specifies the time period of the animation.
  *  - {@link #easing}: Specifies the easing of the animation.
  *  - {@link #iterations}: Allows the animation to repeat a number of times.
  *  - {@link #alternate}: Used in conjunction with {@link #iterations}, reverses the direction every second iteration.
- * 
+ *
  * ## Example Code
- * 
+ *
+ *     @example
  *     var myComponent = Ext.create('Ext.Component', {
  *         renderTo: document.body,
  *         width: 200,
  *         height: 200,
  *         style: 'border: 1px solid red;'
  *     });
- *     
- *     new Ext.fx.Anim({
+ *
+ *     Ext.create('Ext.fx.Anim', {
  *         target: myComponent,
  *         duration: 1000,
  *         from: {
@@ -31820,6 +32915,17 @@ Ext.define('Ext.fx.Anim', {
     /* End Definitions */
 
     isAnimation: true,
+
+    /**
+     * @cfg {Function} callback
+     * A function to be run after the animation has completed.
+     */
+
+    /**
+     * @cfg {Function} scope
+     * The scope that the {@link #callback} function will be called with
+     */
+
     /**
      * @cfg {Number} duration
      * Time in milliseconds for a single animation to last. Defaults to 250. If the {@link #iterations} property is
@@ -31845,7 +32951,7 @@ Ext.define('Ext.fx.Anim', {
     /**
      * @cfg {String} easing
 This describes how the intermediate values used during a transition will be calculated. It allows for a transition to change
-speed over its duration. 
+speed over its duration.
 
          -backIn
          -backOut
@@ -31914,7 +33020,7 @@ keyframes : {
     /**
      * Flag to determine if the animation has started
      * @property running
-     * @type boolean
+     * @type Boolean
      */
     running: false,
 
@@ -31922,13 +33028,13 @@ keyframes : {
      * Flag to determine if the animation is paused. Only set this to true if you need to
      * keep the Anim instance around to be unpaused later; otherwise call {@link #end}.
      * @property paused
-     * @type boolean
+     * @type Boolean
      */
     paused: false,
 
     /**
      * Number of times to execute the animation. Defaults to 1.
-     * @cfg {int} iterations
+     * @cfg {Number} iterations
      */
     iterations: 1,
 
@@ -31942,7 +33048,7 @@ keyframes : {
     /**
      * Current iteration the animation is running.
      * @property currentIteration
-     * @type int
+     * @type Number
      */
     currentIteration: 0,
 
@@ -31995,7 +33101,9 @@ from : {
 
     // @private
     constructor: function(config) {
-        var me = this;
+        var me = this,
+            curve;
+            
         config = config || {};
         // If keyframes are passed, they really want an Animator instead.
         if (config.keyframes) {
@@ -32015,8 +33123,8 @@ from : {
         if (!me.easingFn) {
             me.easingFn = String(me.easing).match(me.bezierRE);
             if (me.easingFn && me.easingFn.length == 5) {
-                var curve = me.easingFn;
-                me.easingFn = Ext.fx.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]);
+                curve = me.easingFn;
+                me.easingFn = Ext.fx.CubicBezier.cubicBezier(+curve[1], +curve[2], +curve[3], +curve[4]);
             }
         }
         me.id = Ext.id(null, 'ext-anim-');
@@ -32058,7 +33166,7 @@ from : {
         return Ext.fx.Manager.items.get(this.id).setAttr(this.target, attr, value);
     },
 
-    /*
+    /**
      * @private
      * Set up the initial currentAttrs hash.
      */
@@ -32092,7 +33200,7 @@ from : {
         me.currentAttrs = out;
     },
 
-    /*
+    /**
      * @private
      * Fires beforeanimate and sets the running flag.
      */
@@ -32126,7 +33234,7 @@ from : {
         }
     },
 
-    /*
+    /**
      * @private
      * Calculate attribute value at the passed timestamp.
      * @returns a hash of the new attributes.
@@ -32158,7 +33266,7 @@ from : {
         return ret;
     },
 
-    /*
+    /**
      * @private
      * Perform lastFrame cleanup and handle iterations
      * @returns a hash of the new attributes.
@@ -32185,7 +33293,7 @@ from : {
         }
     },
 
-    /*
+    /**
      * Fire afteranimate event and end the animation. Usually called automatically when the
      * animation reaches its final frame, but can also be called manually to pre-emptively
      * stop and destroy the running animation.
@@ -32251,14 +33359,14 @@ Ext.enableFx = true;
  */
 Ext.define('Ext.dd.DragDrop', {
     requires: ['Ext.dd.DragDropManager'],
-    
+
     /**
      * Creates new DragDrop.
      * @param {String} id of the element that is linked to this instance
      * @param {String} sGroup the group of related DragDrop objects
-     * @param {object} config an object containing configurable attributes.
+     * @param {Object} config an object containing configurable attributes.
      * Valid properties for DragDrop:
-     * 
+     *
      * - padding
      * - isTarget
      * - maintainOffset
@@ -32269,7 +33377,7 @@ Ext.define('Ext.dd.DragDrop', {
             this.init(id, sGroup, config);
         }
     },
-    
+
     /**
      * Set to false to enable a DragDrop object to fire drag events while dragging
      * over its own Element. Defaults to true - DragDrop objects do not by default
@@ -32291,7 +33399,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * Configuration attributes passed into the constructor
      * @property config
-     * @type object
+     * @type Object
      */
     config: null,
 
@@ -32318,7 +33426,7 @@ Ext.define('Ext.dd.DragDrop', {
 
     /**
      * An object who's property names identify HTML tags to be considered invalid as drag handles.
-     * A non-null property value identifies the tag as invalid. Defaults to the 
+     * A non-null property value identifies the tag as invalid. Defaults to the
      * following value which prevents drag operations from being initiated by &lt;a> elements:<pre><code>
 {
     A: "A"
@@ -32342,8 +33450,7 @@ Ext.define('Ext.dd.DragDrop', {
 
     /**
      * An Array of CSS class names for elements to be considered in valid as drag handles.
-     * @property invalidHandleClasses
-     * @type Array
+     * @property {String[]} invalidHandleClasses
      */
     invalidHandleClasses: null,
 
@@ -32351,7 +33458,7 @@ Ext.define('Ext.dd.DragDrop', {
      * The linked element's absolute X position at the time the drag was
      * started
      * @property startPageX
-     * @type int
+     * @type Number
      * @private
      */
     startPageX: 0,
@@ -32360,7 +33467,7 @@ Ext.define('Ext.dd.DragDrop', {
      * The linked element's absolute X position at the time the drag was
      * started
      * @property startPageY
-     * @type int
+     * @type Number
      * @private
      */
     startPageY: 0,
@@ -32371,7 +33478,7 @@ Ext.define('Ext.dd.DragDrop', {
      * DragDrop object in the same group.  This lets us define multiple
      * groups using a single DragDrop subclass if we want.
      * @property groups
-     * @type object An object in the format {'group1':true, 'group2':true}
+     * @type Object An object in the format {'group1':true, 'group2':true}
      */
     groups: null,
 
@@ -32379,7 +33486,7 @@ Ext.define('Ext.dd.DragDrop', {
      * Individual drag/drop instances can be locked.  This will prevent
      * onmousedown start drag.
      * @property locked
-     * @type boolean
+     * @type Boolean
      * @private
      */
     locked: false,
@@ -32395,7 +33502,7 @@ Ext.define('Ext.dd.DragDrop', {
      * When set to true, other DD objects in cooperating DDGroups do not receive
      * notification events when this DD object is dragged over them. Defaults to false.
      * @property moveOnly
-     * @type boolean
+     * @type Boolean
      */
     moveOnly: false,
 
@@ -32410,7 +33517,7 @@ Ext.define('Ext.dd.DragDrop', {
      * By default, all instances can be a drop target.  This can be disabled by
      * setting isTarget to false.
      * @property isTarget
-     * @type boolean
+     * @type Boolean
      */
     isTarget: true,
 
@@ -32418,7 +33525,7 @@ Ext.define('Ext.dd.DragDrop', {
      * The padding configured for this drag and drop object for calculating
      * the drop zone intersection with this object.
      * An array containing the 4 padding values: [top, right, bottom, left]
-     * @property {[int]} padding
+     * @property {Number[]} padding
      */
     padding: null,
 
@@ -32439,7 +33546,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * Set to true when horizontal contraints are applied
      * @property constrainX
-     * @type boolean
+     * @type Boolean
      * @private
      */
     constrainX: false,
@@ -32447,7 +33554,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * Set to true when vertical contraints are applied
      * @property constrainY
-     * @type boolean
+     * @type Boolean
      * @private
      */
     constrainY: false,
@@ -32455,7 +33562,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * The left constraint
      * @property minX
-     * @type int
+     * @type Number
      * @private
      */
     minX: 0,
@@ -32463,7 +33570,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * The right constraint
      * @property maxX
-     * @type int
+     * @type Number
      * @private
      */
     maxX: 0,
@@ -32471,7 +33578,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * The up constraint
      * @property minY
-     * @type int
+     * @type Number
      * @private
      */
     minY: 0,
@@ -32479,7 +33586,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * The down constraint
      * @property maxY
-     * @type int
+     * @type Number
      * @private
      */
     maxY: 0,
@@ -32490,7 +33597,7 @@ Ext.define('Ext.dd.DragDrop', {
      * when the page changes
      *
      * @property maintainOffset
-     * @type boolean
+     * @type Boolean
      */
     maintainOffset: false,
 
@@ -32498,7 +33605,7 @@ Ext.define('Ext.dd.DragDrop', {
      * Array of pixel locations the element will snap to if we specified a
      * horizontal graduation/interval.  This array is generated automatically
      * when you define a tick interval.
-     * @property {[int]} xTicks
+     * @property {Number[]} xTicks
      */
     xTicks: null,
 
@@ -32506,7 +33613,7 @@ Ext.define('Ext.dd.DragDrop', {
      * Array of pixel locations the element will snap to if we specified a
      * vertical graduation/interval.  This array is generated automatically
      * when you define a tick interval.
-     * @property {[int]} yTicks
+     * @property {Number[]} yTicks
      */
     yTicks: null,
 
@@ -32516,14 +33623,14 @@ Ext.define('Ext.dd.DragDrop', {
      * allow drag and drop to start with any mouse click that is propogated
      * by the browser
      * @property primaryButtonOnly
-     * @type boolean
+     * @type Boolean
      */
     primaryButtonOnly: true,
 
     /**
      * The available property is false until the linked dom element is accessible.
      * @property available
-     * @type boolean
+     * @type Boolean
      */
     available: false,
 
@@ -32535,7 +33642,7 @@ Ext.define('Ext.dd.DragDrop', {
      * if outer handles are defined. Defaults to false.
      *
      * @property hasOuterHandles
-     * @type boolean
+     * @type Boolean
      */
     hasOuterHandles: false,
 
@@ -32548,8 +33655,8 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * Abstract method called after a drag/drop object is clicked
      * and the drag or mousedown time thresholds have beeen met.
-     * @param {int} X click location
-     * @param {int} Y click location
+     * @param {Number} X click location
+     * @param {Number} Y click location
      */
     startDrag: function(x, y) { /* override this */ },
 
@@ -32570,7 +33677,7 @@ Ext.define('Ext.dd.DragDrop', {
      * Abstract method called when this element fist begins hovering over
      * another DragDrop obj
      * @param {Event} e the mousemove event
-     * @param {String/[DragDrop]} id In POINT mode, the element
+     * @param {String/Ext.dd.DragDrop[]} id In POINT mode, the element
      * id this is hovering over.  In INTERSECT mode, an array of one or more
      * dragdrop items being hovered over.
      */
@@ -32586,7 +33693,7 @@ Ext.define('Ext.dd.DragDrop', {
      * Abstract method called when this element is hovering over another
      * DragDrop obj
      * @param {Event} e the mousemove event
-     * @param {String|DragDrop[]} id In POINT mode, the element
+     * @param {String/Ext.dd.DragDrop[]} id In POINT mode, the element
      * id this is hovering over.  In INTERSECT mode, an array of dd items
      * being hovered over.
      */
@@ -32601,7 +33708,7 @@ Ext.define('Ext.dd.DragDrop', {
     /**
      * Abstract method called when we are no longer hovering over an element
      * @param {Event} e the mousemove event
-     * @param {String/[DragDrop]} id In POINT mode, the element
+     * @param {String/Ext.dd.DragDrop[]} id In POINT mode, the element
      * id this was hovering over.  In INTERSECT mode, an array of dd items
      * that the mouse is no longer over.
      */
@@ -32617,7 +33724,7 @@ Ext.define('Ext.dd.DragDrop', {
      * Abstract method called when this item is dropped on another DragDrop
      * obj
      * @param {Event} e the mouseup event
-     * @param {String/[DragDrop]} id In POINT mode, the element
+     * @param {String/Ext.dd.DragDrop[]} id In POINT mode, the element
      * id this was dropped on.  In INTERSECT mode, an array of dd items this
      * was dropped on.
      */
@@ -32669,8 +33776,8 @@ Ext.define('Ext.dd.DragDrop', {
     },
 
     /**
-     * Provides default constraint padding to "constrainTo" elements (defaults to `{left:0, right:0, top:0, bottom:0}`).
-     * @type Object
+     * @property {Object} defaultPadding
+     * Provides default constraint padding to "constrainTo" elements.
      */
     defaultPadding: {
         left: 0,
@@ -32690,7 +33797,7 @@ Ext.define('Ext.dd.DragDrop', {
      *         this.constrainTo("parent-id");
      *     };
      *
-     * Or you can initalize it using the {@link Ext.core.Element} object:
+     * Or you can initalize it using the {@link Ext.Element} object:
      *
      *     Ext.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
      *         startDrag : function(){
@@ -32698,7 +33805,7 @@ Ext.define('Ext.dd.DragDrop', {
      *         }
      *     });
      *
-     * @param {Mixed} constrainTo The element to constrain to.
+     * @param {String/HTMLElement/Ext.Element} constrainTo The element or element ID to constrain to.
      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
      * and can be either a number for symmetrical padding (4 would be equal to `{left:4, right:4, top:4, bottom:4}`) or
      * an object containing the sides to pad. For example: `{right:10, bottom:10}`
@@ -32712,10 +33819,10 @@ Ext.define('Ext.dd.DragDrop', {
         var b = Ext.get(this.getEl()).getBox(),
             ce = Ext.get(constrainTo),
             s = ce.getScroll(),
-            c, 
+            c,
             cd = ce.dom;
         if(cd == document.body){
-            c = { x: s.left, y: s.top, width: Ext.core.Element.getViewWidth(), height: Ext.core.Element.getViewHeight()};
+            c = { x: s.left, y: s.top, width: Ext.Element.getViewWidth(), height: Ext.Element.getViewHeight()};
         }else{
             var xy = ce.getXY();
             c = {x : xy[0], y: xy[1], width: cd.clientWidth, height: cd.clientHeight};
@@ -32850,10 +33957,10 @@ Ext.define('Ext.dd.DragDrop', {
      * Supports css-style shorthand; if only one parameter is passed, all sides
      * will have that padding, and if only two are passed, the top and bottom
      * will have the first param, the left and right the second.
-     * @param {int} iTop    Top pad
-     * @param {int} iRight  Right pad
-     * @param {int} iBot    Bot pad
-     * @param {int} iLeft   Left pad
+     * @param {Number} iTop    Top pad
+     * @param {Number} iRight  Right pad
+     * @param {Number} iBot    Bot pad
+     * @param {Number} iLeft   Left pad
      */
     setPadding: function(iTop, iRight, iBot, iLeft) {
         // this.padding = [iLeft, iRight, iTop, iBot];
@@ -32868,8 +33975,8 @@ Ext.define('Ext.dd.DragDrop', {
 
     /**
      * Stores the initial placement of the linked element.
-     * @param {int} diffX   the X offset, default 0
-     * @param {int} diffY   the Y offset, default 0
+     * @param {Number} diffX   the X offset, default 0
+     * @param {Number} diffY   the Y offset, default 0
      */
     setInitPosition: function(diffX, diffY) {
         var el = this.getEl();
@@ -32881,7 +33988,7 @@ Ext.define('Ext.dd.DragDrop', {
         var dx = diffX || 0;
         var dy = diffY || 0;
 
-        var p = Ext.core.Element.getXY( el );
+        var p = Ext.Element.getXY( el );
 
         this.initPageX = p[0] - dx;
         this.initPageY = p[1] - dy;
@@ -32899,7 +34006,7 @@ Ext.define('Ext.dd.DragDrop', {
      * @private
      */
     setStartPosition: function(pos) {
-        var p = pos || Ext.core.Element.getXY( this.getEl() );
+        var p = pos || Ext.Element.getXY( this.getEl() );
         this.deltaSetXY = null;
 
         this.startPageX = p[0];
@@ -33191,10 +34298,10 @@ Ext.define('Ext.dd.DragDrop', {
      * By default, the element can be dragged any place on the screen.  Use
      * this method to limit the horizontal travel of the element.  Pass in
      * 0,0 for the parameters if you want to lock the drag to the y axis.
-     * @param {int} iLeft the number of pixels the element can move to the left
-     * @param {int} iRight the number of pixels the element can move to the
+     * @param {Number} iLeft the number of pixels the element can move to the left
+     * @param {Number} iRight the number of pixels the element can move to the
      * right
-     * @param {int} iTickSize optional parameter for specifying that the
+     * @param {Number} iTickSize (optional) parameter for specifying that the
      * element should move iTickSize pixels at a time.
      */
     setXConstraint: function(iLeft, iRight, iTickSize) {
@@ -33232,9 +34339,9 @@ Ext.define('Ext.dd.DragDrop', {
      * By default, the element can be dragged any place on the screen.  Set
      * this to limit the vertical travel of the element.  Pass in 0,0 for the
      * parameters if you want to lock the drag to the x axis.
-     * @param {int} iUp the number of pixels the element can move up
-     * @param {int} iDown the number of pixels the element can move down
-     * @param {int} iTickSize optional parameter for specifying that the
+     * @param {Number} iUp the number of pixels the element can move up
+     * @param {Number} iDown the number of pixels the element can move down
+     * @param {Number} iTickSize (optional) parameter for specifying that the
      * element should move iTickSize pixels at a time.
      */
     setYConstraint: function(iUp, iDown, iTickSize) {
@@ -33251,7 +34358,7 @@ Ext.define('Ext.dd.DragDrop', {
 
     /**
      * Must be called if you manually reposition a dd element.
-     * @param {boolean} maintainOffset
+     * @param {Boolean} maintainOffset
      */
     resetConstraints: function() {
         // Maintain offsets if necessary
@@ -33284,9 +34391,9 @@ Ext.define('Ext.dd.DragDrop', {
      * Normally the drag element is moved pixel by pixel, but we can specify
      * that it move a number of pixels at a time.  This method resolves the
      * location when we have it set up like this.
-     * @param {int} val where we want to place the object
-     * @param {int[]} tickArray sorted array of valid points
-     * @return {int} the closest tick
+     * @param {Number} val where we want to place the object
+     * @param {Number[]} tickArray sorted array of valid points
+     * @return {Number} the closest tick
      * @private
      */
     getTick: function(val, tickArray) {
@@ -33316,7 +34423,7 @@ Ext.define('Ext.dd.DragDrop', {
 
     /**
      * toString method
-     * @return {string} string representation of the dd obj
+     * @return {String} string representation of the dd obj
      */
     toString: function() {
         return ("DragDrop " + this.id);
@@ -33347,7 +34454,7 @@ Ext.define('Ext.dd.DD', {
      * Creates new DD instance.
      * @param {String} id the id of the linked element
      * @param {String} sGroup the group of related DragDrop items
-     * @param {object} config an object containing configurable attributes.
+     * @param {Object} config an object containing configurable attributes.
      * Valid properties for DD: scroll
      */
     constructor: function(id, sGroup, config) {
@@ -33361,7 +34468,7 @@ Ext.define('Ext.dd.DD', {
      * window when a drag and drop element is dragged near the viewport boundary.
      * Defaults to true.
      * @property scroll
-     * @type boolean
+     * @type Boolean
      */
     scroll: true,
 
@@ -33369,8 +34476,8 @@ Ext.define('Ext.dd.DD', {
      * Sets the pointer offset to the distance between the linked element's top
      * left corner and the location the element was clicked
      * @method autoOffset
-     * @param {int} iPageX the X coordinate of the click
-     * @param {int} iPageY the Y coordinate of the click
+     * @param {Number} iPageX the X coordinate of the click
+     * @param {Number} iPageY the Y coordinate of the click
      */
     autoOffset: function(iPageX, iPageY) {
         var x = iPageX - this.startPageX;
@@ -33383,8 +34490,8 @@ Ext.define('Ext.dd.DD', {
      * offset to be in a particular location (e.g., pass in 0,0 to set it
      * to the center of the object)
      * @method setDelta
-     * @param {int} iDeltaX the distance from the left
-     * @param {int} iDeltaY the distance from the top
+     * @param {Number} iDeltaX the distance from the left
+     * @param {Number} iDeltaY the distance from the top
      */
     setDelta: function(iDeltaX, iDeltaY) {
         this.deltaX = iDeltaX;
@@ -33397,8 +34504,8 @@ Ext.define('Ext.dd.DD', {
      * that was clicked.  Override this if you want to place the element in a
      * location other than where the cursor is.
      * @method setDragElPos
-     * @param {int} iPageX the X coordinate of the mousedown or drag event
-     * @param {int} iPageY the Y coordinate of the mousedown or drag event
+     * @param {Number} iPageX the X coordinate of the mousedown or drag event
+     * @param {Number} iPageY the Y coordinate of the mousedown or drag event
      */
     setDragElPos: function(iPageX, iPageY) {
         // the first time we do this, we are going to check to make sure
@@ -33415,14 +34522,14 @@ Ext.define('Ext.dd.DD', {
      * location other than where the cursor is.
      * @method alignElWithMouse
      * @param {HTMLElement} el the element to move
-     * @param {int} iPageX the X coordinate of the mousedown or drag event
-     * @param {int} iPageY the Y coordinate of the mousedown or drag event
+     * @param {Number} iPageX the X coordinate of the mousedown or drag event
+     * @param {Number} iPageY the Y coordinate of the mousedown or drag event
      */
     alignElWithMouse: function(el, iPageX, iPageY) {
         var oCoord = this.getTargetCoord(iPageX, iPageY),
             fly = el.dom ? el : Ext.fly(el, '_dd'),
             elSize = fly.getSize(),
-            EL = Ext.core.Element,
+            EL = Ext.Element,
             vpSize;
 
         if (!this.deltaSetXY) {
@@ -33453,9 +34560,9 @@ Ext.define('Ext.dd.DD', {
      * tick marks on-demand.  We need to know this so that we can calculate the
      * number of pixels the element is offset from its original position.
      * @method cachePosition
-     * @param iPageX the current x position (optional, this just makes it so we
+     * @param {Number} iPageX (optional) the current x position (this just makes it so we
      * don't have to look it up again)
-     * @param iPageY the current y position (optional, this just makes it so we
+     * @param {Number} iPageY (optional) the current y position (this just makes it so we
      * don't have to look it up again)
      */
     cachePosition: function(iPageX, iPageY) {
@@ -33463,7 +34570,7 @@ Ext.define('Ext.dd.DD', {
             this.lastPageX = iPageX;
             this.lastPageY = iPageY;
         } else {
-            var aCoord = Ext.core.Element.getXY(this.getEl());
+            var aCoord = Ext.Element.getXY(this.getEl());
             this.lastPageX = aCoord[0];
             this.lastPageY = aCoord[1];
         }
@@ -33473,20 +34580,20 @@ Ext.define('Ext.dd.DD', {
      * Auto-scroll the window if the dragged object has been moved beyond the
      * visible window boundary.
      * @method autoScroll
-     * @param {int} x the drag element's x position
-     * @param {int} y the drag element's y position
-     * @param {int} h the height of the drag element
-     * @param {int} w the width of the drag element
+     * @param {Number} x the drag element's x position
+     * @param {Number} y the drag element's y position
+     * @param {Number} h the height of the drag element
+     * @param {Number} w the width of the drag element
      * @private
      */
     autoScroll: function(x, y, h, w) {
 
         if (this.scroll) {
             // The client height
-            var clientH = Ext.core.Element.getViewHeight();
+            var clientH = Ext.Element.getViewHeight();
 
             // The client width
-            var clientW = Ext.core.Element.getViewWidth();
+            var clientW = Ext.Element.getViewWidth();
 
             // The amt scrolled down
             var st = this.DDMInstance.getScrollTop();
@@ -33548,8 +34655,8 @@ Ext.define('Ext.dd.DD', {
      * Finds the location the element should be placed if we want to move
      * it to where the mouse location less the click offset would place us.
      * @method getTargetCoord
-     * @param {int} iPageX the X coordinate of the click
-     * @param {int} iPageY the Y coordinate of the click
+     * @param {Number} iPageX the X coordinate of the click
+     * @param {Number} iPageY the Y coordinate of the click
      * @return an object that contains the coordinates (Object.x and Object.y)
      * @private
      */
@@ -33677,7 +34784,7 @@ Ext.define('Ext.dd.DDProxy', {
      * Creates new DDProxy.
      * @param {String} id the id of the linked html element
      * @param {String} sGroup the group of related DragDrop objects
-     * @param {object} config an object containing configurable attributes.
+     * @param {Object} config an object containing configurable attributes.
      * Valid properties for DDProxy in addition to those in DragDrop:
      * 
      * - resizeFrame
@@ -33696,7 +34803,7 @@ Ext.define('Ext.dd.DDProxy', {
      * we want to drag (this is to get the frame effect).  We can turn it off
      * if we want a different behavior.
      * @property resizeFrame
-     * @type boolean
+     * @type Boolean
      */
     resizeFrame: true,
 
@@ -33706,7 +34813,7 @@ Ext.define('Ext.dd.DDProxy', {
      * you do not have constraints on the obj is to have the drag frame centered
      * around the cursor.  Set centerFrame to true for this effect.
      * @property centerFrame
-     * @type boolean
+     * @type Boolean
      */
     centerFrame: false,
 
@@ -33764,8 +34871,8 @@ Ext.define('Ext.dd.DDProxy', {
      * Resizes the drag frame to the dimensions of the clicked object, positions
      * it over the object, and finally displays it
      * @method showFrame
-     * @param {int} iPageX X click position
-     * @param {int} iPageY Y click position
+     * @param {Number} iPageX X click position
+     * @param {Number} iPageY Y click position
      * @private
      */
     showFrame: function(iPageX, iPageY) {
@@ -33868,30 +34975,30 @@ Ext.define('Ext.dd.DragSource', {
     /**
      * @cfg {String} ddGroup
      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
-     * interact with other drag drop objects in the same group (defaults to undefined).
+     * interact with other drag drop objects in the same group.
      */
 
     /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+     * @cfg {String} [dropAllowed="x-dd-drop-ok"]
+     * The CSS class returned to the drag source when drop is allowed.
      */
-
     dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',
     /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
+     * @cfg {String} [dropNotAllowed="x-dd-drop-nodrop"]
+     * The CSS class returned to the drag source when drop is not allowed.
      */
     dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',
 
     /**
      * @cfg {Boolean} animRepair
-     * Defaults to true. If true, animates the proxy element back to the position of the handle element used to trigger the drag.
+     * If true, animates the proxy element back to the position of the handle element used to trigger the drag.
      */
     animRepair: true,
 
     /**
-     * @cfg {String} repairHighlightColor The color to use when visually highlighting the drag source in the afterRepair
-     * method after a failed drop (defaults to 'c3daf9' - light blue). The color must be a 6 digit hex value, without
+     * @cfg {String} repairHighlightColor
+     * The color to use when visually highlighting the drag source in the afterRepair
+     * method after a failed drop (defaults to light blue). The color must be a 6 digit hex value, without
      * a preceding '#'.
      */
     repairHighlightColor: 'c3daf9',
@@ -33899,7 +35006,7 @@ Ext.define('Ext.dd.DragSource', {
     /**
      * Creates new drag-source.
      * @constructor
-     * @param {Mixed} el The container element
+     * @param {String/HTMLElement/Ext.Element} el The container element or ID of it.
      * @param {Object} config (optional) Config object.
      */
     constructor: function(el, config) {
@@ -34094,7 +35201,7 @@ Ext.define('Ext.dd.DragSource', {
              * @param {Object} target The target DD
              * @param {Event} e The event object
              * @param {String} id The id of the dropped element
-             * @method afterInvalidDrop
+             * @method afterValidDrop
              */
             this.afterValidDrop(target, e, id);
         }
@@ -34318,91 +35425,110 @@ Ext.define('Ext.layout.component.Dock', {
 
 });
 /**
- * @class Ext.panel.Panel
- * @extends Ext.panel.AbstractPanel
- * <p>Panel is a container that has specific functionality and structural components that make
- * it the perfect building block for application-oriented user interfaces.</p>
- * <p>Panels are, by virtue of their inheritance from {@link Ext.container.Container}, capable
- * of being configured with a {@link Ext.container.Container#layout layout}, and containing child Components.</p>
- * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.container.Container#add adding} Components
- * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
- * those child elements need to be sized using one of Ext&#39;s built-in <code><b>{@link Ext.container.Container#layout layout}</b></code> schemes. By
- * default, Panels use the {@link Ext.layout.container.Auto Auto} scheme. This simply renders
- * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
- * at all.</p>
+ * Panel is a container that has specific functionality and structural components that make it the perfect building
+ * block for application-oriented user interfaces.
+ *
+ * Panels are, by virtue of their inheritance from {@link Ext.container.Container}, capable of being configured with a
+ * {@link Ext.container.Container#layout layout}, and containing child Components.
+ *
+ * When either specifying child {@link #items} of a Panel, or dynamically {@link Ext.container.Container#add adding}
+ * Components to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether those
+ * child elements need to be sized using one of Ext's built-in `{@link Ext.container.Container#layout layout}`
+ * schemes. By default, Panels use the {@link Ext.layout.container.Auto Auto} scheme. This simply renders child
+ * components, appending them one after the other inside the Container, and **does not apply any sizing** at all.
+ *
  * {@img Ext.panel.Panel/panel.png Panel components}
- * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
- * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
- * information).</p>
- * <p>Panel also provides built-in {@link #collapsible collapsible, expandable} and {@link #closable} behavior.
- * Panels can be easily dropped into any {@link Ext.container.Container Container} or layout, and the
- * layout and rendering pipeline is {@link Ext.container.Container#add completely managed by the framework}.</p>
- * <p><b>Note:</b> By default, the <code>{@link #closable close}</code> header tool <i>destroys</i> the Panel resulting in removal of the Panel
- * and the destruction of any descendant Components. This makes the Panel object, and all its descendants <b>unusable</b>. To enable the close
- * tool to simply <i>hide</i> a Panel for later re-use, configure the Panel with <b><code>{@link #closeAction closeAction: 'hide'}</code></b>.</p>
- * <p>Usually, Panels are used as constituents within an application, in which case, they would be used as child items of Containers,
- * and would themselves use Ext.Components as child {@link #items}. However to illustrate simply rendering a Panel into the document,
- * here&#39;s how to do it:<pre><code>
-Ext.create('Ext.panel.Panel', {
-    title: 'Hello',
-    width: 200,
-    html: '&lt;p&gt;World!&lt;/p&gt;',
-    renderTo: document.body
-});
-</code></pre></p>
- * <p>A more realistic scenario is a Panel created to house input fields which will not be rendered, but used as a constituent part of a Container:<pre><code>
-var filterPanel = Ext.create('Ext.panel.Panel', {
-    bodyPadding: 5,  // Don&#39;t want content to crunch against the borders
-    title: 'Filters',
-    items: [{
-        xtype: 'datefield',
-        fieldLabel: 'Start date'
-    }, {
-        xtype: 'datefield',
-        fieldLabel: 'End date'
-    }]
-});
-</code></pre></p>
- * <p>Note that the Panel above is not configured to render into the document, nor is it configured with a size or position. In a real world scenario,
- * the Container into which the Panel is added will use a {@link #layout} to render, size and position its child Components.</p>
- * <p>Panels will often use specific {@link #layout}s to provide an application with shape and structure by containing and arranging child
- * Components: <pre><code>
-var resultsPanel = Ext.create('Ext.panel.Panel', {
-    title: 'Results',
-    width: 600,
-    height: 400,
-    renderTo: document.body,
-    layout: {
-        type: 'vbox',       // Arrange child items vertically
-        align: 'stretch',    // Each takes up full width
-        padding: 5
-    },
-    items: [{               // Results grid specified as a config object with an xtype of 'grid'
-        xtype: 'grid',
-        columns: [{header: 'Column One'}],            // One header just for show. There&#39;s no data,
-        store: Ext.create('Ext.data.ArrayStore', {}), // A dummy empty data store
-        flex: 1                                       // Use 1/3 of Container&#39;s height (hint to Box layout)
-    }, {
-        xtype: 'splitter'   // A splitter between the two child items
-    }, {                    // Details Panel specified as a config object (no xtype defaults to 'panel').
-        title: 'Details',
-        bodyPadding: 5,
-        items: [{
-            fieldLabel: 'Data item',
-            xtype: 'textfield'
-        }], // An array of form fields
-        flex: 2             // Use 2/3 of Container&#39;s height (hint to Box layout)
-    }]
-});
-</code></pre>
- * The example illustrates one possible method of displaying search results. The Panel contains a grid with the resulting data arranged
- * in rows. Each selected row may be displayed in detail in the Panel below. The {@link Ext.layout.container.VBox vbox} layout is used
- * to arrange the two vertically. It is configured to stretch child items horizontally to full width. Child items may either be configured
- * with a numeric height, or with a <code>flex</code> value to distribute available space proportionately.</p>
- * <p>This Panel itself may be a child item of, for exaple, a {@link Ext.tab.Panel} which will size its child items to fit within its
- * content area.</p>
- * <p>Using these techniques, as long as the <b>layout</b> is chosen and configured correctly, an application may have any level of
- * nested containment, all dynamically sized according to configuration, the user&#39;s preference and available browser size.</p>
+ *
+ * A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate {@link
+ * Ext.panel.Header header}, {@link #fbar footer} and body sections.
+ *
+ * Panel also provides built-in {@link #collapsible collapsible, expandable} and {@link #closable} behavior. Panels can
+ * be easily dropped into any {@link Ext.container.Container Container} or layout, and the layout and rendering pipeline
+ * is {@link Ext.container.Container#add completely managed by the framework}.
+ *
+ * **Note:** By default, the `{@link #closable close}` header tool _destroys_ the Panel resulting in removal of the
+ * Panel and the destruction of any descendant Components. This makes the Panel object, and all its descendants
+ * **unusable**. To enable the close tool to simply _hide_ a Panel for later re-use, configure the Panel with
+ * `{@link #closeAction closeAction}: 'hide'`.
+ *
+ * Usually, Panels are used as constituents within an application, in which case, they would be used as child items of
+ * Containers, and would themselves use Ext.Components as child {@link #items}. However to illustrate simply rendering a
+ * Panel into the document, here's how to do it:
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Hello',
+ *         width: 200,
+ *         html: '<p>World!</p>',
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ * A more realistic scenario is a Panel created to house input fields which will not be rendered, but used as a
+ * constituent part of a Container:
+ *
+ *     @example
+ *     var filterPanel = Ext.create('Ext.panel.Panel', {
+ *         bodyPadding: 5,  // Don't want content to crunch against the borders
+ *         width: 300,
+ *         title: 'Filters',
+ *         items: [{
+ *             xtype: 'datefield',
+ *             fieldLabel: 'Start date'
+ *         }, {
+ *             xtype: 'datefield',
+ *             fieldLabel: 'End date'
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ * Note that the Panel above is not configured to render into the document, nor is it configured with a size or
+ * position. In a real world scenario, the Container into which the Panel is added will use a {@link #layout} to render,
+ * size and position its child Components.
+ *
+ * Panels will often use specific {@link #layout}s to provide an application with shape and structure by containing and
+ * arranging child Components:
+ *
+ *     @example
+ *     var resultsPanel = Ext.create('Ext.panel.Panel', {
+ *         title: 'Results',
+ *         width: 600,
+ *         height: 400,
+ *         renderTo: Ext.getBody(),
+ *         layout: {
+ *             type: 'vbox',       // Arrange child items vertically
+ *             align: 'stretch',    // Each takes up full width
+ *             padding: 5
+ *         },
+ *         items: [{               // Results grid specified as a config object with an xtype of 'grid'
+ *             xtype: 'grid',
+ *             columns: [{header: 'Column One'}],            // One header just for show. There's no data,
+ *             store: Ext.create('Ext.data.ArrayStore', {}), // A dummy empty data store
+ *             flex: 1                                       // Use 1/3 of Container's height (hint to Box layout)
+ *         }, {
+ *             xtype: 'splitter'   // A splitter between the two child items
+ *         }, {                    // Details Panel specified as a config object (no xtype defaults to 'panel').
+ *             title: 'Details',
+ *             bodyPadding: 5,
+ *             items: [{
+ *                 fieldLabel: 'Data item',
+ *                 xtype: 'textfield'
+ *             }], // An array of form fields
+ *             flex: 2             // Use 2/3 of Container's height (hint to Box layout)
+ *         }]
+ *     });
+ *
+ * The example illustrates one possible method of displaying search results. The Panel contains a grid with the
+ * resulting data arranged in rows. Each selected row may be displayed in detail in the Panel below. The {@link
+ * Ext.layout.container.VBox vbox} layout is used to arrange the two vertically. It is configured to stretch child items
+ * horizontally to full width. Child items may either be configured with a numeric height, or with a `flex` value to
+ * distribute available space proportionately.
+ *
+ * This Panel itself may be a child item of, for exaple, a {@link Ext.tab.Panel} which will size its child items to fit
+ * within its content area.
+ *
+ * Using these techniques, as long as the **layout** is chosen and configured correctly, an application may have any
+ * level of nested containment, all dynamically sized according to configuration, the user's preference and available
+ * browser size.
  */
 Ext.define('Ext.panel.Panel', {
     extend: 'Ext.panel.AbstractPanel',
@@ -34420,166 +35546,182 @@ Ext.define('Ext.panel.Panel', {
 
     /**
      * @cfg {String} collapsedCls
-     * A CSS class to add to the panel&#39;s element after it has been collapsed (defaults to
-     * <code>'collapsed'</code>).
+     * A CSS class to add to the panel's element after it has been collapsed.
      */
     collapsedCls: 'collapsed',
 
     /**
      * @cfg {Boolean} animCollapse
-     * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
-     * animation (defaults to <code>true</code> if the {@link Ext.fx.Anim} class is available, otherwise <code>false</code>).
-     * May also be specified as the animation duration in milliseconds.
+     * `true` to animate the transition when the panel is collapsed, `false` to skip the animation (defaults to `true`
+     * if the {@link Ext.fx.Anim} class is available, otherwise `false`). May also be specified as the animation
+     * duration in milliseconds.
      */
     animCollapse: Ext.enableFx,
 
     /**
      * @cfg {Number} minButtonWidth
-     * Minimum width of all footer toolbar buttons in pixels (defaults to <tt>75</tt>). If set, this will
-     * be used as the default value for the <tt>{@link Ext.button.Button#minWidth}</tt> config of
-     * each Button added to the <b>footer toolbar</b> via the {@link #fbar} or {@link #buttons} configurations.
-     * It will be ignored for buttons that have a minWidth configured some other way, e.g. in their own config
-     * object or via the {@link Ext.container.Container#config-defaults defaults} of their parent container.
+     * Minimum width of all footer toolbar buttons in pixels. If set, this will be used as the default
+     * value for the {@link Ext.button.Button#minWidth} config of each Button added to the **footer toolbar** via the
+     * {@link #fbar} or {@link #buttons} configurations. It will be ignored for buttons that have a minWidth configured
+     * some other way, e.g. in their own config object or via the {@link Ext.container.Container#defaults defaults} of
+     * their parent container.
      */
     minButtonWidth: 75,
 
     /**
      * @cfg {Boolean} collapsed
-     * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
-     * <code>false</code>).
+     * `true` to render the panel collapsed, `false` to render it expanded.
      */
     collapsed: false,
 
     /**
      * @cfg {Boolean} collapseFirst
-     * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
-     * any other tools in the panel&#39;s title bar, <code>false</code> to render it last (defaults to <code>true</code>).
+     * `true` to make sure the collapse/expand toggle button always renders first (to the left of) any other tools in
+     * the panel's title bar, `false` to render it last.
      */
     collapseFirst: true,
 
     /**
      * @cfg {Boolean} hideCollapseTool
-     * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
-     * <code>false</code> to display it (defaults to <code>false</code>).
+     * `true` to hide the expand/collapse toggle button when `{@link #collapsible} == true`, `false` to display it.
      */
     hideCollapseTool: false,
 
     /**
      * @cfg {Boolean} titleCollapse
-     * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
-     * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
-     * (defaults to <code>false</code>)).
+     * `true` to allow expanding and collapsing the panel (when `{@link #collapsible} = true`) by clicking anywhere in
+     * the header bar, `false`) to allow it only by clicking to tool butto).
      */
     titleCollapse: false,
 
     /**
      * @cfg {String} collapseMode
-     * <p><b>Important: this config is only effective for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}.</b></p>
-     * <p>When <i>not</i> a direct child item of a {@link Ext.layout.container.Border border layout}, then the Panel&#39;s header remains visible, and the body is collapsed to zero dimensions.
-     * If the Panel has no header, then a new header (orientated correctly depending on the {@link #collapseDirection}) will be inserted to show a the title and a re-expand tool.</p>
-     * <p>When a child item of a {@link Ext.layout.container.Border border layout}, this config has two options:
-     * <div class="mdetail-params"><ul>
-     * <li><b><code>undefined/omitted</code></b><div class="sub-desc">When collapsed, a placeholder {@link Ext.panel.Header Header} is injected into the layout to represent the Panel
-     * and to provide a UI with a Tool to allow the user to re-expand the Panel.</div></li>
-     * <li><b><code>header</code></b> : <div class="sub-desc">The Panel collapses to leave its header visible as when not inside a {@link Ext.layout.container.Border border layout}.</div></li>
-     * </ul></div></p>
+     * **Important: this config is only effective for {@link #collapsible} Panels which are direct child items of a
+     * {@link Ext.layout.container.Border border layout}.**
+     *
+     * When _not_ a direct child item of a {@link Ext.layout.container.Border border layout}, then the Panel's header
+     * remains visible, and the body is collapsed to zero dimensions. If the Panel has no header, then a new header
+     * (orientated correctly depending on the {@link #collapseDirection}) will be inserted to show a the title and a re-
+     * expand tool.
+     *
+     * When a child item of a {@link Ext.layout.container.Border border layout}, this config has two options:
+     *
+     * - **`undefined/omitted`**
+     *
+     *   When collapsed, a placeholder {@link Ext.panel.Header Header} is injected into the layout to represent the Panel
+     *   and to provide a UI with a Tool to allow the user to re-expand the Panel.
+     *
+     * - **`header`** :
+     *
+     *   The Panel collapses to leave its header visible as when not inside a {@link Ext.layout.container.Border border
+     *   layout}.
      */
 
     /**
-     * @cfg {Mixed} placeholder
-     * <p><b>Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}
-     * when not using the <code>'header'</code> {@link #collapseMode}.</b></p>
-     * <p><b>Optional.</b> A Component (or config object for a Component) to show in place of this Panel when this Panel is collapsed by a
-     * {@link Ext.layout.container.Border border layout}. Defaults to a generated {@link Ext.panel.Header Header}
-     * containing a {@link Ext.panel.Tool Tool} to re-expand the Panel.</p>
+     * @cfg {Ext.Component/Object} placeholder
+     * **Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a
+     * {@link Ext.layout.container.Border border layout} when not using the `'header'` {@link #collapseMode}.**
+     *
+     * **Optional.** A Component (or config object for a Component) to show in place of this Panel when this Panel is
+     * collapsed by a {@link Ext.layout.container.Border border layout}. Defaults to a generated {@link Ext.panel.Header
+     * Header} containing a {@link Ext.panel.Tool Tool} to re-expand the Panel.
      */
 
     /**
      * @cfg {Boolean} floatable
-     * <p><b>Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}.</b></p>
-     * <tt>true</tt> to allow clicking a collapsed Panel&#39;s {@link #placeholder} to display the Panel floated
-     * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
-     * clicking the expand button to see it again (defaults to <tt>true</tt>).
+     * **Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a
+     * {@link Ext.layout.container.Border border layout}.**
+     *
+     * true to allow clicking a collapsed Panel's {@link #placeholder} to display the Panel floated above the layout,
+     * false to force the user to fully expand a collapsed region by clicking the expand button to see it again.
      */
     floatable: true,
 
     /**
-     * @cfg {Mixed} overlapHeader
-     * True to overlap the header in a panel over the framing of the panel itself. This is needed when frame:true (and is done automatically for you). Otherwise it is undefined.
-     * If you manually add rounded corners to a panel header which does not have frame:true, this will need to be set to true.
+     * @cfg {Boolean} overlapHeader
+     * True to overlap the header in a panel over the framing of the panel itself. This is needed when frame:true (and
+     * is done automatically for you). Otherwise it is undefined. If you manually add rounded corners to a panel header
+     * which does not have frame:true, this will need to be set to true.
      */
 
     /**
      * @cfg {Boolean} collapsible
-     * <p>True to make the panel collapsible and have an expand/collapse toggle Tool added into
-     * the header tool button area. False to keep the panel sized either statically, or by an owning layout manager, with no toggle Tool (defaults to false).</p>
+     * True to make the panel collapsible and have an expand/collapse toggle Tool added into the header tool button
+     * area. False to keep the panel sized either statically, or by an owning layout manager, with no toggle Tool.
+     *
      * See {@link #collapseMode} and {@link #collapseDirection}
      */
     collapsible: false,
 
     /**
      * @cfg {Boolean} collapseDirection
-     * <p>The direction to collapse the Panel when the toggle button is clicked.</p>
-     * <p>Defaults to the {@link #headerPosition}</p>
-     * <p><b>Important: This config is <u>ignored</u> for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}.</b></p>
-     * <p>Specify as <code>'top'</code>, <code>'bottom'</code>, <code>'left'</code> or <code>'right'</code>.</p>
+     * The direction to collapse the Panel when the toggle button is clicked.
+     *
+     * Defaults to the {@link #headerPosition}
+     *
+     * **Important: This config is _ignored_ for {@link #collapsible} Panels which are direct child items of a {@link
+     * Ext.layout.container.Border border layout}.**
+     *
+     * Specify as `'top'`, `'bottom'`, `'left'` or `'right'`.
      */
 
     /**
      * @cfg {Boolean} closable
-     * <p>True to display the 'close' tool button and allow the user to close the window, false to
-     * hide the button and disallow closing the window (defaults to <code>false</code>).</p>
-     * <p>By default, when close is requested by clicking the close button in the header, the {@link #close}
-     * method will be called. This will <i>{@link Ext.Component#destroy destroy}</i> the Panel and its content
-     * meaning that it may not be reused.</p>
-     * <p>To make closing a Panel <i>hide</i> the Panel so that it may be reused, set
-     * {@link #closeAction} to 'hide'.</p>
+     * True to display the 'close' tool button and allow the user to close the window, false to hide the button and
+     * disallow closing the window.
+     *
+     * By default, when close is requested by clicking the close button in the header, the {@link #close} method will be
+     * called. This will _{@link Ext.Component#destroy destroy}_ the Panel and its content meaning that it may not be
+     * reused.
+     *
+     * To make closing a Panel _hide_ the Panel so that it may be reused, set {@link #closeAction} to 'hide'.
      */
     closable: false,
 
     /**
      * @cfg {String} closeAction
-     * <p>The action to take when the close header tool is clicked:
-     * <div class="mdetail-params"><ul>
-     * <li><b><code>'{@link #destroy}'</code></b> : <b>Default</b><div class="sub-desc">
-     * {@link #destroy remove} the window from the DOM and {@link Ext.Component#destroy destroy}
-     * it and all descendant Components. The window will <b>not</b> be available to be
-     * redisplayed via the {@link #show} method.
-     * </div></li>
-     * <li><b><code>'{@link #hide}'</code></b> : <div class="sub-desc">
-     * {@link #hide} the window by setting visibility to hidden and applying negative offsets.
-     * The window will be available to be redisplayed via the {@link #show} method.
-     * </div></li>
-     * </ul></div>
-     * <p><b>Note:</b> This behavior has changed! setting *does* affect the {@link #close} method
-     * which will invoke the approriate closeAction.
+     * The action to take when the close header tool is clicked:
+     *
+     * - **`'{@link #destroy}'`** :
+     *
+     *   {@link #destroy remove} the window from the DOM and {@link Ext.Component#destroy destroy} it and all descendant
+     *   Components. The window will **not** be available to be redisplayed via the {@link #show} method.
+     *
+     * - **`'{@link #hide}'`** :
+     *
+     *   {@link #hide} the window by setting visibility to hidden and applying negative offsets. The window will be
+     *   available to be redisplayed via the {@link #show} method.
+     *
+     * **Note:** This behavior has changed! setting *does* affect the {@link #close} method which will invoke the
+     * approriate closeAction.
      */
     closeAction: 'destroy',
 
     /**
-     * @cfg {Object/Array} dockedItems
-     * A component or series of components to be added as docked items to this panel.
-     * The docked items can be docked to either the top, right, left or bottom of a panel.
-     * This is typically used for things like toolbars or tab bars:
-     * <pre><code>
-var panel = new Ext.panel.Panel({
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'top',
-        items: [{
-            text: 'Docked to the top'
-        }]
-    }]
-});</pre></code>
+     * @cfg {Object/Object[]} dockedItems
+     * A component or series of components to be added as docked items to this panel. The docked items can be docked to
+     * either the top, right, left or bottom of a panel. This is typically used for things like toolbars or tab bars:
+     *
+     *     var panel = new Ext.panel.Panel({
+     *         dockedItems: [{
+     *             xtype: 'toolbar',
+     *             dock: 'top',
+     *             items: [{
+     *                 text: 'Docked to the top'
+     *             }]
+     *         }]
+     *     });
      */
 
     /**
-      * @cfg {Boolean} preventHeader Prevent a Header from being created and shown. Defaults to false.
+      * @cfg {Boolean} preventHeader
+      * Prevent a Header from being created and shown.
       */
     preventHeader: false,
 
      /**
-      * @cfg {String} headerPosition Specify as <code>'top'</code>, <code>'bottom'</code>, <code>'left'</code> or <code>'right'</code>. Defaults to <code>'top'</code>.
+      * @cfg {String} headerPosition
+      * Specify as `'top'`, `'bottom'`, `'left'` or `'right'`.
       */
     headerPosition: 'top',
 
@@ -34596,45 +35738,60 @@ var panel = new Ext.panel.Panel({
     frameHeader: true,
 
     /**
-     * @cfg {Array} tools
-     * An array of {@link Ext.panel.Tool} configs/instances to be added to the header tool area. The tools are stored as child
-     * components of the header container. They can be accessed using {@link #down} and {#query}, as well as the other
-     * component methods. The toggle tool is automatically created if {@link #collapsible} is set to true.
-     * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
-     * tools only provide the visual button. Any required functionality must be provided by adding
-     * handlers that implement the necessary behavior.</p>
-     * <p>Example usage:</p>
-     * <pre><code>
-tools:[{
-    type:'refresh',
-    qtip: 'Refresh form Data',
-    // hidden:true,
-    handler: function(event, toolEl, panel){
-        // refresh logic
-    }
-},
-{
-    type:'help',
-    qtip: 'Get Help',
-    handler: function(event, toolEl, panel){
-        // show help here
-    }
-}]
-</code></pre>
+     * @cfg {Object[]/Ext.panel.Tool[]} tools
+     * An array of {@link Ext.panel.Tool} configs/instances to be added to the header tool area. The tools are stored as
+     * child components of the header container. They can be accessed using {@link #down} and {#query}, as well as the
+     * other component methods. The toggle tool is automatically created if {@link #collapsible} is set to true.
+     *
+     * Note that, apart from the toggle tool which is provided when a panel is collapsible, these tools only provide the
+     * visual button. Any required functionality must be provided by adding handlers that implement the necessary
+     * behavior.
+     *
+     * Example usage:
+     *
+     *     tools:[{
+     *         type:'refresh',
+     *         tooltip: 'Refresh form Data',
+     *         // hidden:true,
+     *         handler: function(event, toolEl, panel){
+     *             // refresh logic
+     *         }
+     *     },
+     *     {
+     *         type:'help',
+     *         tooltip: 'Get Help',
+     *         handler: function(event, toolEl, panel){
+     *             // show help here
+     *         }
+     *     }]
      */
 
     /**
-     * @cfg {String} title
-     * The title text to be used to display in the {@link Ext.panel.Header panel header} (defaults to '').
-     * When a `title` is specified the {@link Ext.panel.Header} will automatically be created and displayed unless
+     * @cfg {String} [title='']
+     * The title text to be used to display in the {@link Ext.panel.Header panel header}. When a
+     * `title` is specified the {@link Ext.panel.Header} will automatically be created and displayed unless
      * {@link #preventHeader} is set to `true`.
      */
 
+    /**
+     * @cfg {String} iconCls
+     * CSS class for icon in header. Used for displaying an icon to the left of a title.
+     */
+
     initComponent: function() {
         var me = this,
             cls;
 
         me.addEvents(
+
+            /**
+             * @event beforeclose
+             * Fires before the user closes the panel. Return false from any listener to stop the close event being
+             * fired
+             * @param {Ext.panel.Panel} panel The Panel object
+             */
+            'beforeclose',
+
             /**
              * @event beforeexpand
              * Fires before this panel is expanded. Return false to prevent the expand.
@@ -34647,11 +35804,13 @@ tools:[{
              * @event beforecollapse
              * Fires before this panel is collapsed. Return false to prevent the collapse.
              * @param {Ext.panel.Panel} p The Panel being collapsed.
-             * @param {String} direction. The direction of the collapse. One of<ul>
-             * <li>Ext.Component.DIRECTION_TOP</li>
-             * <li>Ext.Component.DIRECTION_RIGHT</li>
-             * <li>Ext.Component.DIRECTION_BOTTOM</li>
-             * <li>Ext.Component.DIRECTION_LEFT</li></ul>
+             * @param {String} direction . The direction of the collapse. One of
+             *
+             *   - Ext.Component.DIRECTION_TOP
+             *   - Ext.Component.DIRECTION_RIGHT
+             *   - Ext.Component.DIRECTION_BOTTOM
+             *   - Ext.Component.DIRECTION_LEFT
+             *
              * @param {Boolean} animate True if the collapse is animated, else false.
              */
             "beforecollapse",
@@ -34700,12 +35859,11 @@ tools:[{
             me.setUI(me.ui + '-framed');
         }
 
-        me.callParent();
-
-        me.collapseDirection = me.collapseDirection || me.headerPosition || Ext.Component.DIRECTION_TOP;
-
         // Backwards compatibility
         me.bridgeToolbars();
+
+        me.callParent();
+        me.collapseDirection = me.collapseDirection || me.headerPosition || Ext.Component.DIRECTION_TOP;
     },
 
     setBorder: function(border) {
@@ -34755,7 +35913,7 @@ tools:[{
     },
 
     /**
-     * Set a title for the panel&#39;s header. See {@link Ext.panel.Header#title}.
+     * Set a title for the panel's header. See {@link Ext.panel.Header#title}.
      * @param {String} newTitle
      */
     setTitle: function(newTitle) {
@@ -34776,8 +35934,9 @@ tools:[{
     },
 
     /**
-     * Set the iconCls for the panel&#39;s header. See {@link Ext.panel.Header#iconCls}.
-     * @param {String} newIconCls
+     * Set the iconCls for the panel's header. See {@link Ext.panel.Header#iconCls}. It will fire the
+     * {@link #iconchange} event after completion.
+     * @param {String} newIconCls The new CSS class name
      */
     setIconCls: function(newIconCls) {
         var me = this,
@@ -34793,6 +35952,7 @@ tools:[{
 
     bridgeToolbars: function() {
         var me = this,
+            docked = [],
             fbar,
             fbarDefaults,
             minButtonWidth = me.minButtonWidth;
@@ -34824,94 +35984,85 @@ tools:[{
 
         // Short-hand toolbars (tbar, bbar and fbar plus new lbar and rbar):
 
-    /**
-     * @cfg {String} buttonAlign
-     * <p>The alignment of any buttons added to this panel.  Valid values are 'right',
-     * 'left' and 'center' (defaults to 'right' for buttons/fbar, 'left' for other toolbar types).</p>
-     * <p><b>NOTE:</b> The newer way to specify toolbars is to use the dockedItems config, and
-     * instead of buttonAlign you would add the layout: { pack: 'start' | 'center' | 'end' }
-     * option to the dockedItem config.</p>
-     */
-
         /**
-         * @cfg {Object/Array} tbar
-
-Convenience method. Short for 'Top Bar'.
-
-    tbar: [
-      { xtype: 'button', text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'top',
-        items: [
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
+         * @cfg {String} buttonAlign
+         * The alignment of any buttons added to this panel. Valid values are 'right', 'left' and 'center' (defaults to
+         * 'right' for buttons/fbar, 'left' for other toolbar types).
+         *
+         * **NOTE:** The prefered way to specify toolbars is to use the dockedItems config. Instead of buttonAlign you
+         * would add the layout: { pack: 'start' | 'center' | 'end' } option to the dockedItem config.
+         */
 
-         * @markdown
+        /**
+         * @cfg {Object/Object[]} tbar
+         * Convenience config. Short for 'Top Bar'.
+         *
+         *     tbar: [
+         *       { xtype: 'button', text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'top',
+         *         items: [
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
          */
         if (me.tbar) {
-            me.addDocked(initToolbar(me.tbar, 'top'));
+            docked.push(initToolbar(me.tbar, 'top'));
             me.tbar = null;
         }
 
         /**
-         * @cfg {Object/Array} bbar
-
-Convenience method. Short for 'Bottom Bar'.
-
-    bbar: [
-      { xtype: 'button', text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'bottom',
-        items: [
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
-
-         * @markdown
+         * @cfg {Object/Object[]} bbar
+         * Convenience config. Short for 'Bottom Bar'.
+         *
+         *     bbar: [
+         *       { xtype: 'button', text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'bottom',
+         *         items: [
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
          */
         if (me.bbar) {
-            me.addDocked(initToolbar(me.bbar, 'bottom'));
+            docked.push(initToolbar(me.bbar, 'bottom'));
             me.bbar = null;
         }
 
         /**
-         * @cfg {Object/Array} buttons
-
-Convenience method used for adding buttons docked to the bottom of the panel. This is a
-synonym for the {@link #fbar} config.
-
-    buttons: [
-      { text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'bottom',
-        ui: 'footer',
-        defaults: {minWidth: {@link #minButtonWidth}},
-        items: [
-            { xtype: 'component', flex: 1 },
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
-
-The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
-each of the buttons in the buttons toolbar.
-
-         * @markdown
+         * @cfg {Object/Object[]} buttons
+         * Convenience config used for adding buttons docked to the bottom of the panel. This is a
+         * synonym for the {@link #fbar} config.
+         *
+         *     buttons: [
+         *       { text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'bottom',
+         *         ui: 'footer',
+         *         defaults: {minWidth: {@link #minButtonWidth}},
+         *         items: [
+         *             { xtype: 'component', flex: 1 },
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
+         *
+         * The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
+         * each of the buttons in the buttons toolbar.
          */
         if (me.buttons) {
             me.fbar = me.buttons;
@@ -34919,31 +36070,28 @@ each of the buttons in the buttons toolbar.
         }
 
         /**
-         * @cfg {Object/Array} fbar
-
-Convenience method used for adding items to the bottom of the panel. Short for Footer Bar.
-
-    fbar: [
-      { type: 'button', text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'bottom',
-        ui: 'footer',
-        defaults: {minWidth: {@link #minButtonWidth}},
-        items: [
-            { xtype: 'component', flex: 1 },
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
-
-The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
-each of the buttons in the fbar.
-
-         * @markdown
+         * @cfg {Object/Object[]} fbar
+         * Convenience config used for adding items to the bottom of the panel. Short for Footer Bar.
+         *
+         *     fbar: [
+         *       { type: 'button', text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'bottom',
+         *         ui: 'footer',
+         *         defaults: {minWidth: {@link #minButtonWidth}},
+         *         items: [
+         *             { xtype: 'component', flex: 1 },
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
+         *
+         * The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
+         * each of the buttons in the fbar.
          */
         if (me.fbar) {
             fbar = initToolbar(me.fbar, 'bottom', true); // only we useButtonAlign
@@ -34962,14 +36110,13 @@ each of the buttons in the fbar.
                 };
             }
 
-            me.addDocked(fbar);
+            docked.push(fbar);
             me.fbar = null;
         }
 
         /**
-         * @cfg {Object/Array} lbar
-         *
-         * Convenience method. Short for 'Left Bar' (left-docked, vertical toolbar).
+         * @cfg {Object/Object[]} lbar
+         * Convenience config. Short for 'Left Bar' (left-docked, vertical toolbar).
          *
          *     lbar: [
          *       { xtype: 'button', text: 'Button 1' }
@@ -34984,18 +36131,15 @@ each of the buttons in the fbar.
          *             { xtype: 'button', text: 'Button 1' }
          *         ]
          *     }]
-         *
-         * @markdown
          */
         if (me.lbar) {
-            me.addDocked(initToolbar(me.lbar, 'left'));
+            docked.push(initToolbar(me.lbar, 'left'));
             me.lbar = null;
         }
 
         /**
-         * @cfg {Object/Array} rbar
-         *
-         * Convenience method. Short for 'Right Bar' (right-docked, vertical toolbar).
+         * @cfg {Object/Object[]} rbar
+         * Convenience config. Short for 'Right Bar' (right-docked, vertical toolbar).
          *
          *     rbar: [
          *       { xtype: 'button', text: 'Button 1' }
@@ -35010,13 +36154,20 @@ each of the buttons in the fbar.
          *             { xtype: 'button', text: 'Button 1' }
          *         ]
          *     }]
-         *
-         * @markdown
          */
         if (me.rbar) {
-            me.addDocked(initToolbar(me.rbar, 'right'));
+            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;
+        }
     },
 
     /**
@@ -35027,7 +36178,7 @@ each of the buttons in the fbar.
     initTools: function() {
         var me = this;
 
-        me.tools = me.tools || [];
+        me.tools = me.tools ? Ext.Array.clone(me.tools) : [];
 
         // Add a collapse tool unless configured to not show a collapse tool
         // or to not even show a header.
@@ -35067,17 +36218,18 @@ each of the buttons in the fbar.
 
     /**
      * @private
+     * @template
      * Template method to be implemented in subclasses to add their tools after the collapsible tool.
      */
     addTools: Ext.emptyFn,
 
     /**
-     * <p>Closes the Panel. By default, this method, removes it from the DOM, {@link Ext.Component#destroy destroy}s
-     * the Panel object and all its descendant Components. The {@link #beforeclose beforeclose}
-     * event is fired before the close happens and will cancel the close action if it returns false.<p>
-     * <p><b>Note:</b> This method is not affected by the {@link #closeAction} setting which
-     * only affects the action triggered when clicking the {@link #closable 'close' tool in the header}.
-     * To hide the Panel without destroying it, call {@link #hide}.</p>
+     * Closes the Panel. By default, this method, removes it from the DOM, {@link Ext.Component#destroy destroy}s the
+     * Panel object and all its descendant Components. The {@link #beforeclose beforeclose} event is fired before the
+     * close happens and will cancel the close action if it returns false.
+     *
+     * **Note:** This method is also affected by the {@link #closeAction} setting. For more explicit control use
+     * {@link #destroy} and {@link #hide} methods.
      */
     close: function() {
         if (this.fireEvent('beforeclose', this) !== false) {
@@ -35108,7 +36260,12 @@ each of the buttons in the fbar.
 
     afterRender: function() {
         var me = this;
+
         me.callParent(arguments);
+
+        // Instate the collapsed state after render. We need to wait for
+        // this moment so that we have established at least some of our size (from our
+        // configured dimensions or from content via the component layout)
         if (me.collapsed) {
             me.collapsed = false;
             me.collapse(null, false, true);
@@ -35180,13 +36337,52 @@ each of the buttons in the fbar.
         return this.body || this.frameBody || this.el;
     },
 
+    // the overrides below allow for collapsed regions inside the border layout to be hidden
+
+    // inherit docs
+    isVisible: function(deep){
+        var me = this;
+        if (me.collapsed && me.placeholder) {
+            return me.placeholder.isVisible(deep);
+        }
+        return me.callParent(arguments);
+    },
+
+    // inherit docs
+    onHide: function(){
+        var me = this;
+        if (me.collapsed && me.placeholder) {
+            me.placeholder.hide();
+        } else {
+            me.callParent(arguments);
+        }
+    },
+
+    // inherit docs
+    onShow: function(){
+        var me = this;
+        if (me.collapsed && me.placeholder) {
+            // force hidden back to true, since this gets set by the layout
+            me.hidden = true;
+            me.placeholder.show();
+        } else {
+            me.callParent(arguments);
+        }
+    },
+
     addTool: function(tool) {
-        this.tools.push(tool);
-        var header = this.header;
+        var me = this,
+            header = me.header;
+
+        if (Ext.isArray(tool)) {
+            Ext.each(tool, me.addTool, me);
+            return;
+        }
+        me.tools.push(tool);
         if (header) {
             header.addTool(tool);
         }
-        this.updateHeader();
+        me.updateHeader();
     },
 
     getOppositeDirection: function(d) {
@@ -35204,15 +36400,18 @@ each of the buttons in the fbar.
     },
 
     /**
-     * Collapses the panel body so that the body becomes hidden. Docked Components parallel to the
-     * border towards which the collapse takes place will remain visible.  Fires the {@link #beforecollapse} event which will
-     * cancel the collapse action if it returns false.
-     * @param {String} direction. The direction to collapse towards. Must be one of<ul>
-     * <li>Ext.Component.DIRECTION_TOP</li>
-     * <li>Ext.Component.DIRECTION_RIGHT</li>
-     * <li>Ext.Component.DIRECTION_BOTTOM</li>
-     * <li>Ext.Component.DIRECTION_LEFT</li></ul>
-     * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
+     * Collapses the panel body so that the body becomes hidden. Docked Components parallel to the border towards which
+     * the collapse takes place will remain visible. Fires the {@link #beforecollapse} event which will cancel the
+     * collapse action if it returns false.
+     *
+     * @param {String} direction . The direction to collapse towards. Must be one of
+     *
+     *   - Ext.Component.DIRECTION_TOP
+     *   - Ext.Component.DIRECTION_RIGHT
+     *   - Ext.Component.DIRECTION_BOTTOM
+     *   - Ext.Component.DIRECTION_LEFT
+     *
+     * @param {Boolean} [animate] True to animate the transition, else false (defaults to the value of the
      * {@link #animCollapse} panel config)
      * @return {Ext.panel.Panel} this
      */
@@ -35247,7 +36446,6 @@ each of the buttons in the fbar.
             reExpanderOrientation,
             reExpanderDock,
             getDimension,
-            setDimension,
             collapseDimension;
 
         if (!direction) {
@@ -35270,23 +36468,22 @@ each of the buttons in the fbar.
         switch (direction) {
             case c.DIRECTION_TOP:
             case c.DIRECTION_BOTTOM:
-                me.expandedSize = me.getHeight();
                 reExpanderOrientation = 'horizontal';
                 collapseDimension = 'height';
                 getDimension = 'getHeight';
-                setDimension = 'setHeight';
 
-                // Collect the height of the visible header.
-                // Hide all docked items except the header.
-                // Hide *ALL* docked items if we're going to end up hiding the whole Panel anyway
+                // Attempt to find a reExpander Component (docked in a horizontal orientation)
+                // Also, collect all other docked items which we must hide after collapse.
                 for (; i < dockedItemCount; i++) {
                     comp = dockedItems[i];
                     if (comp.isVisible()) {
-                        if (comp.isHeader && (!comp.dock || comp.dock == 'top' || comp.dock == 'bottom')) {
+                        if (comp.isXType('header', true) && (!comp.dock || comp.dock == 'top' || comp.dock == 'bottom')) {
                             reExpander = comp;
                         } else {
                             me.hiddenDocked.push(comp);
                         }
+                    } else if (comp === me.reExpander) {
+                        reExpander = comp;
                     }
                 }
 
@@ -35298,15 +36495,12 @@ each of the buttons in the fbar.
 
             case c.DIRECTION_LEFT:
             case c.DIRECTION_RIGHT:
-                me.expandedSize = me.getWidth();
                 reExpanderOrientation = 'vertical';
                 collapseDimension = 'width';
                 getDimension = 'getWidth';
-                setDimension = 'setWidth';
 
-                // Collect the height of the visible header.
-                // Hide all docked items except the header.
-                // Hide *ALL* docked items if we're going to end up hiding the whole Panel anyway
+                // Attempt to find a reExpander Component (docked in a vecrtical orientation)
+                // Also, collect all other docked items which we must hide after collapse.
                 for (; i < dockedItemCount; i++) {
                     comp = dockedItems[i];
                     if (comp.isVisible()) {
@@ -35315,6 +36509,8 @@ each of the buttons in the fbar.
                         } else {
                             me.hiddenDocked.push(comp);
                         }
+                    } else if (comp === me.reExpander) {
+                        reExpander = comp;
                     }
                 }
 
@@ -35328,12 +36524,6 @@ each of the buttons in the fbar.
                 throw('Panel collapse must be passed a valid Component collapse direction');
         }
 
-        // No scrollbars when we shrink this Panel
-        // And no laying out of any children... we're effectively *hiding* the body
-        me.setAutoScroll(false);
-        me.suspendLayout = true;
-        me.body.setVisibilityMode(Ext.core.Element.DISPLAY);
-
         // Disable toggle tool during animated collapse
         if (animate && me.collapseTool) {
             me.collapseTool.disable();
@@ -35346,7 +36536,8 @@ each of the buttons in the fbar.
         // }
 
         // We found a header: Measure it to find the collapse-to size.
-        if (reExpander) {
+        if (reExpander && reExpander.rendered) {
+
             //we must add the collapsed cls to the header and then remove to get the proper height
             reExpander.addClsWithUI(me.collapsedCls);
             reExpander.addClsWithUI(me.collapsedCls + '-' + reExpander.dock);
@@ -35428,13 +36619,14 @@ each of the buttons in the fbar.
         if (!me.collapseMemento) {
             me.collapseMemento = new Ext.util.Memento(me);
         }
-        me.collapseMemento.capture(['width', 'height', 'minWidth', 'minHeight']);
+        me.collapseMemento.capture(['width', 'height', 'minWidth', 'minHeight', 'layoutManagedHeight', 'layoutManagedWidth']);
 
         // Remove any flex config before we attempt to collapse.
         me.savedFlex = me.flex;
         me.minWidth = 0;
         me.minHeight = 0;
         delete me.flex;
+        me.suspendLayout = true;
 
         if (animate) {
             me.animate(anim);
@@ -35455,7 +36647,22 @@ each of the buttons in the fbar.
 
         me.collapseMemento.restore(['minWidth', 'minHeight']);
 
-        me.body.hide();
+        // Now we can restore the dimension we don't control to its original state
+        // Leave the value in the memento so that it can be correctly restored
+        // if it is set by animation.
+        if (Ext.Component.VERTICAL_DIRECTION_Re.test(me.expandDirection)) {
+            me.layoutManagedHeight = 2;
+            me.collapseMemento.restore('width', false);
+        } else {
+            me.layoutManagedWidth = 2;
+            me.collapseMemento.restore('height', false);
+        }
+
+        // We must hide the body, otherwise it overlays docked items which come before
+        // it in the DOM order. Collapsing its dimension won't work - padding and borders keep a size.
+        me.saveScrollTop = me.body.dom.scrollTop;
+        me.body.setStyle('display', 'none');
+
         for (; i < l; i++) {
             me.hiddenDocked[i].hide();
         }
@@ -35464,22 +36671,24 @@ each of the buttons in the fbar.
             me.reExpander.show();
         }
         me.collapsed = true;
+        me.suspendLayout = false;
 
         if (!internal) {
-            me.doComponentLayout();
+            if (me.ownerCt) {
+                // Because Component layouts only inform upstream containers if they have changed size,
+                // explicitly lay out the container now, because the lastComponentsize will have been set by the non-animated setCalculatedSize.
+                if (animated) {
+                    me.ownerCt.layout.layout();
+                }
+            } else if (me.reExpander.temporary) {
+                me.doComponentLayout();
+            }
         }
 
         if (me.resizer) {
             me.resizer.disable();
         }
 
-        // Now we can restore the dimension we don't control to its original state
-        if (Ext.Component.VERTICAL_DIRECTION.test(me.expandDirection)) {
-            me.collapseMemento.restore('width');
-        } else {
-            me.collapseMemento.restore('height');
-        }
-
         // If me Panel was configured with a collapse tool in its header, flip it's type
         if (me.collapseTool) {
             me.collapseTool.setType('expand-' + me.expandDirection);
@@ -35495,9 +36704,9 @@ each of the buttons in the fbar.
     },
 
     /**
-     * Expands the panel body so that it becomes visible.  Fires the {@link #beforeexpand} event which will
-     * cancel the expand action if it returns false.
-     * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
+     * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will cancel the
+     * expand action if it returns false.
+     * @param {Boolean} [animate] True to animate the transition, else false (defaults to the value of the
      * {@link #animCollapse} panel config)
      * @return {Ext.panel.Panel} this
      */
@@ -35543,12 +36752,13 @@ each of the buttons in the fbar.
             me.collapseTool.setType('collapse-' + me.collapseDirection);
         }
 
+        // Restore body display and scroll position
+        me.body.setStyle('display', '');
+        me.body.dom.scrollTop = me.saveScrollTop;
+
         // Unset the flag before the potential call to calculateChildBox to calculate our newly flexed size
         me.collapsed = false;
 
-        // Collapsed means body element was hidden
-        me.body.show();
-
         // Remove any collapsed styling before any animation begins
         me.removeClsWithUI(me.collapsedCls);
         // if (me.border === false) {
@@ -35570,8 +36780,12 @@ each of the buttons in the fbar.
 
         if ((direction == Ext.Component.DIRECTION_TOP) || (direction == Ext.Component.DIRECTION_BOTTOM)) {
 
+            // Restore the collapsed dimension.
+            // Leave it in the memento, so that the final restoreAll can overwrite anything that animation does.
+            me.collapseMemento.restore('height', false);
+
             // If autoHeight, measure the height now we have shown the body element.
-            if (me.autoHeight) {
+            if (me.height === undefined) {
                 me.setCalculatedSize(me.width, null);
                 anim.to.height = me.getHeight();
 
@@ -35587,7 +36801,7 @@ each of the buttons in the fbar.
             }
             // Else, restore to saved height
             else {
-                anim.to.height = me.expandedSize;
+                anim.to.height = me.height;
             }
 
             // top needs animating upwards
@@ -35598,8 +36812,12 @@ each of the buttons in the fbar.
             }
         } else if ((direction == Ext.Component.DIRECTION_LEFT) || (direction == Ext.Component.DIRECTION_RIGHT)) {
 
+            // Restore the collapsed dimension.
+            // Leave it in the memento, so that the final restoreAll can overwrite anything that animation does.
+            me.collapseMemento.restore('width', false);
+
             // If autoWidth, measure the width now we have shown the body element.
-            if (me.autoWidth) {
+            if (me.width === undefined) {
                 me.setCalculatedSize(null, me.height);
                 anim.to.width = me.getWidth();
 
@@ -35615,7 +36833,7 @@ each of the buttons in the fbar.
             }
             // Else, restore to saved width
             else {
-                anim.to.width = me.expandedSize;
+                anim.to.width = me.width;
             }
 
             // left needs animating leftwards
@@ -35645,15 +36863,6 @@ each of the buttons in the fbar.
     afterExpand: function(animated) {
         var me = this;
 
-        if (me.collapseMemento) {
-            // collapse has to use setSize (since it takes control of the component's size in
-            // collapsed mode) and so we restore the original size now that the component has
-            // been expanded.
-            me.collapseMemento.restoreAll();
-        }
-
-        me.setAutoScroll(me.initialConfig.autoScroll);
-
         // Restored to a calculated flex. Delete the set width and height properties so that flex works from now on.
         if (me.savedFlex) {
             me.flex = me.savedFlex;
@@ -35662,8 +36871,11 @@ each of the buttons in the fbar.
             delete me.height;
         }
 
-        // Reinstate layout out after Panel has re-expanded
-        delete me.suspendLayout;
+        // Restore width/height and dimension management flags to original values
+        if (me.collapseMemento) {
+            me.collapseMemento.restoreAll();
+        }
+
         if (animated && me.ownerCt) {
             // IE 6 has an intermittent repaint issue in this case so give
             // it a little extra time to catch up before laying out.
@@ -35706,12 +36918,12 @@ each of the buttons in the fbar.
     // private
     initDraggable : function(){
         /**
-         * <p>If this Panel is configured {@link #draggable}, this property will contain
-         * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
-         * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
-         * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
-         * @type Ext.dd.DragSource.
-         * @property dd
+         * @property {Ext.dd.DragSource} dd
+         * If this Panel is configured {@link #draggable}, this property will contain an instance of {@link
+         * Ext.dd.DragSource} which handles dragging the Panel.
+         *
+         * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource} in order to
+         * supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
          */
         this.dd = Ext.create('Ext.panel.DD', this, Ext.isBoolean(this.draggable) ? null : this.draggable);
     },
@@ -35719,10 +36931,10 @@ each of the buttons in the fbar.
     // private - helper function for ghost
     ghostTools : function() {
         var tools = [],
-            origTools = this.initialConfig.tools;
+            headerTools = this.header.query('tool[hidden=false]');
 
-        if (origTools) {
-            Ext.each(origTools, function(tool) {
+        if (headerTools.length) {
+            Ext.each(headerTools, function(tool) {
                 // Some tools can be full components, and copying them into the ghost
                 // actually removes them from the owning panel. You could also potentially
                 // end up with duplicate DOM ids as well. To avoid any issues we just make
@@ -35731,8 +36943,7 @@ each of the buttons in the fbar.
                     type: tool.type
                 });
             });
-        }
-        else {
+        } else {
             tools = [{
                 type: 'placeholder'
             }];
@@ -35744,23 +36955,19 @@ each of the buttons in the fbar.
     ghost: function(cls) {
         var me = this,
             ghostPanel = me.ghostPanel,
-            box = me.getBox();
+            box = me.getBox(),
+            header;
 
         if (!ghostPanel) {
             ghostPanel = Ext.create('Ext.panel.Panel', {
-                renderTo: document.body,
+                renderTo: me.floating ? me.el.dom.parentNode : document.body,
                 floating: {
                     shadow: false
                 },
                 frame: Ext.supports.CSS3BorderRadius ? me.frame : false,
-                title: me.title,
                 overlapHeader: me.overlapHeader,
                 headerPosition: me.headerPosition,
-                width: me.getWidth(),
-                height: me.getHeight(),
-                iconCls: me.iconCls,
                 baseCls: me.baseCls,
-                tools: me.ghostTools(),
                 cls: me.baseCls + '-ghost ' + (cls ||'')
             });
             me.ghostPanel = ghostPanel;
@@ -35771,6 +36978,19 @@ each of the buttons in the fbar.
         } else {
             ghostPanel.toFront();
         }
+        header = ghostPanel.header;
+        // restore options
+        if (header) {
+            header.suspendLayout = true;
+            Ext.Array.forEach(header.query('tool'), function(tool){
+                header.remove(tool);
+            });
+            header.suspendLayout = false;
+        }
+        ghostPanel.addTool(me.ghostTools());
+        ghostPanel.setTitle(me.title);
+        ghostPanel.setIconCls(me.iconCls);
+
         ghostPanel.el.show();
         ghostPanel.setPosition(box.x, box.y);
         ghostPanel.setSize(box.width, box.height);
@@ -35806,6 +37026,8 @@ each of the buttons in the fbar.
         }
         this.callParent([resizable]);
     }
+}, function(){
+    this.prototype.animCollapse = Ext.enableFx;
 });
 
 /**
@@ -35898,7 +37120,8 @@ Ext.define('Ext.tip.Tip', {
     requires: [ 'Ext.layout.component.Tip' ],
     alternateClassName: 'Ext.Tip',
     /**
-     * @cfg {Boolean} closable True to render a close tool button into the tooltip header (defaults to false).
+     * @cfg {Boolean} [closable=false]
+     * True to render a close tool button into the tooltip header.
      */
     /**
      * @cfg {Number} width
@@ -35906,33 +37129,32 @@ Ext.define('Ext.tip.Tip', {
      * {@link #minWidth} or {@link #maxWidth}.  The maximum supported value is 500.
      */
     /**
-     * @cfg {Number} minWidth The minimum width of the tip in pixels (defaults to 40).
+     * @cfg {Number} minWidth The minimum width of the tip in pixels.
      */
     minWidth : 40,
     /**
-     * @cfg {Number} maxWidth The maximum width of the tip in pixels (defaults to 300).  The maximum supported value is 500.
+     * @cfg {Number} maxWidth The maximum width of the tip in pixels.  The maximum supported value is 500.
      */
     maxWidth : 300,
     /**
      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
-     * for bottom-right shadow (defaults to "sides").
+     * for bottom-right shadow.
      */
     shadow : "sides",
 
     /**
-     * @cfg {String} defaultAlign <b>Experimental</b>. The default {@link Ext.core.Element#alignTo} anchor position value
-     * for this tip relative to its element of origin (defaults to "tl-bl?").
+     * @cfg {String} defaultAlign
+     * <b>Experimental</b>. The default {@link Ext.Element#alignTo} anchor position value for this tip relative
+     * to its element of origin.
      */
     defaultAlign : "tl-bl?",
     /**
-     * @cfg {Boolean} constrainPosition If true, then the tooltip will be automatically constrained to stay within
-     * the browser viewport. Defaults to false.
+     * @cfg {Boolean} constrainPosition
+     * If true, then the tooltip will be automatically constrained to stay within the browser viewport.
      */
     constrainPosition : true,
 
-    /**
-     * @inherited
-     */
+    // @inherited
     frame: false,
 
     // private panel overrides
@@ -35969,10 +37191,13 @@ Ext.define('Ext.tip.Tip', {
     ariaRole: 'tooltip',
 
     initComponent: function() {
-        this.callParent(arguments);
+        var me = this;
+
+        me.floating = Ext.apply({}, {shadow: me.shadow}, me.self.prototype.floating);
+        me.callParent(arguments);
 
         // Or in the deprecated config. Floating.doConstrain only constrains if the constrain property is truthy.
-        this.constrain = this.constrain || this.constrainPosition;
+        me.constrain = me.constrain || me.constrainPosition;
     },
 
     /**
@@ -35981,11 +37206,11 @@ Ext.define('Ext.tip.Tip', {
 // Show the tip at x:50 and y:100
 tip.showAt([50,100]);
 </code></pre>
-     * @param {Array} xy An array containing the x and y coordinates
+     * @param {Number[]} xy An array containing the x and y coordinates
      */
     showAt : function(xy){
         var me = this;
-        this.callParent();
+        this.callParent(arguments);
         // Show may have been vetoed.
         if (me.isVisible()) {
             me.setPagePosition(xy[0], xy[1]);
@@ -35997,7 +37222,7 @@ tip.showAt([50,100]);
     },
 
     /**
-     * <b>Experimental</b>. Shows this tip at a position relative to another element using a standard {@link Ext.core.Element#alignTo}
+     * <b>Experimental</b>. Shows this tip at a position relative to another element using a standard {@link Ext.Element#alignTo}
      * anchor position value.  Example usage:
      * <pre><code>
 // Show the tip at the default position ('tl-br?')
@@ -36006,8 +37231,8 @@ tip.showBy('my-el');
 // Show the tip's top-left corner anchored to the element's top-right corner
 tip.showBy('my-el', 'tl-tr');
 </code></pre>
-     * @param {Mixed} el An HTMLElement, Ext.core.Element or string id of the target element to align to
-     * @param {String} position (optional) A valid {@link Ext.core.Element#alignTo} anchor position (defaults to 'tl-br?' or
+     * @param {String/HTMLElement/Ext.Element} el An HTMLElement, Ext.Element or string id of the target element to align to
+     * @param {String} [position] A valid {@link Ext.Element#alignTo} anchor position (defaults to 'tl-br?' or
      * {@link #defaultAlign} if specified).
      */
     showBy : function(el, pos) {
@@ -36025,7 +37250,7 @@ tip.showBy('my-el', 'tl-tr');
             el: me.getDragEl(),
             delegate: me.header.el,
             constrain: me,
-            constrainTo: me.el.dom.parentNode
+            constrainTo: me.el.getScopeParent()
         };
         // Important: Bypass Panel's initDraggable. Call direct to Component's implementation.
         Ext.Component.prototype.initDraggable.call(me);
@@ -36041,35 +37266,35 @@ tip.showBy('my-el', 'tl-tr');
  * tooltip when hovering over a certain element or elements on the page. It allows fine-grained
  * control over the tooltip's alignment relative to the target element or mouse, and the timing
  * of when it is automatically shown and hidden.
- * 
+ *
  * This implementation does **not** have a built-in method of automatically populating the tooltip's
  * text based on the target element; you must either configure a fixed {@link #html} value for each
  * ToolTip instance, or implement custom logic (e.g. in a {@link #beforeshow} event listener) to
  * generate the appropriate tooltip content on the fly. See {@link Ext.tip.QuickTip} for a more
  * convenient way of automatically populating and configuring a tooltip based on specific DOM
  * attributes of each target element.
- * 
+ *
  * # Basic Example
- * 
+ *
  *     var tip = Ext.create('Ext.tip.ToolTip', {
  *         target: 'clearButton',
  *         html: 'Press this button to clear the form'
  *     });
- * 
+ *
  * {@img Ext.tip.ToolTip/Ext.tip.ToolTip1.png Basic Ext.tip.ToolTip}
- * 
+ *
  * # Delegation
- * 
+ *
  * In addition to attaching a ToolTip to a single element, you can also use delegation to attach
  * one ToolTip to many elements under a common parent. This is more efficient than creating many
  * ToolTip instances. To do this, point the {@link #target} config to a common ancestor of all the
  * elements, and then set the {@link #delegate} config to a CSS selector that will select all the
  * appropriate sub-elements.
- * 
+ *
  * When using delegation, it is likely that you will want to programmatically change the content
  * of the ToolTip based on each delegate element; you can do this by implementing a custom
  * listener for the {@link #beforeshow} event. Example:
- * 
+ *
  *     var store = Ext.create('Ext.data.ArrayStore', {
  *         fields: ['company', 'price', 'change'],
  *         data: [
@@ -36081,7 +37306,7 @@ tip.showBy('my-el', 'tl-tr');
  *             ['AT&T Inc.',                           31.61, -0.48]
  *         ]
  *     });
- *  
+ *
  *     var grid = Ext.create('Ext.grid.Panel', {
  *         title: 'Array Grid',
  *         store: store,
@@ -36094,7 +37319,7 @@ tip.showBy('my-el', 'tl-tr');
  *         width: 400,
  *         renderTo: Ext.getBody()
  *     });
- *  
+ *
  *     grid.getView().on('render', function(view) {
  *         view.tip = Ext.create('Ext.tip.ToolTip', {
  *             // The overall target element.
@@ -36113,30 +37338,30 @@ tip.showBy('my-el', 'tl-tr');
  *             }
  *         });
  *     });
- * 
+ *
  * {@img Ext.tip.ToolTip/Ext.tip.ToolTip2.png Ext.tip.ToolTip with delegation}
- * 
+ *
  * # Alignment
- * 
+ *
  * The following configuration properties allow control over how the ToolTip is aligned relative to
  * the target element and/or mouse pointer:
- * 
+ *
  * - {@link #anchor}
  * - {@link #anchorToTarget}
  * - {@link #anchorOffset}
  * - {@link #trackMouse}
  * - {@link #mouseOffset}
- * 
+ *
  * # Showing/Hiding
- * 
+ *
  * The following configuration properties allow control over how and when the ToolTip is automatically
  * shown and hidden:
- * 
+ *
  * - {@link #autoHide}
  * - {@link #showDelay}
  * - {@link #hideDelay}
  * - {@link #dismissDelay}
- * 
+ *
  * @docauthor Jason Johnston <jason@sencha.com>
  */
 Ext.define('Ext.tip.ToolTip', {
@@ -36144,71 +37369,70 @@ Ext.define('Ext.tip.ToolTip', {
     alias: 'widget.tooltip',
     alternateClassName: 'Ext.ToolTip',
     /**
+     * @property {HTMLElement} triggerElement
      * When a ToolTip is configured with the `{@link #delegate}`
      * option to cause selected child elements of the `{@link #target}`
      * Element to each trigger a seperate show event, this property is set to
      * the DOM element which triggered the show.
-     * @type DOMElement
-     * @property triggerElement
      */
     /**
-     * @cfg {Mixed} target The target HTMLElement, Ext.core.Element or id to monitor
-     * for mouseover events to trigger showing this ToolTip.
+     * @cfg {HTMLElement/Ext.Element/String} target
+     * The target element or string id to monitor for mouseover events to trigger
+     * showing this ToolTip.
      */
     /**
-     * @cfg {Boolean} autoHide True to automatically hide the tooltip after the
+     * @cfg {Boolean} [autoHide=true]
+     * True to automatically hide the tooltip after the
      * mouse exits the target element or after the `{@link #dismissDelay}`
-     * has expired if set (defaults to true).  If `{@link #closable} = true`
+     * has expired if set.  If `{@link #closable} = true`
      * a close tool button will be rendered into the tooltip header.
      */
     /**
-     * @cfg {Number} showDelay Delay in milliseconds before the tooltip displays
-     * after the mouse enters the target element (defaults to 500)
+     * @cfg {Number} showDelay
+     * Delay in milliseconds before the tooltip displays after the mouse enters the target element.
      */
     showDelay: 500,
     /**
-     * @cfg {Number} hideDelay Delay in milliseconds after the mouse exits the
-     * target element but before the tooltip actually hides (defaults to 200).
+     * @cfg {Number} hideDelay
+     * Delay in milliseconds after the mouse exits the target element but before the tooltip actually hides.
      * Set to 0 for the tooltip to hide immediately.
      */
     hideDelay: 200,
     /**
-     * @cfg {Number} dismissDelay Delay in milliseconds before the tooltip
-     * automatically hides (defaults to 5000). To disable automatic hiding, set
+     * @cfg {Number} dismissDelay
+     * Delay in milliseconds before the tooltip automatically hides. To disable automatic hiding, set
      * dismissDelay = 0.
      */
     dismissDelay: 5000,
     /**
-     * @cfg {Array} mouseOffset An XY offset from the mouse position where the
-     * tooltip should be shown (defaults to [15,18]).
+     * @cfg {Number[]} [mouseOffset=[15,18]]
+     * An XY offset from the mouse position where the tooltip should be shown.
      */
     /**
-     * @cfg {Boolean} trackMouse True to have the tooltip follow the mouse as it
-     * moves over the target element (defaults to false).
+     * @cfg {Boolean} trackMouse
+     * True to have the tooltip follow the mouse as it moves over the target element.
      */
     trackMouse: false,
     /**
-     * @cfg {String} anchor If specified, indicates that the tip should be anchored to a
+     * @cfg {String} anchor
+     * If specified, indicates that the tip should be anchored to a
      * particular side of the target element or mouse pointer ("top", "right", "bottom",
      * or "left"), with an arrow pointing back at the target or mouse pointer. If
      * {@link #constrainPosition} is enabled, this will be used as a preferred value
      * only and may be flipped as needed.
      */
     /**
-     * @cfg {Boolean} anchorToTarget True to anchor the tooltip to the target
-     * element, false to anchor it relative to the mouse coordinates (defaults
-     * to true).  When `anchorToTarget` is true, use
-     * `{@link #defaultAlign}` to control tooltip alignment to the
-     * target element.  When `anchorToTarget` is false, use
-     * `{@link #anchorPosition}` instead to control alignment.
+     * @cfg {Boolean} anchorToTarget
+     * True to anchor the tooltip to the target element, false to anchor it relative to the mouse coordinates.
+     * When `anchorToTarget` is true, use `{@link #defaultAlign}` to control tooltip alignment to the
+     * target element.  When `anchorToTarget` is false, use `{@link #anchor}` instead to control alignment.
      */
     anchorToTarget: true,
     /**
-     * @cfg {Number} anchorOffset A numeric pixel value used to offset the
-     * default position of the anchor arrow (defaults to 0).  When the anchor
-     * position is on the top or bottom of the tooltip, `anchorOffset`
-     * will be used as a horizontal offset.  Likewise, when the anchor position
-     * is on the left or right side, `anchorOffset` will be used as
+     * @cfg {Number} anchorOffset
+     * A numeric pixel value used to offset the default position of the anchor arrow.  When the anchor
+     * position is on the top or bottom of the tooltip, `anchorOffset` will be used as a horizontal offset.
+     * Likewise, when the anchor position is on the left or right side, `anchorOffset` will be used as
      * a vertical offset.
      */
     anchorOffset: 0,
@@ -36224,7 +37448,7 @@ Ext.define('Ext.tip.ToolTip', {
      *
      * This may be useful when a Component has regular, repeating elements in it, each of which need a
      * ToolTip which contains information specific to that element.
-     * 
+     *
      * See the delegate example in class documentation of {@link Ext.tip.ToolTip}.
      */
 
@@ -36258,12 +37482,12 @@ Ext.define('Ext.tip.ToolTip', {
 
         me.callParent(arguments);
         zIndex = parseInt(me.el.getZIndex(), 10) || 0;
-        me.anchorEl.setStyle('z-index', zIndex + 1).setVisibilityMode(Ext.core.Element.DISPLAY);
+        me.anchorEl.setStyle('z-index', zIndex + 1).setVisibilityMode(Ext.Element.DISPLAY);
     },
 
     /**
      * Binds this ToolTip to the specified element. The tooltip will be displayed when the mouse moves over the element.
-     * @param {Mixed} t The Element, HtmlElement, or ID of an element to bind to
+     * @param {String/HTMLElement/Ext.Element} t The Element, HtmlElement, or ID of an element to bind to
      */
     setTarget: function(target) {
         var me = this,
@@ -36276,10 +37500,10 @@ Ext.define('Ext.tip.ToolTip', {
             me.mun(tg, 'mouseout', me.onTargetOut, me);
             me.mun(tg, 'mousemove', me.onMouseMove, me);
         }
-        
+
         me.target = t;
         if (t) {
-            
+
             me.mon(t, {
                 // TODO - investigate why IE6/7 seem to fire recursive resize in e.getXY
                 // breaking QuickTip#onTargetOver (EXTJSIV-1608)
@@ -36307,7 +37531,7 @@ Ext.define('Ext.tip.ToolTip', {
                 if (!me.hidden && me.trackMouse) {
                     xy = me.getTargetXY();
                     if (me.constrainPosition) {
-                        xy = me.el.adjustForConstraints(xy, me.el.dom.parentNode);
+                        xy = me.el.adjustForConstraints(xy, me.el.getScopeParent());
                     }
                     me.setPagePosition(xy);
                 }
@@ -36332,8 +37556,8 @@ Ext.define('Ext.tip.ToolTip', {
             me.targetCounter++;
                 var offsets = me.getOffsets(),
                     xy = (me.anchorToTarget && !me.trackMouse) ? me.el.getAlignToXY(me.anchorTarget, me.getAnchorAlign()) : me.targetXY,
-                    dw = Ext.core.Element.getViewWidth() - 5,
-                    dh = Ext.core.Element.getViewHeight() - 5,
+                    dw = Ext.Element.getViewWidth() - 5,
+                    dh = Ext.Element.getViewHeight() - 5,
                     de = document.documentElement,
                     bd = document.body,
                     scrollX = (de.scrollLeft || bd.scrollLeft || 0) + 5,
@@ -36731,17 +37955,17 @@ Ext.define('Ext.tip.ToolTip', {
  * @class Ext.tip.QuickTip
  * @extends Ext.tip.ToolTip
  * A specialized tooltip class for tooltips that can be specified in markup and automatically managed by the global
- * {@link Ext.tip.QuickTipManager} instance.  See the QuickTipManager class header for additional usage details and examples.
+ * {@link Ext.tip.QuickTipManager} instance.  See the QuickTipManager documentation for additional usage details and examples.
  * @xtype quicktip
  */
 Ext.define('Ext.tip.QuickTip', {
     extend: 'Ext.tip.ToolTip',
     alternateClassName: 'Ext.QuickTip',
     /**
-     * @cfg {Mixed} target The target HTMLElement, Ext.core.Element or id to associate with this Quicktip (defaults to the document).
+     * @cfg {String/HTMLElement/Ext.Element} target The target HTMLElement, Ext.Element or id to associate with this Quicktip (defaults to the document).
      */
     /**
-     * @cfg {Boolean} interceptTitles True to automatically use the element's DOM title value if available (defaults to false).
+     * @cfg {Boolean} interceptTitles True to automatically use the element's DOM title value if available.
      */
     interceptTitles : false,
 
@@ -36764,7 +37988,7 @@ Ext.define('Ext.tip.QuickTip', {
     // private
     initComponent : function(){
         var me = this;
-        
+
         me.target = me.target || Ext.getDoc();
         me.targets = me.targets || {};
         me.callParent();
@@ -36788,7 +38012,7 @@ Ext.define('Ext.tip.QuickTip', {
             i = 0,
             len = configs.length,
             target, j, targetLen;
-            
+
         for (; i < len; i++) {
             config = configs[i];
             target = config.target;
@@ -36806,20 +38030,20 @@ Ext.define('Ext.tip.QuickTip', {
 
     /**
      * Removes this quick tip from its element and destroys it.
-     * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
+     * @param {String/HTMLElement/Ext.Element} el The element from which the quick tip is to be removed or ID of the element.
      */
     unregister : function(el){
         delete this.targets[Ext.id(el)];
     },
-    
+
     /**
      * Hides a visible tip or cancels an impending show for a particular element.
-     * @param {String/HTMLElement/Element} el The element that is the target of the tip.
+     * @param {String/HTMLElement/Ext.Element} el The element that is the target of the tip or ID of the element.
      */
     cancelShow: function(el){
         var me = this,
             activeTarget = me.activeTarget;
-            
+
         el = Ext.get(el).dom;
         if (me.isVisible()) {
             if (activeTarget && activeTarget.el == el) {
@@ -36829,26 +38053,36 @@ Ext.define('Ext.tip.QuickTip', {
             me.clearTimer('show');
         }
     },
-    
+
+    /**
+     * @private
+     * Reads the tip text from the closest node to the event target which contains the attribute we
+     * are configured to look for. Returns an object containing the text from the attribute, and the target element from
+     * which the text was read.
+     */
     getTipCfg: function(e) {
         var t = e.getTarget(),
-            ttp, 
+            titleText = t.title,
             cfg;
-        
-        if(this.interceptTitles && t.title && Ext.isString(t.title)){
-            ttp = t.title;
-            t.qtip = ttp;
+
+        if (this.interceptTitles && titleText && Ext.isString(titleText)) {
+            t.qtip = titleText;
             t.removeAttribute("title");
             e.preventDefault();
-        } 
-        else {            
+            return {
+                text: titleText
+            };
+        }
+        else {
             cfg = this.tagConfig;
             t = e.getTarget('[' + cfg.namespace + cfg.attribute + ']');
             if (t) {
-                ttp = t.getAttribute(cfg.namespace + cfg.attribute);
+                return {
+                    target: t,
+                    text: t.getAttribute(cfg.namespace + cfg.attribute)
+                };
             }
         }
-        return ttp;
     },
 
     // private
@@ -36858,9 +38092,9 @@ Ext.define('Ext.tip.QuickTip', {
             elTarget,
             cfg,
             ns,
-            ttp,
+            tipConfig,
             autoHide;
-        
+
         if (me.disabled) {
             return;
         }
@@ -36873,13 +38107,13 @@ Ext.define('Ext.tip.QuickTip', {
         if(!target || target.nodeType !== 1 || target == document || 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) {
             Ext.Object.each(me.targets, function(key, value) {
                 var targetEl = Ext.fly(value.target);
@@ -36902,21 +38136,28 @@ Ext.define('Ext.tip.QuickTip', {
 
         elTarget = Ext.get(target);
         cfg = me.tagConfig;
-        ns = cfg.namespace; 
-        ttp = me.getTipCfg(e);
-        
-        if (ttp) {
+        ns = cfg.namespace;
+        tipConfig = me.getTipCfg(e);
+
+        if (tipConfig) {
+
+            // getTipCfg may look up the parentNode axis for a tip text attribute and will return the new target node.
+            // Change our target element to match that from which the tip text attribute was read.
+            if (tipConfig.target) {
+                target = tipConfig.target;
+                elTarget = Ext.get(target);
+            }
             autoHide = elTarget.getAttribute(ns + cfg.hide);
-                 
+
             me.activeTarget = {
                 el: target,
-                text: ttp,
+                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) {
@@ -36929,7 +38170,7 @@ Ext.define('Ext.tip.QuickTip', {
     // private
     onTargetOut : function(e){
         var me = this;
-        
+
         // If moving within the current target, and it does not have a new tip, ignore the mouseout
         if (me.activeTarget && e.within(me.activeTarget.el) && !me.getTipCfg(e)) {
             return;
@@ -36945,7 +38186,7 @@ Ext.define('Ext.tip.QuickTip', {
     showAt : function(xy){
         var me = this,
             target = me.activeTarget;
-        
+
         if (target) {
             if (!me.rendered) {
                 me.render(Ext.getBody());
@@ -36970,7 +38211,7 @@ Ext.define('Ext.tip.QuickTip', {
             }
 
             me.setWidth(target.width);
-            
+
             if (me.anchor) {
                 me.constrainPosition = false;
             } else if (target.align) { // TODO: this doesn't seem to work consistently
@@ -37030,20 +38271,17 @@ Ext.define('Ext.tip.QuickTip', {
  *
  * Here is an example showing how some of these config options could be used:
  *
- * {@img Ext.tip.QuickTipManager/Ext.tip.QuickTipManager.png Ext.tip.QuickTipManager component}
- *
- * ## Code
- *
+ *     @example
  *     // Init the singleton.  Any tag-based quick tips will start working.
  *     Ext.tip.QuickTipManager.init();
- *     
+ *
  *     // Apply a set of config properties to the singleton
  *     Ext.apply(Ext.tip.QuickTipManager.getQuickTip(), {
  *         maxWidth: 200,
  *         minWidth: 100,
  *         showDelay: 50      // Show 50ms after entering target
  *     });
- *     
+ *
  *     // Create a small panel to add a quick tip to
  *     Ext.create('Ext.container.Container', {
  *         id: 'quickTipContainer',
@@ -37054,8 +38292,8 @@ Ext.define('Ext.tip.QuickTip', {
  *         },
  *         renderTo: Ext.getBody()
  *     });
- *     
- *     
+ *
+ *
  *     // Manually register a quick tip for a specific element
  *     Ext.tip.QuickTipManager.register({
  *         target: 'quickTipContainer',
@@ -37076,7 +38314,7 @@ Ext.define('Ext.tip.QuickTip', {
  *  - `qwidth`: The quick tip width (equivalent to the 'width' target element config).
  *
  * Here is an example of configuring an HTML element to display a tooltip from markup:
- *     
+ *
  *     // Add a quick tip to an HTML button
  *     <input type="button" value="OK" data-qtitle="OK Button" data-qwidth="100"
  *          data-qtip="This is a quick tip from markup!"></input>
@@ -37094,9 +38332,9 @@ Ext.define('Ext.tip.QuickTipManager', function() {
 
         /**
          * Initialize the global QuickTips instance and prepare any quick tips.
-         * @param {Boolean} autoRender True to render the QuickTips container immediately to
+         * @param {Boolean} autoRender (optional) True to render the QuickTips container immediately to
          * preload images. (Defaults to true)
-         * @param {Object} config An optional config object for the created QuickTip. By
+         * @param {Object} config (optional) config object for the created QuickTip. By
          * default, the {@link Ext.tip.QuickTip QuickTip} class is instantiated, but this can
          * be changed by supplying an xtype property or a className property in this object.
          * All other properties on this object are configuration for the created component.
@@ -37213,7 +38451,7 @@ Ext.define('Ext.tip.QuickTipManager', function() {
 
         /**
          * Removes any registered quick tip from the target element and destroys it.
-         * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
+         * @param {String/HTMLElement/Ext.Element} el The element from which the quick tip is to be removed or ID of the element.
          */
         unregister : function(){
             tip.unregister.apply(tip, arguments);
@@ -37229,12 +38467,9 @@ Ext.define('Ext.tip.QuickTipManager', function() {
     };
 }());
 /**
- * @class Ext.app.Application
- * @extend Ext.app.Controller
- * 
  * Represents an Ext JS 4 application, which is typically a single page app using a {@link Ext.container.Viewport Viewport}.
  * A typical Ext.app.Application might look like this:
- * 
+ *
  *     Ext.application({
  *         name: 'MyApp',
  *         launch: function() {
@@ -37245,54 +38480,56 @@ Ext.define('Ext.tip.QuickTipManager', function() {
  *             });
  *         }
  *     });
- * 
+ *
  * This does several things. First it creates a global variable called 'MyApp' - all of your Application's classes (such
  * as its Models, Views and Controllers) will reside under this single namespace, which drastically lowers the chances
  * of colliding global variables.
- * 
+ *
  * When the page is ready and all of your JavaScript has loaded, your Application's {@link #launch} function is called,
  * at which time you can run the code that starts your app. Usually this consists of creating a Viewport, as we do in
  * the example above.
- * 
- * <u>Telling Application about the rest of the app</u>
- * 
+ *
+ * # Telling Application about the rest of the app
+ *
  * Because an Ext.app.Application represents an entire app, we should tell it about the other parts of the app - namely
  * the Models, Views and Controllers that are bundled with the application. Let's say we have a blog management app; we
  * might have Models and Controllers for Posts and Comments, and Views for listing, adding and editing Posts and Comments.
  * Here's how we'd tell our Application about all these things:
- * 
+ *
  *     Ext.application({
  *         name: 'Blog',
  *         models: ['Post', 'Comment'],
  *         controllers: ['Posts', 'Comments'],
- *     
+ *
  *         launch: function() {
  *             ...
  *         }
  *     });
- * 
+ *
  * Note that we didn't actually list the Views directly in the Application itself. This is because Views are managed by
- * Controllers, so it makes sense to keep those dependencies there. The Application will load each of the specified 
- * Controllers using the pathing conventions laid out in the <a href="../guide/application_architecture">application 
- * architecture guide</a> - in this case expecting the controllers to reside in app/controller/Posts.js and
- * app/controller/Comments.js. In turn, each Controller simply needs to list the Views it uses and they will be
+ * Controllers, so it makes sense to keep those dependencies there. The Application will load each of the specified
+ * Controllers using the pathing conventions laid out in the [application architecture guide][mvc] -
+ * in this case expecting the controllers to reside in `app/controller/Posts.js` and
+ * `app/controller/Comments.js`. In turn, each Controller simply needs to list the Views it uses and they will be
  * automatically loaded. Here's how our Posts controller like be defined:
- * 
+ *
  *     Ext.define('MyApp.controller.Posts', {
  *         extend: 'Ext.app.Controller',
  *         views: ['posts.List', 'posts.Edit'],
- *     
+ *
  *         //the rest of the Controller here
  *     });
- * 
+ *
  * Because we told our Application about our Models and Controllers, and our Controllers about their Views, Ext JS will
  * automatically load all of our app files for us. This means we don't have to manually add script tags into our html
- * files whenever we add a new class, but more importantly it enables us to create a minimized build of our entire 
+ * files whenever we add a new class, but more importantly it enables us to create a minimized build of our entire
  * application using the Ext JS 4 SDK Tools.
- * 
+ *
  * For more information about writing Ext JS 4 applications, please see the
- * [application architecture guide](#/guide/application_architecture).
- * 
+ * [application architecture guide][mvc].
+ *
+ * [mvc]: #!/guide/application_architecture
+ *
  * @docauthor Ed Spencer
  */
 Ext.define('Ext.app.Application', {
@@ -37319,30 +38556,29 @@ Ext.define('Ext.app.Application', {
     scope: undefined,
 
     /**
-     * @cfg {Boolean} enableQuickTips True to automatically set up Ext.tip.QuickTip support (defaults to true)
+     * @cfg {Boolean} enableQuickTips True to automatically set up Ext.tip.QuickTip support.
      */
     enableQuickTips: true,
 
     /**
-     * @cfg {String} defaultUrl When the app is first loaded, this url will be redirected to. Defaults to undefined
+     * @cfg {String} defaultUrl When the app is first loaded, this url will be redirected to.
      */
 
     /**
      * @cfg {String} appFolder The path to the directory which contains all application's classes.
      * This path will be registered via {@link Ext.Loader#setPath} for the namespace specified in the {@link #name name} config.
-     * Defaults to 'app'
      */
     appFolder: 'app',
 
     /**
      * @cfg {Boolean} autoCreateViewport True to automatically load and instantiate AppName.view.Viewport
-     * before firing the launch function (defaults to false).
+     * before firing the launch function.
      */
     autoCreateViewport: false,
 
     /**
      * Creates new Application.
-     * @param {Object} config (optional) Config object.
+     * @param {Object} [config] Config object.
      */
     constructor: function(config) {
         config = config || {};
@@ -37708,7 +38944,7 @@ Ext.define('Ext.draw.CompositeSprite', {
         });
     },
 
-    /** Add a Sprite to the Group */
+    // Inherit docs from MixedCollection
     add: function(key, o) {
         var result = this.callParent(arguments);
         this.attachEvents(result);
@@ -37719,7 +38955,7 @@ Ext.define('Ext.draw.CompositeSprite', {
         return this.callParent(arguments);
     },
 
-    /** Remove a Sprite from the Group */
+    // Inherit docs from MixedCollection
     remove: function(o) {
         var me = this;
         
@@ -37731,13 +38967,14 @@ Ext.define('Ext.draw.CompositeSprite', {
             mouseout: me.onMouseOut,
             click: me.onClick
         });
-        me.callParent(arguments);
+        return me.callParent(arguments);
     },
     
     /**
      * Returns the group bounding box.
-     * Behaves like {@link Ext.draw.Sprite} getBBox method.
-    */
+     * Behaves like {@link Ext.draw.Sprite#getBBox} method.
+     * @return {Object} an object with x, y, width, and height properties.
+     */
     getBBox: function() {
         var i = 0,
             sprite,
@@ -37771,10 +39008,11 @@ Ext.define('Ext.draw.CompositeSprite', {
     },
 
     /**
-     *  Iterates through all sprites calling
-     *  `setAttributes` on each one. For more information
-     *  {@link Ext.draw.Sprite} provides a description of the
-     *  attributes that can be set with this method.
+     * Iterates through all sprites calling `setAttributes` on each one. For more information {@link Ext.draw.Sprite}
+     * provides a description of the attributes that can be set with this method.
+     * @param {Object} attrs Attributes to be changed on the sprite.
+     * @param {Boolean} redraw Flag to immediatly draw the change.
+     * @return {Ext.draw.CompositeSprite} this
      */
     setAttributes: function(attrs, redraw) {
         var i = 0,
@@ -37790,6 +39028,8 @@ Ext.define('Ext.draw.CompositeSprite', {
     /**
      * Hides all sprites. If the first parameter of the method is true
      * then a redraw will be forced for each sprite.
+     * @param {Boolean} redraw Flag to immediatly draw the change.
+     * @return {Ext.draw.CompositeSprite} this
      */
     hide: function(redraw) {
         var i = 0,
@@ -37805,6 +39045,8 @@ Ext.define('Ext.draw.CompositeSprite', {
     /**
      * Shows all sprites. If the first parameter of the method is true
      * then a redraw will be forced for each sprite.
+     * @param {Boolean} redraw Flag to immediatly draw the change.
+     * @return {Ext.draw.CompositeSprite} this
      */
     show: function(redraw) {
         var i = 0,
@@ -37906,27 +39148,28 @@ Ext.define('Ext.draw.CompositeSprite', {
 });
 
 /**
- * @class Ext.layout.component.Draw
+ * @class Ext.layout.component.Auto
  * @extends Ext.layout.component.Component
  * @private
  *
+ * <p>The AutoLayout is the default layout manager delegated by {@link Ext.Component} to
+ * render any child Elements when no <tt>{@link Ext.container.Container#layout layout}</tt> is configured.</p>
  */
 
-Ext.define('Ext.layout.component.Draw', {
+Ext.define('Ext.layout.component.Auto', {
 
     /* Begin Definitions */
 
-    alias: 'layout.draw',
+    alias: 'layout.autocomponent',
 
-    extend: 'Ext.layout.component.Auto',
+    extend: 'Ext.layout.component.Component',
 
     /* End Definitions */
 
-    type: 'draw',
+    type: 'autocomponent',
 
     onLayout : function(width, height) {
-        this.owner.surface.setSize(width, height);
-        this.callParent(arguments);
+        this.setTargetSize(width, height);
     }
 });
 /**
@@ -38218,6 +39461,7 @@ function() {
  * 
  */
 Ext.define('Ext.chart.Mask', {
+    require: ['Ext.chart.MaskLayer'],
     /**
      * Creates new Mask.
      * @param {Object} config (optional) Config object.
@@ -38364,12 +39608,7 @@ Ext.define('Ext.chart.Mask', {
                 width: abs(width),
                 height: abs(height)
             };
-            me.mask.updateBox({
-                x: posX - abs(width),
-                y: posY - abs(height),
-                width: abs(width),
-                height: abs(height)
-            });
+            me.mask.updateBox(me.maskSelection);
             me.mask.show();
             me.maskSprite.setAttributes({
                 hidden: true    
@@ -38408,7 +39647,7 @@ Ext.define('Ext.chart.Mask', {
  * @class Ext.chart.Navigation
  *
  * Handles panning and zooming capabilities.
- * 
+ *
  * Used as mixin by Ext.chart.Chart.
  */
 Ext.define('Ext.chart.Navigation', {
@@ -38416,49 +39655,68 @@ Ext.define('Ext.chart.Navigation', {
     constructor: function() {
         this.originalStore = this.store;
     },
-    
-    //filters the store to the specified interval(s)
+
+    /**
+     * Zooms the chart to the specified selection range.
+     * Can be used with a selection mask. For example:
+     *
+     *     items: {
+     *         xtype: 'chart',
+     *         animate: true,
+     *         store: store1,
+     *         mask: 'horizontal',
+     *         listeners: {
+     *             select: {
+     *                 fn: function(me, selection) {
+     *                     me.setZoom(selection);
+     *                     me.mask.hide();
+     *                 }
+     *             }
+     *         }
+     *     }
+     */
     setZoom: function(zoomConfig) {
         var me = this,
-            store = me.substore || me.store,
+            axes = me.axes,
             bbox = me.chartBBox,
-            len = store.getCount(),
-            from = (zoomConfig.x / bbox.width * len) >> 0,
-            to = Math.ceil(((zoomConfig.x + zoomConfig.width) / bbox.width * len)),
-            recFieldsLen, recFields = [], curField, json = [], obj;
-        
-        store.each(function(rec, i) {
-            if (i < from || i > to) {
-                return;
-            }
-            obj = {};
-            //get all record field names in a simple array
-            if (!recFields.length) {
-                rec.fields.each(function(f) {
-                    recFields.push(f.name);
-                });
-                recFieldsLen = recFields.length;
-            }
-            //append record values to an aggregation record
-            for (i = 0; i < recFieldsLen; i++) {
-                curField = recFields[i];
-                obj[curField] = rec.get(curField);
+            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
+            };
+        axes.each(function(axis) {
+            var ends = axis.calcEnds();
+            if (axis.position == 'bottom' || axis.position == 'top') {
+                var from = (ends.to - ends.from) * zoomer.x + ends.from,
+                    to = (ends.to - ends.from) * zoomer.width + from;
+                axis.minimum = from;
+                axis.maximum = to;
+            } else {
+                var to = (ends.to - ends.from) * (1 - zoomer.y) + ends.from,
+                    from = to - (ends.to - ends.from) * zoomer.height;
+                axis.minimum = from;
+                axis.maximum = to;
             }
-            json.push(obj);
-        });
-        me.store = me.substore = Ext.create('Ext.data.JsonStore', {
-            fields: recFields,
-            data: json
         });
-        me.redraw(true);
+        me.redraw(false);
     },
 
+    /**
+     * Restores the zoom to the original value. This can be used to reset
+     * the previous zoom state set by `setZoom`. For example:
+     *
+     *     myChart.restoreZoom();
+     */
     restoreZoom: function() {
         this.store = this.substore = this.originalStore;
         this.redraw(true);
     }
-    
+
 });
+
 /**
  * @class Ext.chart.Shape
  * @ignore
@@ -38605,7 +39863,7 @@ Ext.define('Ext.chart.Shape', {
  *
  *     drawComponent.surface.on({
  *        'mousemove': function() {
- *             console.log('moving the mouse over the surface');   
+ *             console.log('moving the mouse over the surface');
  *         }
  *     });
  *
@@ -38616,7 +39874,7 @@ Ext.define('Ext.chart.Shape', {
  *         height: 600,
  *         renderTo: document.body
  *     }), surface = drawComponent.surface;
- *   
+ *
  *     surface.add([{
  *         type: 'circle',
  *         radius: 10,
@@ -38663,7 +39921,7 @@ Ext.define('Ext.chart.Shape', {
  *         y: 100,
  *         group: 'rectangles'
  *     }]);
- *   
+ *
  *     // Get references to my groups
  *     circles = surface.getGroup('circles');
  *     rectangles = surface.getGroup('rectangles');
@@ -38677,7 +39935,7 @@ Ext.define('Ext.chart.Shape', {
  *             }
  *         }
  *     });
- *   
+ *
  *     // Animate the rectangles across
  *     rectangles.animate({
  *         duration: 1000,
@@ -38705,7 +39963,7 @@ Ext.define('Ext.draw.Surface', {
         /**
          * Creates and returns a new concrete Surface instance appropriate for the current environment.
          * @param {Object} config Initial configuration for the Surface instance
-         * @param {[String]} enginePriority Optional order of implementations to use; the first one that is
+         * @param {String[]} enginePriority (Optional) order of implementations to use; the first one that is
          * available in the current environment will be used. Defaults to `['Svg', 'Vml']`.
          * @return {Object} The created Surface or false.
          * @static
@@ -38774,12 +40032,10 @@ Ext.define('Ext.draw.Surface', {
     /**
      * @cfg {Number} height
      * The height of this component in pixels (defaults to auto).
-     * **Note** to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
      */
     /**
      * @cfg {Number} width
      * The width of this component in pixels (defaults to auto).
-     * **Note** to express this dimension as a percentage or offset see {@link Ext.Component#anchor}.
      */
 
     container: undefined,
@@ -38788,6 +40044,13 @@ Ext.define('Ext.draw.Surface', {
     x: 0,
     y: 0,
 
+    /**
+     * @private Flag indicating that the surface implementation requires sprites to be maintained
+     * in order of their zIndex. Impls that don't require this can set it to false.
+     */
+    orderSpritesByZIndex: true,
+
+
     /**
      * Creates new Surface.
      * @param {Object} config (optional) Config object.
@@ -38798,7 +40061,7 @@ Ext.define('Ext.draw.Surface', {
         Ext.apply(me, config);
 
         me.domRef = Ext.getDoc().dom;
-        
+
         me.customAttributes = {};
 
         me.addEvents(
@@ -38836,7 +40099,12 @@ Ext.define('Ext.draw.Surface', {
     renderItems: Ext.emptyFn,
 
     // @private
-    setViewBox: 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();
+        }
+    },
 
     /**
      * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
@@ -38846,7 +40114,7 @@ Ext.define('Ext.draw.Surface', {
      *     drawComponent.surface.addCls(sprite, 'x-visible');
      *
      * @param {Object} sprite The sprite to add the class to.
-     * @param {String/[String]} className The CSS class to add, or an array of classes
+     * @param {String/String[]} className The CSS class to add, or an array of classes
      * @method
      */
     addCls: Ext.emptyFn,
@@ -38859,7 +40127,7 @@ Ext.define('Ext.draw.Surface', {
      *     drawComponent.surface.removeCls(sprite, 'x-visible');
      *
      * @param {Object} sprite The sprite to remove the class from.
-     * @param {String/[String]} className The CSS class to remove, or an array of classes
+     * @param {String/String[]} className The CSS class to remove, or an array of classes
      * @method
      */
     removeCls: Ext.emptyFn,
@@ -38896,7 +40164,7 @@ Ext.define('Ext.draw.Surface', {
             this.add(items);
         }
     },
-    
+
     // @private
     initBackground: function(config) {
         var me = this,
@@ -38937,7 +40205,7 @@ Ext.define('Ext.draw.Surface', {
             }
         }
     },
-    
+
     /**
      * Sets the size of the surface. Accomodates the background (if any) to fit the new size too.
      *
@@ -38946,7 +40214,7 @@ Ext.define('Ext.draw.Surface', {
      *     drawComponent.surface.setSize(500, 500);
      *
      * This method is generally called when also setting the size of the draw Component.
-     * 
+     *
      * @param {Number} w The new width of the canvas.
      * @param {Number} h The new height of the canvas.
      */
@@ -38958,6 +40226,7 @@ Ext.define('Ext.draw.Surface', {
                 hidden: false
             }, true);
         }
+        this.applyViewBox();
     },
 
     // @private
@@ -38966,7 +40235,7 @@ Ext.define('Ext.draw.Surface', {
             attrs = {},
             exclude = {},
             sattr = sprite.attr;
-        for (i in sattr) {    
+        for (i in sattr) {
             // Narrow down attributes to the main set
             if (this.translateAttrs.hasOwnProperty(i)) {
                 // Translated attr
@@ -39026,7 +40295,7 @@ Ext.define('Ext.draw.Surface', {
      * configuration object please refer to {@link Ext.chart.Chart}.
      *
      * The gradient object to be passed into this method is composed by:
-     * 
+     *
      * - **id** - string - The unique name of the gradient.
      * - **angle** - number, optional - The angle of the gradient in degrees.
      * - **stops** - object - An object with numbers as keys (from 0 to 100) and style objects as values.
@@ -39085,38 +40354,53 @@ Ext.define('Ext.draw.Surface', {
             return results;
         }
         sprite = this.prepareItems(args[0], true)[0];
-        this.normalizeSpriteCollection(sprite);
+        this.insertByZIndex(sprite);
         this.onAdd(sprite);
         return sprite;
     },
 
     /**
      * @private
-     * Inserts or moves a given sprite into the correct position in the items
-     * MixedCollection, according to its zIndex. Will be inserted at the end of
-     * an existing series of sprites with the same or lower zIndex. If the sprite
-     * is already positioned within an appropriate zIndex group, it will not be moved.
-     * This ordering can be used by subclasses to assist in rendering the sprites in
-     * the correct order for proper z-index stacking.
+     * Inserts a given sprite into the correct position in the items collection, according to
+     * its zIndex. It will be inserted at the end of an existing series of sprites with the same or
+     * lower zIndex. By ensuring sprites are always ordered, this allows surface subclasses to render
+     * the sprites in the correct order for proper z-index stacking.
      * @param {Ext.draw.Sprite} sprite
      * @return {Number} the sprite's new index in the list
      */
-    normalizeSpriteCollection: function(sprite) {
-        var items = this.items,
+    insertByZIndex: function(sprite) {
+        var me = this,
+            sprites = me.items.items,
+            len = sprites.length,
+            ceil = Math.ceil,
             zIndex = sprite.attr.zIndex,
-            idx = items.indexOf(sprite);
-
-        if (idx < 0 || (idx > 0 && items.getAt(idx - 1).attr.zIndex > zIndex) ||
-                (idx < items.length - 1 && items.getAt(idx + 1).attr.zIndex < zIndex)) {
-            items.removeAt(idx);
-            idx = items.findIndexBy(function(otherSprite) {
-                return otherSprite.attr.zIndex > zIndex;
-            });
-            if (idx < 0) {
-                idx = items.length;
+            idx = len,
+            high = idx - 1,
+            low = 0,
+            otherZIndex;
+
+        if (me.orderSpritesByZIndex && len && zIndex < sprites[high].attr.zIndex) {
+            // Find the target index via a binary search for speed
+            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;
+                }
+            }
+            // Step forward to the end of a sequence of the same or lower z-index
+            while (idx < len && sprites[idx].attr.zIndex <= zIndex) {
+                idx++;
             }
-            items.insert(idx, sprite);
         }
+
+        me.items.insert(idx, sprite);
         return idx;
     },
 
@@ -39188,6 +40472,52 @@ Ext.define('Ext.draw.Surface', {
 
     onDestroy: Ext.emptyFn,
 
+    /**
+     * @private Using the current viewBox property and the surface's width and height, calculate the
+     * appropriate viewBoxShift that will be applied as a persistent transform to all sprites.
+     */
+    applyViewBox: function() {
+        var me = this,
+            viewBox = me.viewBox,
+            width = me.width,
+            height = me.height,
+            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;
+
+            if (viewBoxWidth * relativeHeight < width) {
+                viewBoxX -= (width - viewBoxWidth * relativeHeight) / 2 / relativeHeight;
+            }
+            if (viewBoxHeight * relativeWidth < height) {
+                viewBoxY -= (height - viewBoxHeight * relativeWidth) / 2 / relativeWidth;
+            }
+
+            size = 1 / Math.min(viewBoxWidth, relativeHeight);
+
+            me.viewBoxShift = {
+                dx: -viewBoxX,
+                dy: -viewBoxY,
+                scale: size
+            };
+        }
+    },
+
+    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];
+        }
+    },
+
     // @private
     applyTransformations: function(sprite) {
             sprite.bbox.transform = 0;
@@ -39373,7 +40703,7 @@ Ext.define('Ext.draw.Surface', {
         }
         return items;
     },
-    
+
     /**
      * Changes the text in the sprite element. The sprite must be a `text` sprite.
      * This method can also be called from {@link Ext.draw.Sprite}.
@@ -39387,7 +40717,7 @@ Ext.define('Ext.draw.Surface', {
      * @method
      */
     setText: Ext.emptyFn,
-    
+
     //@private Creates an item and appends it to the surface. Called
     //as an internal method when calling `add`.
     createItem: Ext.emptyFn,
@@ -39413,6 +40743,30 @@ Ext.define('Ext.draw.Surface', {
         this.removeAll();
     }
 });
+/**
+ * @class Ext.layout.component.Draw
+ * @extends Ext.layout.component.Component
+ * @private
+ *
+ */
+
+Ext.define('Ext.layout.component.Draw', {
+
+    /* Begin Definitions */
+
+    alias: 'layout.draw',
+
+    extend: 'Ext.layout.component.Auto',
+
+    /* End Definitions */
+
+    type: 'draw',
+
+    onLayout : function(width, height) {
+        this.owner.surface.setSize(width, height);
+        this.callParent(arguments);
+    }
+});
 /**
  * @class Ext.draw.Component
  * @extends Ext.Component
@@ -39421,9 +40775,10 @@ Ext.define('Ext.draw.Surface', {
  * manages and holds a `Surface` instance: an interface that has
  * an SVG or VML implementation depending on the browser capabilities and where
  * Sprites can be appended.
- * {@img Ext.draw.Component/Ext.draw.Component.png Ext.draw.Component component}
+ *
  * One way to create a draw component is:
- * 
+ *
+ *     @example
  *     var drawComponent = Ext.create('Ext.draw.Component', {
  *         viewBox: false,
  *         items: [{
@@ -39434,21 +40789,21 @@ Ext.define('Ext.draw.Surface', {
  *             y: 100
  *         }]
  *     });
- *   
+ *
  *     Ext.create('Ext.Window', {
  *         width: 215,
  *         height: 235,
  *         layout: 'fit',
  *         items: [drawComponent]
  *     }).show();
- * 
+ *
  * In this case we created a draw component and added a sprite to it.
  * The *type* of the sprite is *circle* so if you run this code you'll see a yellow-ish
  * circle in a Window. When setting `viewBox` to `false` we are responsible for setting the object's position and
- * dimensions accordingly. 
- * 
+ * dimensions accordingly.
+ *
  * You can also add sprites by using the surface's add method:
- *    
+ *
  *     drawComponent.surface.add({
  *         type: 'circle',
  *         fill: '#79BB3F',
@@ -39456,7 +40811,7 @@ Ext.define('Ext.draw.Surface', {
  *         x: 100,
  *         y: 100
  *     });
- *  
+ *
  * For more information on Sprites, the core elements added to a draw component's surface,
  * refer to the Ext.draw.Sprite documentation.
  */
@@ -39476,7 +40831,7 @@ Ext.define('Ext.draw.Component', {
     /* End Definitions */
 
     /**
-     * @cfg {Array} enginePriority
+     * @cfg {String[]} enginePriority
      * Defines the priority order for which Surface implementation to use. The first
      * one supported by the current environment will be used.
      */
@@ -39498,60 +40853,50 @@ Ext.define('Ext.draw.Component', {
      * Turn on autoSize support which will set the bounding div's size to the natural size of the contents. Defaults to false.
      */
     autoSize: false,
-    
+
     /**
-     * @cfg {Array} gradients (optional) Define a set of gradients that can be used as `fill` property in sprites.
+     * @cfg {Object[]} gradients (optional) Define a set of gradients that can be used as `fill` property in sprites.
      * The gradients array is an array of objects with the following properties:
      *
-     * <ul>
-     * <li><strong>id</strong> - string - The unique name of the gradient.</li>
-     * <li><strong>angle</strong> - number, optional - The angle of the gradient in degrees.</li>
-     * <li><strong>stops</strong> - object - An object with numbers as keys (from 0 to 100) and style objects
-     * as values</li>
-     * </ul>
-     * 
-     
-     For example:
-     
-     <pre><code>
-        gradients: [{
-            id: 'gradientId',
-            angle: 45,
-            stops: {
-                0: {
-                    color: '#555'
-                },
-                100: {
-                    color: '#ddd'
-                }
-            }
-        },  {
-            id: 'gradientId2',
-            angle: 0,
-            stops: {
-                0: {
-                    color: '#590'
-                },
-                20: {
-                    color: '#599'
-                },
-                100: {
-                    color: '#ddd'
-                }
-            }
-        }]
-     </code></pre>
-     
-     Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:
-     
-     <pre><code>
-        sprite.setAttributes({
-            fill: 'url(#gradientId)'
-        }, true);
-     </code></pre>
-     
+     *  - `id` - string - The unique name of the gradient.
+     *  - `angle` - number, optional - The angle of the gradient in degrees.
+     *  - `stops` - object - An object with numbers as keys (from 0 to 100) and style objects as values
+     *
+     * ## Example
+     *
+     *     gradients: [{
+     *         id: 'gradientId',
+     *         angle: 45,
+     *         stops: {
+     *             0: {
+     *                 color: '#555'
+     *             },
+     *             100: {
+     *                 color: '#ddd'
+     *             }
+     *         }
+     *     }, {
+     *         id: 'gradientId2',
+     *         angle: 0,
+     *         stops: {
+     *             0: {
+     *                 color: '#590'
+     *             },
+     *             20: {
+     *                 color: '#599'
+     *             },
+     *             100: {
+     *                 color: '#ddd'
+     *             }
+     *         }
+     *     }]
+     *
+     * Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:
+     *
+     *     sprite.setAttributes({
+     *         fill: 'url(#gradientId)'
+     *     }, true);
      */
-
     initComponent: function() {
         this.callParent(arguments);
 
@@ -39577,22 +40922,22 @@ Ext.define('Ext.draw.Component', {
             bbox, items, width, height, x, y;
         me.callParent(arguments);
 
-        me.createSurface();
+        if (me.createSurface() !== false) {
+            items = me.surface.items;
 
-        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 {
-                // AutoSized
-                me.autoSizeSurface();
+            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 {
+                    // AutoSized
+                    me.autoSizeSurface();
+                }
             }
         }
     },
@@ -39626,9 +40971,7 @@ Ext.define('Ext.draw.Component', {
      * instantiate based on the 'enginePriority' config. Once the Surface instance is
      * created you can use the handle to that instance to add sprites. For example:
      *
-     <pre><code>
-        drawComponent.surface.add(sprite);
-     </code></pre>
+     *     drawComponent.surface.add(sprite);
      */
     createSurface: function() {
         var surface = Ext.draw.Surface.create(Ext.apply({}, {
@@ -39636,8 +40979,13 @@ Ext.define('Ext.draw.Component', {
                 height: this.height,
                 renderTo: this.el
             }, this.initialConfig));
+        if (!surface) {
+            // In case we cannot create a surface, return false so we can stop
+            return false;
+        }
         this.surface = surface;
 
+
         function refire(eventName) {
             return function(e) {
                 this.fireEvent(eventName, e);
@@ -39658,7 +41006,7 @@ Ext.define('Ext.draw.Component', {
 
     /**
      * @private
-     * 
+     *
      * Clean up the Surface instance on component destruction
      */
     onDestroy: function() {
@@ -39881,6 +41229,7 @@ Ext.define('Ext.chart.LegendItem', {
         }
     }
 });
+
 /**
  * @class Ext.chart.Legend
  *
@@ -39897,72 +41246,74 @@ Ext.define('Ext.chart.LegendItem', {
  *     legend: {
  *         position: 'right'
  *     },
- * 
- * Full example:
-    <pre><code>
-    var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        animate: true,
-        store: store,
-        shadow: true,
-        theme: 'Category1',
-        legend: {
-            position: 'top'
-        },
-         axes: [{
-                type: 'Numeric',
-                grid: true,
-                position: 'left',
-                fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
-                title: 'Sample Values',
-                grid: {
-                    odd: {
-                        opacity: 1,
-                        fill: '#ddd',
-                        stroke: '#bbb',
-                        'stroke-width': 1
-                    }
-                },
-                minimum: 0,
-                adjustMinimumByMajorUnit: 0
-            }, {
-                type: 'Category',
-                position: 'bottom',
-                fields: ['name'],
-                title: 'Sample Metrics',
-                grid: true,
-                label: {
-                    rotate: {
-                        degrees: 315
-                    }
-                }
-        }],
-        series: [{
-            type: 'area',
-            highlight: false,
-            axis: 'left',
-            xField: 'name',
-            yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
-            style: {
-                opacity: 0.93
-            }
-        }]
-    });    
-    </code></pre>    
  *
+ * ## Example
+ *
+ *     @example
+ *     var store = Ext.create('Ext.data.JsonStore', {
+ *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
+ *         data: [
+ *             { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
+ *             { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
+ *             { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
+ *             { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
+ *             { 'name': 'metric five',  'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
+ *         ]
+ *     });
+ *
+ *     Ext.create('Ext.chart.Chart', {
+ *         renderTo: Ext.getBody(),
+ *         width: 500,
+ *         height: 300,
+ *         animate: true,
+ *         store: store,
+ *         shadow: true,
+ *         theme: 'Category1',
+ *         legend: {
+ *             position: 'top'
+ *         },
+ *         axes: [
+ *             {
+ *                 type: 'Numeric',
+ *                 grid: true,
+ *                 position: 'left',
+ *                 fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *                 title: 'Sample Values',
+ *                 grid: {
+ *                     odd: {
+ *                         opacity: 1,
+ *                         fill: '#ddd',
+ *                         stroke: '#bbb',
+ *                         'stroke-width': 1
+ *                     }
+ *                 },
+ *                 minimum: 0,
+ *                 adjustMinimumByMajorUnit: 0
+ *             },
+ *             {
+ *                 type: 'Category',
+ *                 position: 'bottom',
+ *                 fields: ['name'],
+ *                 title: 'Sample Metrics',
+ *                 grid: true,
+ *                 label: {
+ *                     rotate: {
+ *                         degrees: 315
+ *                     }
+ *                 }
+ *             }
+ *         ],
+ *         series: [{
+ *             type: 'area',
+ *             highlight: false,
+ *             axis: 'left',
+ *             xField: 'name',
+ *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *             style: {
+ *                 opacity: 0.93
+ *             }
+ *         }]
+ *     });
  */
 Ext.define('Ext.chart.Legend', {
 
@@ -39988,7 +41339,7 @@ Ext.define('Ext.chart.Legend', {
 
     /**
      * @cfg {Number} x
-     * X-position of the legend box. Used directly if position is set to "float", otherwise 
+     * X-position of the legend box. Used directly if position is set to "float", otherwise
      * it will be calculated dynamically.
      */
     x: 0,
@@ -40062,7 +41413,7 @@ Ext.define('Ext.chart.Legend', {
          * @type {Boolean}
          */
         me.isVertical = ("left|right|float".indexOf(me.position) !== -1);
-        
+
         // cache these here since they may get modified later on
         me.origX = me.x;
         me.origY = me.y;
@@ -40073,9 +41424,9 @@ Ext.define('Ext.chart.Legend', {
      */
     create: function() {
         var me = this;
+        me.createBox();
         me.createItems();
         if (!me.created && me.isDisplayed()) {
-            me.createBox();
             me.created = true;
 
             // Listen for changes to series titles to trigger regeneration of the legend
@@ -40115,8 +41466,8 @@ Ext.define('Ext.chart.Legend', {
             math = Math,
             mfloor = math.floor,
             mmax = math.max,
-            index = 0, 
-            i = 0, 
+            index = 0,
+            i = 0,
             len = items ? items.length : 0,
             x, y, spacing, item, bbox, height, width;
 
@@ -40142,7 +41493,7 @@ Ext.define('Ext.chart.Legend', {
                     bbox = item.getBBox();
 
                     //always measure from x=0, since not all markers go all the way to the left
-                    width = bbox.width; 
+                    width = bbox.width;
                     height = bbox.height;
 
                     if (i + j === 0) {
@@ -40193,13 +41544,20 @@ Ext.define('Ext.chart.Legend', {
      */
     createBox: function() {
         var me = this,
-            box = me.boxSprite = me.chart.surface.add(Ext.apply({
-                type: 'rect',
-                stroke: me.boxStroke,
-                "stroke-width": me.boxStrokeWidth,
-                fill: me.boxFill,
-                zIndex: me.boxZIndex
-            }, me.getBBox()));
+            box;
+
+        if (me.boxSprite) {
+            me.boxSprite.destroy();
+        }
+        
+        box = me.boxSprite = me.chart.surface.add(Ext.apply({
+            type: 'rect',
+            stroke: me.boxStroke,
+            "stroke-width": me.boxStrokeWidth,
+            fill: me.boxFill,
+            zIndex: me.boxZIndex
+        }, me.getBBox()));
+
         box.redraw();
     },
 
@@ -40221,7 +41579,7 @@ Ext.define('Ext.chart.Legend', {
             chartY = chartBBox.y + insets,
             surface = chart.surface,
             mfloor = Math.floor;
-        
+
         if (me.isDisplayed()) {
             // Find the position based on the dimensions
             switch(me.position) {
@@ -40257,37 +41615,143 @@ Ext.define('Ext.chart.Legend', {
         }
     }
 });
+
 /**
- * @class Ext.chart.Chart
- * @extends Ext.draw.Component
- *
- * The Ext.chart package provides the capability to visualize data.
- * Each chart binds directly to an Ext.data.Store enabling automatic updates of the chart.
- * A chart configuration object has some overall styling options as well as an array of axes
- * and series. A chart instance example could look like:
- *
-  <pre><code>
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 800,
-        height: 600,
-        animate: true,
-        store: store1,
-        shadow: true,
-        theme: 'Category1',
-        legend: {
-            position: 'right'
-        },
-        axes: [ ...some axes options... ],
-        series: [ ...some series options... ]
-    });
-  </code></pre>
- *
- * In this example we set the `width` and `height` of the chart, we decide whether our series are
- * animated or not and we select a store to be bound to the chart. We also turn on shadows for all series,
- * select a color theme `Category1` for coloring the series, set the legend to the right part of the chart and
- * then tell the chart to render itself in the body element of the document. For more information about the axes and
- * series configurations please check the documentation of each series (Line, Bar, Pie, etc).
+ * Charts provide a flexible way to achieve a wide range of data visualization capablitities.
+ * Each Chart gets its data directly from a {@link Ext.data.Store Store}, and automatically
+ * updates its display whenever data in the Store changes. In addition, the look and feel
+ * of a Chart can be customized using {@link Ext.chart.theme.Theme Theme}s.
+ * 
+ * ## Creating a Simple Chart
+ * 
+ * Every Chart has three key parts - a {@link Ext.data.Store Store} that contains the data,
+ * an array of {@link Ext.chart.axis.Axis Axes} which define the boundaries of the Chart,
+ * and one or more {@link Ext.chart.series.Series Series} to handle the visual rendering of the data points.
+ * 
+ * ### 1. Creating a Store
+ * 
+ * The first step is to create a {@link Ext.data.Model Model} that represents the type of
+ * data that will be displayed in the Chart. For example the data for a chart that displays
+ * a weather forecast could be represented as a series of "WeatherPoint" data points with
+ * two fields - "temperature", and "date":
+ * 
+ *     Ext.define('WeatherPoint', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['temperature', 'date']
+ *     });
+ * 
+ * Next a {@link Ext.data.Store Store} must be created.  The store contains a collection of "WeatherPoint" Model instances.
+ * The data could be loaded dynamically, but for sake of ease this example uses inline data:
+ * 
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: 'WeatherPoint',
+ *         data: [
+ *             { temperature: 58, date: new Date(2011, 1, 1, 8) },
+ *             { temperature: 63, date: new Date(2011, 1, 1, 9) },
+ *             { temperature: 73, date: new Date(2011, 1, 1, 10) },
+ *             { temperature: 78, date: new Date(2011, 1, 1, 11) },
+ *             { temperature: 81, date: new Date(2011, 1, 1, 12) }
+ *         ]
+ *     });
+ *    
+ * For additional information on Models and Stores please refer to the [Data Guide](#/guide/data).
+ * 
+ * ### 2. Creating the Chart object
+ * 
+ * Now that a Store has been created it can be used in a Chart:
+ * 
+ *     Ext.create('Ext.chart.Chart', {
+ *        renderTo: Ext.getBody(),
+ *        width: 400,
+ *        height: 300,
+ *        store: store
+ *     });
+ *    
+ * That's all it takes to create a Chart instance that is backed by a Store.
+ * However, if the above code is run in a browser, a blank screen will be displayed.
+ * This is because the two pieces that are responsible for the visual display,
+ * the Chart's {@link #cfg-axes axes} and {@link #cfg-series series}, have not yet been defined.
+ * 
+ * ### 3. Configuring the Axes
+ * 
+ * {@link Ext.chart.axis.Axis Axes} are the lines that define the boundaries of the data points that a Chart can display.
+ * This example uses one of the most common Axes configurations - a horizontal "x" axis, and a vertical "y" axis:
+ * 
+ *     Ext.create('Ext.chart.Chart', {
+ *         ...
+ *         axes: [
+ *             {
+ *                 title: 'Temperature',
+ *                 type: 'Numeric',
+ *                 position: 'left',
+ *                 fields: ['temperature'],
+ *                 minimum: 0,
+ *                 maximum: 100
+ *             },
+ *             {
+ *                 title: 'Time',
+ *                 type: 'Time',
+ *                 position: 'bottom',
+ *                 fields: ['date'],
+ *                 dateFormat: 'ga'
+ *             }
+ *         ]
+ *     });
+ *    
+ * The "Temperature" axis is a vertical {@link Ext.chart.axis.Numeric Numeric Axis} and is positioned on the left edge of the Chart.
+ * It represents the bounds of the data contained in the "WeatherPoint" Model's "temperature" field that was
+ * defined above. The minimum value for this axis is "0", and the maximum is "100".
+ * 
+ * The horizontal axis is a {@link Ext.chart.axis.Time Time Axis} and is positioned on the bottom edge of the Chart.
+ * It represents the bounds of the data contained in the "WeatherPoint" Model's "date" field.
+ * The {@link Ext.chart.axis.Time#cfg-dateFormat dateFormat}
+ * configuration tells the Time Axis how to format it's labels.
+ * 
+ * Here's what the Chart looks like now that it has its Axes configured:
+ * 
+ * {@img Ext.chart.Chart/Ext.chart.Chart1.png Chart Axes}
+ * 
+ * ### 4. Configuring the Series
+ * 
+ * The final step in creating a simple Chart is to configure one or more {@link Ext.chart.series.Series Series}.
+ * Series are responsible for the visual representation of the data points contained in the Store.
+ * This example only has one Series:
+ * 
+ *     Ext.create('Ext.chart.Chart', {
+ *         ...
+ *         axes: [
+ *             ...
+ *         ],
+ *         series: [
+ *             {
+ *                 type: 'line',
+ *                 xField: 'date',
+ *                 yField: 'temperature'
+ *             }
+ *         ]
+ *     });
+ *     
+ * This Series is a {@link Ext.chart.series.Line Line Series}, and it uses the "date" and "temperature" fields
+ * from the "WeatherPoint" Models in the Store to plot its data points:
+ * 
+ * {@img Ext.chart.Chart/Ext.chart.Chart2.png Line Series}
+ * 
+ * See the [Simple Chart Example](doc-resources/Ext.chart.Chart/examples/simple_chart/index.html) for a live demo.
+ * 
+ * ## Themes
+ * 
+ * The color scheme for a Chart can be easily changed using the {@link #cfg-theme theme} configuration option:
+ * 
+ *     Ext.create('Ext.chart.Chart', {
+ *         ...
+ *         theme: 'Green',
+ *         ...
+ *     });
+ * 
+ * {@img Ext.chart.Chart/Ext.chart.Chart3.png Green Theme}
+ * 
+ * For more information on Charts please refer to the [Drawing and Charting Guide](#/guide/drawing_and_charting).
+ * 
  */
 Ext.define('Ext.chart.Chart', {
 
@@ -40316,134 +41780,166 @@ Ext.define('Ext.chart.Chart', {
     viewBox: false,
 
     /**
-     * @cfg {String} theme (optional) The name of the theme to be used. A theme defines the colors and
-     * other visual displays of tick marks on axis, text, title text, line colors, marker colors and styles, etc.
-     * Possible theme values are 'Base', 'Green', 'Sky', 'Red', 'Purple', 'Blue', 'Yellow' and also six category themes
-     * 'Category1' to 'Category6'. Default value is 'Base'.
+     * @cfg {String} theme
+     * The name of the theme to be used. A theme defines the colors and other visual displays of tick marks
+     * on axis, text, title text, line colors, marker colors and styles, etc. Possible theme values are 'Base', 'Green',
+     * 'Sky', 'Red', 'Purple', 'Blue', 'Yellow' and also six category themes 'Category1' to 'Category6'. Default value
+     * is 'Base'.
      */
 
     /**
-     * @cfg {Boolean/Object} animate (optional) true for the default animation (easing: 'ease' and duration: 500)
-     * or a standard animation config object to be used for default chart animations. Defaults to false.
+     * @cfg {Boolean/Object} animate
+     * True for the default animation (easing: 'ease' and duration: 500) or a standard animation config
+     * object to be used for default chart animations. Defaults to false.
      */
     animate: false,
 
     /**
-     * @cfg {Boolean/Object} legend (optional) true for the default legend display or a legend config object. Defaults to false.
+     * @cfg {Boolean/Object} legend
+     * True for the default legend display or a legend config object. Defaults to false.
      */
     legend: false,
 
     /**
-     * @cfg {integer} insetPadding (optional) Set the amount of inset padding in pixels for the chart. Defaults to 10.
+     * @cfg {Number} insetPadding
+     * The amount of inset padding in pixels for the chart. Defaults to 10.
      */
     insetPadding: 10,
 
     /**
-     * @cfg {Array} enginePriority
-     * Defines the priority order for which Surface implementation to use. The first
-     * one supported by the current environment will be used.
+     * @cfg {String[]} enginePriority
+     * Defines the priority order for which Surface implementation to use. The first one supported by the current
+     * environment will be used. Defaults to `['Svg', 'Vml']`.
      */
     enginePriority: ['Svg', 'Vml'],
 
     /**
-     * @cfg {Object|Boolean} background (optional) Set the chart background. This can be a gradient object, image, or color.
-     * Defaults to false for no background.
+     * @cfg {Object/Boolean} background
+     * The chart background. This can be a gradient object, image, or color. Defaults to false for no
+     * background. For example, if `background` were to be a color we could set the object as
      *
-     * For example, if `background` were to be a color we could set the object as
+     *     background: {
+     *         //color string
+     *         fill: '#ccc'
+     *     }
      *
-     <pre><code>
-        background: {
-            //color string
-            fill: '#ccc'
-        }
-     </code></pre>
-
-     You can specify an image by using:
-
-     <pre><code>
-        background: {
-            image: 'http://path.to.image/'
-        }
-     </code></pre>
-
-     Also you can specify a gradient by using the gradient object syntax:
-
-     <pre><code>
-        background: {
-            gradient: {
-                id: 'gradientId',
-                angle: 45,
-                stops: {
-                    0: {
-                        color: '#555'
-                    }
-                    100: {
-                        color: '#ddd'
-                    }
-                }
-            }
-        }
-     </code></pre>
+     * You can specify an image by using:
+     *
+     *     background: {
+     *         image: 'http://path.to.image/'
+     *     }
+     *
+     * Also you can specify a gradient by using the gradient object syntax:
+     *
+     *     background: {
+     *         gradient: {
+     *             id: 'gradientId',
+     *             angle: 45,
+     *             stops: {
+     *                 0: {
+     *                     color: '#555'
+     *                 }
+     *                 100: {
+     *                     color: '#ddd'
+     *                 }
+     *             }
+     *         }
+     *     }
      */
     background: false,
 
     /**
-     * @cfg {Array} gradients (optional) Define a set of gradients that can be used as `fill` property in sprites.
-     * The gradients array is an array of objects with the following properties:
+     * @cfg {Object[]} gradients
+     * Define a set of gradients that can be used as `fill` property in sprites. The gradients array is an
+     * array of objects with the following properties:
      *
-     * <ul>
-     * <li><strong>id</strong> - string - The unique name of the gradient.</li>
-     * <li><strong>angle</strong> - number, optional - The angle of the gradient in degrees.</li>
-     * <li><strong>stops</strong> - object - An object with numbers as keys (from 0 to 100) and style objects
-     * as values</li>
-     * </ul>
+     * - **id** - string - The unique name of the gradient.
+     * - **angle** - number, optional - The angle of the gradient in degrees.
+     * - **stops** - object - An object with numbers as keys (from 0 to 100) and style objects as values
      *
+     * For example:
+     *
+     *     gradients: [{
+     *         id: 'gradientId',
+     *         angle: 45,
+     *         stops: {
+     *             0: {
+     *                 color: '#555'
+     *             },
+     *             100: {
+     *                 color: '#ddd'
+     *             }
+     *         }
+     *     }, {
+     *         id: 'gradientId2',
+     *         angle: 0,
+     *         stops: {
+     *             0: {
+     *                 color: '#590'
+     *             },
+     *             20: {
+     *                 color: '#599'
+     *             },
+     *             100: {
+     *                 color: '#ddd'
+     *             }
+     *         }
+     *     }]
+     *
+     * Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:
+     *
+     *     sprite.setAttributes({
+     *         fill: 'url(#gradientId)'
+     *     }, true);
+     */
 
-     For example:
-
-     <pre><code>
-        gradients: [{
-            id: 'gradientId',
-            angle: 45,
-            stops: {
-                0: {
-                    color: '#555'
-                },
-                100: {
-                    color: '#ddd'
-                }
-            }
-        },  {
-            id: 'gradientId2',
-            angle: 0,
-            stops: {
-                0: {
-                    color: '#590'
-                },
-                20: {
-                    color: '#599'
-                },
-                100: {
-                    color: '#ddd'
-                }
-            }
-        }]
-     </code></pre>
-
-     Then the sprites can use `gradientId` and `gradientId2` by setting the fill attributes to those ids, for example:
-
-     <pre><code>
-        sprite.setAttributes({
-            fill: 'url(#gradientId)'
-        }, true);
-     </code></pre>
+    /**
+     * @cfg {Ext.data.Store} store
+     * The store that supplies data to this chart.
+     */
 
+    /**
+     * @cfg {Ext.chart.series.Series[]} series
+     * Array of {@link Ext.chart.series.Series Series} instances or config objects.  For example:
+     * 
+     *     series: [{
+     *         type: 'column',
+     *         axis: 'left',
+     *         listeners: {
+     *             'afterrender': function() {
+     *                 console('afterrender');
+     *             }
+     *         },
+     *         xField: 'category',
+     *         yField: 'data1'
+     *     }]
      */
 
+    /**
+     * @cfg {Ext.chart.axis.Axis[]} axes
+     * Array of {@link Ext.chart.axis.Axis Axis} instances or config objects.  For example:
+     * 
+     *     axes: [{
+     *         type: 'Numeric',
+     *         position: 'left',
+     *         fields: ['data1'],
+     *         title: 'Number of Hits',
+     *         minimum: 0,
+     *         //one minor tick between two major ticks
+     *         minorTickSteps: 1
+     *     }, {
+     *         type: 'Category',
+     *         position: 'bottom',
+     *         fields: ['name'],
+     *         title: 'Month of the Year'
+     *     }]
+     */
 
     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 });
@@ -40467,6 +41963,10 @@ Ext.define('Ext.chart.Chart', {
         me.mixins.navigation.constructor.call(me, config);
         me.callParent([config]);
     },
+    
+    getChartStore: function(){
+        return this.substore || this.store;    
+    },
 
     initComponent: function() {
         var me = this,
@@ -40484,17 +41984,17 @@ Ext.define('Ext.chart.Chart', {
             'itemdrag',
             'itemdragend',
             /**
-                 * @event beforerefresh
-                 * Fires before a refresh to the chart data is called.  If the beforerefresh handler returns
-                 * <tt>false</tt> the {@link #refresh} action will be cancelled.
-                 * @param {Chart} this
-                 */
+             * @event beforerefresh
+             * Fires before a refresh to the chart data is called. If the beforerefresh handler returns false the
+             * {@link #refresh} action will be cancelled.
+             * @param {Ext.chart.Chart} this
+             */
             'beforerefresh',
             /**
-                 * @event refresh
-                 * Fires after the chart data has been refreshed.
-                 * @param {Chart} this
-                 */
+             * @event refresh
+             * Fires after the chart data has been refreshed.
+             * @param {Ext.chart.Chart} this
+             */
             'refresh'
         );
         Ext.applyIf(me, {
@@ -40542,8 +42042,8 @@ Ext.define('Ext.chart.Chart', {
     },
 
     /**
-     * Redraw the chart. If animations are set this will animate the chart too.
-     * @cfg {boolean} resize Optional flag which changes the default origin points of the chart for animations.
+     * Redraws the chart. If animations are set this will animate the chart too. 
+     * @param {Boolean} resize (optional) flag which changes the default origin points of the chart for animations.
      */
     redraw: function(resize) {
         var me = this,
@@ -40755,7 +42255,7 @@ Ext.define('Ext.chart.Chart', {
     // @private
     refresh: function() {
         var me = this;
-        if (me.rendered && me.curWidth != undefined && me.curHeight != undefined) {
+        if (me.rendered && me.curWidth !== undefined && me.curHeight !== undefined) {
             if (me.fireEvent('beforerefresh', me) !== false) {
                 me.redraw();
                 me.fireEvent('refresh', me);
@@ -40765,13 +42265,13 @@ Ext.define('Ext.chart.Chart', {
 
     /**
      * Changes the data store bound to this chart and refreshes it.
-     * @param {Store} store The store to bind to this chart
+     * @param {Ext.data.Store} store The store to bind to this chart
      */
     bindStore: function(store, initial) {
         var me = this;
         if (!initial && me.store) {
             if (store !== me.store && me.store.autoDestroy) {
-                me.store.destroy();
+                me.store.destroyStore();
             }
             else {
                 me.store.un('datachanged', me.refresh, me);
@@ -41005,7 +42505,7 @@ Ext.define('Ext.chart.Chart', {
 
     // @private remove gently.
     destroy: function() {
-        this.surface.destroy();
+        Ext.destroy(this.surface);
         this.bindStore(null);
         this.callParent(arguments);
     }
@@ -41025,7 +42525,7 @@ Ext.define('Ext.chart.Highlight', {
 
     /**
      * Highlight the given series item.
-     * @param {Boolean|Object} Default's false. Can also be an object width style properties (i.e fill, stroke, radius) 
+     * @param {Boolean/Object} Default's false. Can also be an object width style properties (i.e fill, stroke, radius) 
      * or just use default styles per series by setting highlight = true.
      */
     highlight: false,
@@ -41191,11 +42691,11 @@ Ext.define('Ext.chart.Highlight', {
 /**
  * @class Ext.chart.Label
  *
- * Labels is a mixin whose methods are appended onto the Series class. Labels is an interface with methods implemented
- * in each of the Series (Pie, Bar, etc) for label creation and label placement.
+ * Labels is a mixin to the Series class. Labels methods are implemented
+ * in each of the Series (Pie, Bar, etc) for label creation and placement.
  *
  * The methods implemented by the Series are:
- *  
+ *
  * - **`onCreateLabel(storeItem, item, i, display)`** Called each time a new label is created.
  *   The arguments of the method are:
  *   - *`storeItem`* The element of the store that is related to the label sprite.
@@ -41219,57 +42719,59 @@ Ext.define('Ext.chart.Label', {
     /* Begin Definitions */
 
     requires: ['Ext.draw.Color'],
-    
-    /* End Definitions */
-
-    /**
-     * @cfg {String} display
-     * Specifies the presence and position of labels for each pie slice. Either "rotate", "middle", "insideStart",
-     * "insideEnd", "outside", "over", "under", or "none" to prevent label rendering.
-     * Default value: 'none'.
-     */
-
-    /**
-     * @cfg {String} color
-     * The color of the label text.
-     * Default value: '#000' (black).
-     */
-
-    /**
-     * @cfg {String} field
-     * The name of the field to be displayed in the label.
-     * Default value: 'name'.
-     */
-
-    /**
-     * @cfg {Number} minMargin
-     * Specifies the minimum distance from a label to the origin of the visualization.
-     * This parameter is useful when using PieSeries width variable pie slice lengths.
-     * Default value: 50.
-     */
 
-    /**
-     * @cfg {String} font
-     * The font used for the labels.
-     * Defautl value: "11px Helvetica, sans-serif".
-     */
-
-    /**
-     * @cfg {String} orientation
-     * Either "horizontal" or "vertical".
-     * Dafault value: "horizontal".
-     */
+    /* End Definitions */
 
     /**
-     * @cfg {Function} renderer
-     * Optional function for formatting the label into a displayable value.
-     * Default value: function(v) { return v; }
-     * @param v
+     * @cfg {Object} label
+     * Object with the following properties:
+     *
+     * - **display** : String
+     *
+     *   Specifies the presence and position of labels for each pie slice. Either "rotate", "middle", "insideStart",
+     *   "insideEnd", "outside", "over", "under", or "none" to prevent label rendering.
+     *   Default value: 'none'.
+     *
+     * - **color** : String
+     *
+     *   The color of the label text.
+     *   Default value: '#000' (black).
+     *
+     * - **contrast** : Boolean
+     *
+     *   True to render the label in contrasting color with the backround.
+     *   Default value: false.
+     *
+     * - **field** : String
+     *
+     *   The name of the field to be displayed in the label.
+     *   Default value: 'name'.
+     *
+     * - **minMargin** : Number
+     *
+     *   Specifies the minimum distance from a label to the origin of the visualization.
+     *   This parameter is useful when using PieSeries width variable pie slice lengths.
+     *   Default value: 50.
+     *
+     * - **font** : String
+     *
+     *   The font used for the labels.
+     *   Default value: "11px Helvetica, sans-serif".
+     *
+     * - **orientation** : String
+     *
+     *   Either "horizontal" or "vertical".
+     *   Dafault value: "horizontal".
+     *
+     * - **renderer** : Function
+     *
+     *   Optional function for formatting the label into a displayable value.
+     *   Default value: function(v) { return v; }
      */
 
     //@private a regex to parse url type colors.
     colorStringRe: /url\s*\(\s*#([^\/)]+)\s*\)/,
-    
+
     //@private the mixin constructor. Used internally by Series.
     constructor: function(config) {
         var me = this;
@@ -41303,103 +42805,111 @@ Ext.define('Ext.chart.Label', {
             color = config.color,
             field = [].concat(config.field),
             group = me.labelsGroup,
+            groupLength = (group || 0) && group.length,
             store = me.chart.store,
             len = store.getCount(),
             itemLength = (items || 0) && items.length,
             ratio = itemLength / len,
             gradientsCount = (gradients || 0) && gradients.length,
             Color = Ext.draw.Color,
-            gradient, i, count, index, j, k, colorStopTotal, colorStopIndex, colorStop, item, label,
+            hides = [],
+            gradient, i, count, groupIndex, index, j, k, colorStopTotal, colorStopIndex, colorStop, item, label,
             storeItem, sprite, spriteColor, spriteBrightness, labelColor, colorString;
 
         if (display == 'none') {
             return;
         }
+        // no items displayed, hide all labels
+        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);
+                    //check the excludes
+                    while(this.__excludes && this.__excludes[index] && ratio > 1) {
+                        if(field[j]){
+                            hides.push(groupIndex);
+                        }
+                        index++;
 
-        for (i = 0, count = 0; i < len; i++) {
-            index = 0;
-            for (j = 0; j < ratio; j++) {
-                item = items[count];
-                label = group.getAt(count);
-                storeItem = store.getAt(i);
-                
-                //check the excludes
-                while(this.__excludes && this.__excludes[index]) {
-                    index++;
-                }
-
-                if (!item && label) {
-                    label.hide(true);
-                }
+                    }
 
-                if (item && field[j]) {
-                    if (!label) {
-                        label = me.onCreateLabel(storeItem, item, i, display, j, index);
+                    if (!item && label) {
+                        label.hide(true);
+                        groupIndex++;
                     }
-                    me.onPlaceLabel(label, storeItem, item, i, display, animate, j, index);
-
-                    //set contrast
-                    if (config.contrast && item.sprite) {
-                        sprite = item.sprite;
-                        //set the color string to the color to be set.
-                        if (sprite._endStyle) {
-                            colorString = sprite._endStyle.fill;
-                        }
-                        else if (sprite._to) {
-                            colorString = sprite._to.fill;
-                        }
-                        else {
-                            colorString = sprite.attr.fill;
+
+                    if (item && field[j]) {
+                        if (!label) {
+                            label = me.onCreateLabel(storeItem, item, i, display, j, index);
                         }
-                        colorString = colorString || sprite.attr.fill;
-                        
-                        spriteColor = Color.fromString(colorString);
-                        //color wasn't parsed property maybe because it's a gradient id
-                        if (colorString && !spriteColor) {
-                            colorString = colorString.match(me.colorStringRe)[1];
-                            for (k = 0; k < gradientsCount; k++) {
-                                gradient = gradients[k];
-                                if (gradient.id == colorString) {
-                                    //avg color stops
-                                    colorStop = 0; colorStopTotal = 0;
-                                    for (colorStopIndex in gradient.stops) {
-                                        colorStop++;
-                                        colorStopTotal += Color.fromString(gradient.stops[colorStopIndex].color).getGrayscale();
+                        me.onPlaceLabel(label, storeItem, item, i, display, animate, j, index);
+                        groupIndex++;
+
+                        //set contrast
+                        if (config.contrast && item.sprite) {
+                            sprite = item.sprite;
+                            //set the color string to the color to be set.
+                            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);
+                            //color wasn't parsed property maybe because it's a gradient id
+                            if (colorString && !spriteColor) {
+                                colorString = colorString.match(me.colorStringRe)[1];
+                                for (k = 0; k < gradientsCount; k++) {
+                                    gradient = gradients[k];
+                                    if (gradient.id == colorString) {
+                                        //avg color stops
+                                        colorStop = 0; colorStopTotal = 0;
+                                        for (colorStopIndex in gradient.stops) {
+                                            colorStop++;
+                                            colorStopTotal += Color.fromString(gradient.stops[colorStopIndex].color).getGrayscale();
+                                        }
+                                        spriteBrightness = (colorStopTotal / colorStop) / 255;
+                                        break;
                                     }
-                                    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);
                         }
-                        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++;
                 }
-                count++;
-                index++;
             }
         }
-        me.hideLabels(count);
+        me.hideLabels(hides);
     },
-
-    //@private a method to hide labels.
-    hideLabels: function(index) {
-        var labelsGroup = this.labelsGroup, len;
-        if (labelsGroup) {
-            len = labelsGroup.getCount();
-            while (len-->index) {
-                labelsGroup.getAt(len).hide(true);
-            }
-        }
+    hideLabels: function(hides){
+        var labelsGroup = this.labelsGroup,
+            hlen = hides.length;
+        while(hlen--)
+            labelsGroup.getAt(hides[hlen]).hide(true);
     }
 });
 Ext.define('Ext.chart.MaskLayer', {
@@ -41515,7 +43025,10 @@ Ext.define('Ext.chart.Tip', {
                 constrainPosition: false
             });
             me.tooltip = Ext.create('Ext.tip.ToolTip', me.tipConfig);
-            Ext.getBody().on('mousemove', me.tooltip.onMouseMove, me.tooltip);
+            me.chart.surface.on('mousemove', me.tooltip.onMouseMove, me.tooltip);
+            me.chart.surface.on('mouseleave', function() {
+                me.hideTip();
+            });
             if (me.tipConfig.surface) {
                 //initialize a surface
                 surface = me.tipConfig.surface;
@@ -41579,6 +43092,7 @@ Ext.define('Ext.chart.Tip', {
 /**
  * @class Ext.chart.axis.Abstract
  * Base class for all axis classes.
+ * @private
  */
 Ext.define('Ext.chart.axis.Abstract', {
 
@@ -41638,13 +43152,13 @@ Ext.define('Ext.chart.axis.Abstract', {
 /**
  * @class Ext.chart.axis.Axis
  * @extends Ext.chart.axis.Abstract
- * 
+ *
  * Defines axis for charts. The axis position, type, style can be configured.
- * The axes are defined in an axes array of configuration objects where the type, 
- * field, grid and other configuration options can be set. To know more about how 
+ * The axes are defined in an axes array of configuration objects where the type,
+ * field, grid and other configuration options can be set. To know more about how
  * to create a Chart please check the Chart class documentation. Here's an example for the axes part:
  * An example of axis for a series (in this case for an area chart that has multiple layers of yFields) could be:
- * 
+ *
  *     axes: [{
  *         type: 'Numeric',
  *         grid: true,
@@ -41672,10 +43186,10 @@ Ext.define('Ext.chart.axis.Abstract', {
  *             }
  *         }
  *     }]
- * 
+ *
  * In this case we use a `Numeric` axis for displaying the values of the Area series and a `Category` axis for displaying the names of
- * the store elements. The numeric axis is placed on the left of the screen, while the category axis is placed at the bottom of the chart. 
- * Both the category and numeric axes have `grid` set, which means that horizontal and vertical lines will cover the chart background. In the 
+ * the store elements. The numeric axis is placed on the left of the screen, while the category axis is placed at the bottom of the chart.
+ * Both the category and numeric axes have `grid` set, which means that horizontal and vertical lines will cover the chart background. In the
  * category axis the labels will be rotated so they can fit the space better.
  */
 Ext.define('Ext.chart.axis.Axis', {
@@ -41691,7 +43205,7 @@ Ext.define('Ext.chart.axis.Axis', {
     /* End Definitions */
 
     /**
-     * @cfg {Boolean | Object} grid 
+     * @cfg {Boolean/Object} grid
      * The grid configuration enables you to set a background grid for an axis.
      * If set to *true* on a vertical axis, vertical lines will be drawn.
      * If set to *true* on a horizontal axis, horizontal lines will be drawn.
@@ -41728,76 +43242,82 @@ Ext.define('Ext.chart.axis.Axis', {
      *         title: 'Month of the Year',
      *         grid: true
      *     }]
-     * 
+     *
      */
 
     /**
-     * @cfg {Number} majorTickSteps 
+     * @cfg {Number} majorTickSteps
      * If `minimum` and `maximum` are specified it forces the number of major ticks to the specified value.
      */
 
     /**
-     * @cfg {Number} minorTickSteps 
+     * @cfg {Number} minorTickSteps
      * The number of small ticks between two major ticks. Default is zero.
      */
-    
+
+    /**
+     * @cfg {String} title
+     * The title for the Axis
+     */
+
     //@private force min/max values from store
     forceMinMax: false,
-    
+
     /**
-     * @cfg {Number} dashSize 
+     * @cfg {Number} dashSize
      * The size of the dash marker. Default's 3.
      */
     dashSize: 3,
-    
+
     /**
      * @cfg {String} position
      * Where to set the axis. Available options are `left`, `bottom`, `right`, `top`. Default's `bottom`.
      */
     position: 'bottom',
-    
+
     // @private
     skipFirst: false,
-    
+
     /**
      * @cfg {Number} length
      * Offset axis position. Default's 0.
      */
     length: 0,
-    
+
     /**
      * @cfg {Number} width
      * Offset axis width. Default's 0.
      */
     width: 0,
-    
+
     majorTickSteps: false,
 
     // @private
     applyData: Ext.emptyFn,
 
-    // @private creates a structure with start, end and step points.
-    calcEnds: function() {
+    getRange: function () {
         var me = this,
+            store = me.chart.getChartStore(),
+            fields = me.fields,
+            ln = fields.length,
             math = Math,
             mmax = math.max,
             mmin = math.min,
-            store = me.chart.substore || me.chart.store,
-            series = me.chart.series.items,
-            fields = me.fields,
-            ln = fields.length,
+            aggregate = false,
             min = isNaN(me.minimum) ? Infinity : me.minimum,
             max = isNaN(me.maximum) ? -Infinity : me.maximum,
-            prevMin = me.prevMin,
-            prevMax = me.prevMax,
-            aggregate = false,
-            total = 0,
+            total = 0, i, l, value, values, rec,
             excludes = [],
-            outfrom, outto,
-            i, l, values, rec, out;
+            series = me.chart.series.items;
 
         //if one series is stacked I have to aggregate the values
         //for the scale.
+        // TODO(zhangbei): the code below does not support series that stack on 1 side but non-stacked axis
+        // listed in axis config. For example, a Area series whose axis : ['left', 'bottom'].
+        // Assuming only stack on y-axis.
+        // CHANGED BY Nicolas: I removed the check `me.position == 'left'` and `me.position == 'right'` since 
+        // it was constraining the minmax calculation to y-axis stacked
+        // visualizations.
         for (i = 0, l = series.length; !aggregate && i < l; i++) {
             aggregate = aggregate || series[i].stacked;
             excludes = series[i].__excludes || excludes;
@@ -41814,8 +43334,8 @@ Ext.define('Ext.chart.axis.Axis', {
                     rec = record.get(fields[i]);
                     values[+(rec > 0)] += math.abs(rec);
                 }
-                max = mmax(max, -values[0], values[1]);
-                min = mmin(min, -values[0], values[1]);
+                max = mmax(max, -values[0], +values[1]);
+                min = mmin(min, -values[0], +values[1]);
             }
             else {
                 for (i = 0; i < ln; i++) {
@@ -41823,8 +43343,8 @@ Ext.define('Ext.chart.axis.Axis', {
                         continue;
                     }
                     value = record.get(fields[i]);
-                    max = mmax(max, value);
-                    min = mmin(min, value);
+                    max = mmax(max, +value);
+                    min = mmin(min, +value);
                 }
             }
         });
@@ -41835,9 +43355,30 @@ Ext.define('Ext.chart.axis.Axis', {
             min = me.prevMin || 0;
         }
         //normalize min max for snapEnds.
-        if (min != max && (max != (max >> 0))) {
-            max = (max >> 0) + 1;
+        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;
+        }
+
+        return {min: min, max: max};
+    },
+
+    // @private creates a structure with start, end and step points.
+    calcEnds: function() {
+        var me = this,
+            fields = me.fields,
+            range = me.getRange(),
+            min = range.min,
+            max = range.max,
+            outfrom, outto, out;
+
         out = Ext.draw.Draw.snapEnds(min, max, me.majorTickSteps !== false ?  (me.majorTickSteps +1) : me.steps);
         outfrom = out.from;
         outto = out.to;
@@ -41859,10 +43400,10 @@ Ext.define('Ext.chart.axis.Axis', {
             //Clipping should be added to remove lines in the chart which are below the axis.
             out.from = me.minimum;
         }
-        
+
         //Adjust after adjusting minimum and maximum
         out.step = (out.to - out.from) / (outto - outfrom) * out.step;
-        
+
         if (me.adjustMaximumByMajorUnit) {
             out.to += out.step;
         }
@@ -41875,7 +43416,7 @@ Ext.define('Ext.chart.axis.Axis', {
     },
 
     /**
-     * Renders the axis into the screen and updates it's position.
+     * Renders the axis into the screen and updates its position.
      */
     drawAxis: function (init) {
         var me = this,
@@ -41904,7 +43445,7 @@ Ext.define('Ext.chart.axis.Axis', {
             dashesX,
             dashesY,
             delta;
-        
+
         //If no steps are specified
         //then don't draw the axis. This generally happens
         //when an empty store.
@@ -41924,11 +43465,11 @@ Ext.define('Ext.chart.axis.Axis', {
             path = ["M", x, currentY, "l", length, 0];
             trueLength = length - (gutterX * 2);
         }
-        
+
         delta = trueLength / (steps || 1);
         dashesX = Math.max(subDashesX +1, 0);
         dashesY = Math.max(subDashesY +1, 0);
-        if (me.type == 'Numeric') {
+        if (me.type == 'Numeric' || me.type == 'Time') {
             calcLabels = true;
             me.labels = [stepCalcs.from];
         }
@@ -42013,7 +43554,7 @@ Ext.define('Ext.chart.axis.Axis', {
      */
     drawGrid: function() {
         var me = this,
-            surface = me.chart.surface, 
+            surface = me.chart.surface,
             grid = me.grid,
             odd = grid.odd,
             even = grid.even,
@@ -42027,7 +43568,7 @@ Ext.define('Ext.chart.axis.Axis', {
             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;
@@ -42042,25 +43583,25 @@ Ext.define('Ext.chart.axis.Axis', {
                 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, 
+                    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, 
+                    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, 
+                    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, 
+                    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");
@@ -42099,7 +43640,7 @@ Ext.define('Ext.chart.axis.Axis', {
                         type: 'path',
                         path: evenPath
                     });
-                } 
+                }
                 me.gridEven.setAttributes(Ext.apply({
                     path: evenPath,
                     hidden: false
@@ -42156,8 +43697,8 @@ Ext.define('Ext.chart.axis.Axis', {
         if (me.label.rotation) {
             textLabel.setAttributes({
                 rotation: {
-                    degrees: 0    
-                }    
+                    degrees: 0
+                }
             }, true);
             textLabel._ubbox = textLabel.getBBox();
             textLabel.setAttributes(me.label, true);
@@ -42166,7 +43707,7 @@ Ext.define('Ext.chart.axis.Axis', {
         }
         return textLabel;
     },
-    
+
     rect2pointArray: function(sprite) {
         var surface = this.chart.surface,
             rect = surface.getBBox(sprite, true),
@@ -42182,24 +43723,24 @@ Ext.define('Ext.chart.axis.Axis', {
         //transform the points
         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,
@@ -42223,8 +43764,8 @@ Ext.define('Ext.chart.axis.Axis', {
         //get a reference to the first text label dimensions
         point = inflections[0];
         firstLabel = me.getOrCreateLabel(0, me.label.renderer(labels[0]));
-        ratio = Math.abs(Math.sin(labelConf.rotate && (labelConf.rotate.degrees * Math.PI / 180) || 0)) >> 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]);
@@ -42246,7 +43787,7 @@ Ext.define('Ext.chart.axis.Axis', {
             else {
                 y = point[1] + (me.dashSize * 2) + me.label.padding + (bbox.height / 2);
             }
-            
+
             textLabel.setAttributes({
                 hidden: false,
                 x: x,
@@ -42259,13 +43800,13 @@ Ext.define('Ext.chart.axis.Axis', {
                 textLabel.hide(true);
                 continue;
             }
-            
+
             prevLabel = textLabel;
         }
 
         return maxHeight;
     },
-    
+
     drawVerticalLabels: function() {
         var me = this,
             inflections = me.inflections,
@@ -42289,7 +43830,7 @@ Ext.define('Ext.chart.axis.Axis', {
             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 (gutterY < bbox.height / 2) {
@@ -42305,7 +43846,7 @@ Ext.define('Ext.chart.axis.Axis', {
             }
             else {
                 x = point[0] + me.dashSize + me.label.padding + 2;
-            }    
+            }
             textLabel.setAttributes(Ext.apply({
                 hidden: false,
                 x: x,
@@ -42318,7 +43859,7 @@ Ext.define('Ext.chart.axis.Axis', {
             }
             prevLabel = textLabel;
         }
-        
+
         return maxWidth;
     },
 
@@ -42335,7 +43876,7 @@ Ext.define('Ext.chart.axis.Axis', {
             ln, i;
 
         if (position == 'left' || position == 'right') {
-            maxWidth = me.drawVerticalLabels();    
+            maxWidth = me.drawVerticalLabels();
         } else {
             maxHeight = me.drawHorizontalLabels();
         }
@@ -42447,19 +43988,19 @@ Ext.define('Ext.chart.axis.Axis', {
         }, true);
     }
 });
+
 /**
  * @class Ext.chart.axis.Category
  * @extends Ext.chart.axis.Axis
  *
  * A type of axis that displays items in categories. This axis is generally used to
  * display categorical information like names of items, month names, quarters, etc.
- * but no quantitative values. For that other type of information <em>Number</em>
+ * but no quantitative values. For that other type of information `Number`
  * axis are more suitable.
  *
  * As with other axis you can set the position of the axis and its title. For example:
  *
- * {@img Ext.chart.axis.Category/Ext.chart.axis.Category.png Ext.chart.axis.Category chart axis}
- *
+ *     @example
  *     var store = Ext.create('Ext.data.JsonStore', {
  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
  *         data: [
@@ -42467,10 +44008,10 @@ Ext.define('Ext.chart.axis.Axis', {
  *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
  *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
  *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
+ *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
  *         ]
  *     });
- *  
+ *
  *     Ext.create('Ext.chart.Chart', {
  *         renderTo: Ext.getBody(),
  *         width: 500,
@@ -42517,4479 +44058,5375 @@ Ext.define('Ext.chart.axis.Axis', {
  *     });
  *
  * In this example with set the category axis to the bottom of the surface, bound the axis to
- * the <em>name</em> property and set as title <em>Month of the Year</em>.
+ * the `name` property and set as title _Month of the Year_.
+ */
+Ext.define('Ext.chart.axis.Category', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.chart.axis.Axis',
+
+    alternateClassName: 'Ext.chart.CategoryAxis',
+
+    alias: 'axis.category',
+
+    /* End Definitions */
+
+    /**
+     * A list of category names to display along this axis.
+     * @property {String} categoryNames
+     */
+    categoryNames: null,
+
+    /**
+     * Indicates whether or not to calculate the number of categories (ticks and
+     * labels) when there is not enough room to display all labels on the axis.
+     * If set to true, the axis will determine the number of categories to plot.
+     * If not, all categories will be plotted.
+     *
+     * @property calculateCategoryCount
+     * @type Boolean
+     */
+    calculateCategoryCount: false,
+
+    // @private creates an array of labels to be used when rendering.
+    setLabels: function() {
+        var store = this.chart.store,
+            fields = this.fields,
+            ln = fields.length,
+            i;
+
+        this.labels = [];
+        store.each(function(record) {
+            for (i = 0; i < ln; i++) {
+                this.labels.push(record.get(fields[i]));
+            }
+        }, this);
+    },
+
+    // @private calculates labels positions and marker positions for rendering.
+    applyData: function() {
+        this.callParent();
+        this.setLabels();
+        var count = this.chart.store.getCount();
+        return {
+            from: 0,
+            to: count,
+            power: 1,
+            step: 1,
+            steps: count - 1
+        };
+    }
+});
+
+/**
+ * @class Ext.chart.axis.Gauge
+ * @extends Ext.chart.axis.Abstract
+ *
+ * Gauge Axis is the axis to be used with a Gauge series. The Gauge axis
+ * displays numeric data from an interval defined by the `minimum`, `maximum` and
+ * `step` configuration properties. The placement of the numeric data can be changed
+ * by altering the `margin` option that is set to `10` by default.
+ *
+ * A possible configuration for this axis would look like:
+ *
+ *     axes: [{
+ *         type: 'gauge',
+ *         position: 'gauge',
+ *         minimum: 0,
+ *         maximum: 100,
+ *         steps: 10,
+ *         margin: 7
+ *     }],
  */
+Ext.define('Ext.chart.axis.Gauge', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.chart.axis.Abstract',
+
+    /* End Definitions */
+
+    /**
+     * @cfg {Number} minimum (required)
+     * The minimum value of the interval to be displayed in the axis.
+     */
+
+    /**
+     * @cfg {Number} maximum (required)
+     * The maximum value of the interval to be displayed in the axis.
+     */
+
+    /**
+     * @cfg {Number} steps (required)
+     * The number of steps and tick marks to add to the interval.
+     */
+
+    /**
+     * @cfg {Number} [margin=10]
+     * The offset positioning of the tick marks and labels in pixels.
+     */
+
+    /**
+     * @cfg {String} title
+     * The title for the Axis.
+     */
+
+    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) {
+                //draw circles
+                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;
+                //draw circles
+                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);
+    },
+
+    /**
+     * Updates the {@link #title} of this axis.
+     * @param {String} title
+     */
+    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,
+            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) {
+            //draw scale
+            for (i = 0; i <= steps; i++) {
+                // TODO Adjust for height of text / 2 instead
+                adjY = (i === 0 || i === steps) ? 7 : 0;
+                label = surface.add({
+                    type: 'text',
+                    text: renderer(round(i / steps * maxValue)),
+                    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;
+            //draw values
+            for (i = 0; i <= steps; i++) {
+                // TODO Adjust for height of text / 2 instead
+                adjY = (i === 0 || i === steps) ? 7 : 0;
+                labelArray[i].setAttributes({
+                    text: renderer(round(i / steps * maxValue)),
+                    x: centerX + rho * cos(i / steps * pi - pi),
+                    y: centerY + rho * sin(i / steps * pi - pi) - adjY
+                }, true);
+            }
+        }
+        this.labelArray = labelArray;
+    }
+});
+/**
+ * @class Ext.chart.axis.Numeric
+ * @extends Ext.chart.axis.Axis
+ *
+ * An axis to handle numeric values. This axis is used for quantitative data as
+ * opposed to the category axis. You can set mininum and maximum values to the
+ * axis so that the values are bound to that. If no values are set, then the
+ * scale will auto-adjust to the values.
+ *
+ *     @example
+ *     var store = Ext.create('Ext.data.JsonStore', {
+ *          fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
+ *          data: [
+ *              {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
+ *              {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
+ *              {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
+ *              {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
+ *              {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
+ *          ]
+ *     });
+ *
+ *     Ext.create('Ext.chart.Chart', {
+ *         renderTo: Ext.getBody(),
+ *         width: 500,
+ *         height: 300,
+ *         store: store,
+ *         axes: [{
+ *             type: 'Numeric',
+ *             grid: true,
+ *             position: 'left',
+ *             fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *             title: 'Sample Values',
+ *             grid: {
+ *                 odd: {
+ *                     opacity: 1,
+ *                     fill: '#ddd',
+ *                     stroke: '#bbb',
+ *                     'stroke-width': 1
+ *                 }
+ *             },
+ *             minimum: 0,
+ *             adjustMinimumByMajorUnit: 0
+ *         }, {
+ *             type: 'Category',
+ *             position: 'bottom',
+ *             fields: ['name'],
+ *             title: 'Sample Metrics',
+ *             grid: true,
+ *             label: {
+ *                 rotate: {
+ *                     degrees: 315
+ *                 }
+ *             }
+ *         }],
+ *         series: [{
+ *             type: 'area',
+ *             highlight: false,
+ *             axis: 'left',
+ *             xField: 'name',
+ *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *             style: {
+ *                 opacity: 0.93
+ *             }
+ *         }]
+ *     });
+ *
+ * In this example we create an axis of Numeric type. We set a minimum value so that
+ * even if all series have values greater than zero, the grid starts at zero. We bind
+ * the axis onto the left part of the surface by setting `position` to `left`.
+ * We bind three different store fields to this axis by setting `fields` to an array.
+ * We set the title of the axis to _Number of Hits_ by using the `title` property.
+ * We use a `grid` configuration to set odd background rows to a certain style and even rows
+ * to be transparent/ignored.
+ */
+Ext.define('Ext.chart.axis.Numeric', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.chart.axis.Axis',
+
+    alternateClassName: 'Ext.chart.NumericAxis',
+
+    /* End Definitions */
+
+    type: 'numeric',
+
+    alias: 'axis.numeric',
+
+    constructor: function(config) {
+        var me = this,
+            hasLabel = !!(config.label && config.label.renderer),
+            label;
+
+        me.callParent([config]);
+        label = me.label;
+        if (me.roundToDecimal === false) {
+            return;
+        }
+        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.floor(v * val) / val;
+    },
+
+    /**
+     * The minimum value drawn by the axis. If not set explicitly, the axis
+     * minimum will be calculated automatically.
+     *
+     * @property {Number} minimum
+     */
+    minimum: NaN,
+
+    /**
+     * The maximum value drawn by the axis. If not set explicitly, the axis
+     * maximum will be calculated automatically.
+     *
+     * @property {Number} maximum
+     */
+    maximum: NaN,
+
+    /**
+     * The number of decimals to round the value to.
+     *
+     * @property {Number} decimals
+     */
+    decimals: 2,
+
+    /**
+     * The scaling algorithm to use on this axis. May be "linear" or
+     * "logarithmic".  Currently only linear scale is implemented.
+     *
+     * @property {String} scale
+     * @private
+     */
+    scale: "linear",
+
+    /**
+     * Indicates the position of the axis relative to the chart
+     *
+     * @property {String} position
+     */
+    position: 'left',
+
+    /**
+     * Indicates whether to extend maximum beyond data's maximum to the nearest
+     * majorUnit.
+     *
+     * @property {Boolean} adjustMaximumByMajorUnit
+     */
+    adjustMaximumByMajorUnit: false,
+
+    /**
+     * Indicates whether to extend the minimum beyond data's minimum to the
+     * nearest majorUnit.
+     *
+     * @property {Boolean} adjustMinimumByMajorUnit
+     */
+    adjustMinimumByMajorUnit: false,
+
+    // @private apply data.
+    applyData: function() {
+        this.callParent();
+        return this.calcEnds();
+    }
+});
+
+/**
+ * @class Ext.chart.axis.Radial
+ * @extends Ext.chart.axis.Abstract
+ * @ignore
+ */
+Ext.define('Ext.chart.axis.Radial', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.chart.axis.Abstract',
+
+    /* End Definitions */
+
+    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) {
+            //draw circles
+            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);
+            }
+            //draw lines
+            store.each(function(rec, 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;
+            //draw circles
+            for (i = 0; i < steps; i++) {
+                sprites[i].setAttributes({
+                    x: centerX,
+                    y: centerY,
+                    radius: Math.max(rho * (i + 1) / steps, 0),
+                    stroke: '#ccc'
+                }, true);
+            }
+            //draw lines
+            store.each(function(rec, 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,
+            surface = chart.surface,
+            bbox = chart.chartBBox,
+            store = chart.store,
+            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;
+        }
+
+        //get all rendered fields
+        chart.series.each(function(series) {
+            fields.push(series.yField);
+            xField = series.xField;
+        });
+        
+        //get maxValue to interpolate
+        store.each(function(record, i) {
+            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') {
+                //draw scale
+                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') {
+                //draw text
+                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') {
+                //draw values
+                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') {
+                //draw text
+                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;
+    }
+});
+/**
+ * @author Ed Spencer
+ *
+ * AbstractStore is a superclass of {@link Ext.data.Store} and {@link Ext.data.TreeStore}. It's never used directly,
+ * but offers a set of methods used by both of those subclasses.
+ * 
+ * We've left it here in the docs for reference purposes, but unless you need to make a whole new type of Store, what
+ * you're probably looking for is {@link Ext.data.Store}. If you're still interested, here's a brief description of what 
+ * AbstractStore is and is not.
+ * 
+ * AbstractStore provides the basic configuration for anything that can be considered a Store. It expects to be 
+ * given a {@link Ext.data.Model Model} that represents the type of data in the Store. It also expects to be given a 
+ * {@link Ext.data.proxy.Proxy Proxy} that handles the loading of data into the Store.
+ * 
+ * AbstractStore provides a few helpful methods such as {@link #load} and {@link #sync}, which load and save data
+ * respectively, passing the requests through the configured {@link #proxy}. Both built-in Store subclasses add extra
+ * behavior to each of these functions. Note also that each AbstractStore subclass has its own way of storing data - 
+ * in {@link Ext.data.Store} the data is saved as a flat {@link Ext.util.MixedCollection MixedCollection}, whereas in
+ * {@link Ext.data.TreeStore TreeStore} we use a {@link Ext.data.Tree} to maintain the data's hierarchy.
+ * 
+ * The store provides filtering and sorting support. This sorting/filtering can happen on the client side
+ * or can be completed on the server. This is controlled by the {@link Ext.data.Store#remoteSort remoteSort} and
+ * {@link Ext.data.Store#remoteFilter remoteFilter} config options. For more information see the {@link #sort} and
+ * {@link Ext.data.Store#filter filter} methods.
+ */
+Ext.define('Ext.data.AbstractStore', {
+    requires: ['Ext.util.MixedCollection', '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,
+
+    /**
+     * @cfg {String/Ext.data.proxy.Proxy/Object} proxy
+     * The Proxy to use for this Store. This can be either a string, a config object or a Proxy instance -
+     * see {@link #setProxy} for details.
+     */
+
+    /**
+     * @cfg {Boolean/Object} autoLoad
+     * If data is not specified, and if autoLoad is true or an Object, this store's load method is automatically called
+     * after creation. If the value of autoLoad is an Object, this Object will be passed to the store's load method.
+     * Defaults to false.
+     */
+    autoLoad: false,
+
+    /**
+     * @cfg {Boolean} autoSync
+     * True to automatically sync the Store with its Proxy after every edit to one of its Records. Defaults to false.
+     */
+    autoSync: false,
+
+    /**
+     * @property {String} batchUpdateMode
+     * Sets the updating behavior based on batch synchronization. 'operation' (the default) will update the Store's
+     * internal representation of the data after each operation of the batch has completed, 'complete' will wait until
+     * the entire batch has been completed before updating the Store's data. 'complete' is a good choice for local
+     * storage proxies, 'operation' is better for remote proxies, where there is a comparatively high latency.
+     */
+    batchUpdateMode: 'operation',
+
+    /**
+     * @property {Boolean} filterOnLoad
+     * If true, any filters attached to this Store will be run after loading data, before the datachanged event is fired.
+     * Defaults to true, ignored if {@link Ext.data.Store#remoteFilter remoteFilter} is true
+     */
+    filterOnLoad: true,
+
+    /**
+     * @property {Boolean} sortOnLoad
+     * If true, any sorters attached to this Store will be run after loading data, before the datachanged event is fired.
+     * Defaults to true, igored if {@link Ext.data.Store#remoteSort remoteSort} is true
+     */
+    sortOnLoad: true,
+
+    /**
+     * @property {Boolean} implicitModel
+     * True if a model was created implicitly for this Store. This happens if a fields array is passed to the Store's
+     * constructor instead of a model constructor or name.
+     * @private
+     */
+    implicitModel: false,
+
+    /**
+     * @property {String} defaultProxyType
+     * The string type of the Proxy to create if none is specified. This defaults to creating a
+     * {@link Ext.data.proxy.Memory memory proxy}.
+     */
+    defaultProxyType: 'memory',
+
+    /**
+     * @property {Boolean} isDestroyed
+     * True if the Store has already been destroyed. If this is true, the reference to Store should be deleted
+     * as it will not function correctly any more.
+     */
+    isDestroyed: false,
+
+    isStore: true,
+
+    /**
+     * @cfg {String} storeId
+     * Unique identifier for this store. If present, this Store will be registered with the {@link Ext.data.StoreManager},
+     * making it easy to reuse elsewhere. Defaults to undefined.
+     */
+    
+    /**
+     * @cfg {Object[]} fields
+     * This may be used in place of specifying a {@link #model} configuration. The fields should be a 
+     * set of {@link Ext.data.Field} configuration objects. The store will automatically create a {@link Ext.data.Model}
+     * with these fields. In general this configuration option should be avoided, it exists for the purposes of
+     * backwards compatibility. For anything more complicated, such as specifying a particular id property or
+     * assocations, a {@link Ext.data.Model} should be defined and specified for the {@link #model}
+     * config.
+     */
+
+    /**
+     * @cfg {String} model
+     * Name of the {@link Ext.data.Model Model} associated with this store.
+     * The string is used as an argument for {@link Ext.ModelManager#getModel}.
+     */
+
+    sortRoot: 'data',
+    
+    //documented above
+    constructor: function(config) {
+        var me = this,
+            filters;
+        
+        me.addEvents(
+            /**
+             * @event add
+             * Fired when a Model instance has been added to this Store
+             * @param {Ext.data.Store} store The store
+             * @param {Ext.data.Model[]} records The Model instances that were added
+             * @param {Number} index The index at which the instances were inserted
+             */
+            'add',
+
+            /**
+             * @event remove
+             * Fired when a Model instance has been removed from this Store
+             * @param {Ext.data.Store} store The Store object
+             * @param {Ext.data.Model} record The record that was removed
+             * @param {Number} index The index of the record that was removed
+             */
+            'remove',
+            
+            /**
+             * @event update
+             * Fires when a Model instance has been updated
+             * @param {Ext.data.Store} this
+             * @param {Ext.data.Model} record The Model instance that was updated
+             * @param {String} operation The update operation being performed. Value may be one of:
+             *
+             *     Ext.data.Model.EDIT
+             *     Ext.data.Model.REJECT
+             *     Ext.data.Model.COMMIT
+             */
+            'update',
+
+            /**
+             * @event datachanged
+             * Fires whenever the records in the Store have changed in some way - this could include adding or removing
+             * records, or updating the data in existing records
+             * @param {Ext.data.Store} this The data store
+             */
+            'datachanged',
+
+            /**
+             * @event beforeload
+             * Fires before a request is made for a new data object. If the beforeload handler returns false the load
+             * action will be canceled.
+             * @param {Ext.data.Store} store This Store
+             * @param {Ext.data.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to
+             * load the Store
+             */
+            'beforeload',
+
+            /**
+             * @event load
+             * Fires whenever the store reads data from a remote data source.
+             * @param {Ext.data.Store} this
+             * @param {Ext.data.Model[]} records An array of records
+             * @param {Boolean} successful True if the operation was successful.
+             */
+            'load',
+            
+            /**
+             * @event write
+             * Fires whenever a successful write has been made via the configured {@link #proxy Proxy}
+             * @param {Ext.data.Store} store This Store
+             * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object that was used in
+             * the write
+             */
+            'write',
+
+            /**
+             * @event beforesync
+             * Fired before a call to {@link #sync} is executed. Return false from any listener to cancel the synv
+             * @param {Object} options Hash of all records to be synchronized, broken down into create, update and destroy
+             */
+            'beforesync',
+            /**
+             * @event clear
+             * Fired after the {@link #removeAll} method is called.
+             * @param {Ext.data.Store} this
+             */
+            'clear'
+        );
+        
+        Ext.apply(me, config);
+        // don't use *config* anymore from here on... use *me* instead...
+
+        /**
+         * Temporary cache in which removed model instances are kept until successfully synchronised with a Proxy,
+         * at which point this is cleared.
+         * @private
+         * @property {Ext.data.Model[]} removed
+         */
+        me.removed = [];
+
+        me.mixins.observable.constructor.apply(me, arguments);
+        me.model = Ext.ModelManager.getModel(me.model);
+
+        /**
+         * @property {Object} modelDefaults
+         * @private
+         * A set of default values to be applied to every model instance added via {@link #insert} or created via {@link #create}.
+         * This is used internally by associations to set foreign keys and other fields. See the Association classes source code
+         * for examples. This should not need to be used by application developers.
+         */
+        Ext.applyIf(me, {
+            modelDefaults: {}
+        });
+
+        //Supports the 3.x style of simply passing an array of fields to the store, implicitly creating a model
+        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;
+        }
+        
+        // <debug>
+        if (!me.model) {
+            if (Ext.isDefined(Ext.global.console)) {
+                Ext.global.console.warn('Store defined with no model. You may have mistyped the model name.');
+            }
+        }
+        // </debug>
+
+        //ensures that the Proxy is instantiated correctly
+        me.setProxy(me.proxy || me.model.getProxy());
+
+        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);        
+        
+        /**
+         * @property {Ext.util.MixedCollection} filters
+         * The collection of {@link Ext.util.Filter Filters} currently applied to this Store
+         */
+        filters = me.decodeFilters(me.filters);
+        me.filters = Ext.create('Ext.util.MixedCollection');
+        me.filters.addAll(filters);
+    },
+
+    /**
+     * Sets the Store's Proxy by string, config object or Proxy instance
+     * @param {String/Object/Ext.data.proxy.Proxy} proxy The new Proxy, which can be either a type string, a configuration object
+     * or an Ext.data.proxy.Proxy instance
+     * @return {Ext.data.proxy.Proxy} The attached Proxy object
+     */
+    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;
+    },
 
-Ext.define('Ext.chart.axis.Category', {
+    /**
+     * Returns the proxy currently attached to this proxy instance
+     * @return {Ext.data.proxy.Proxy} The Proxy instance
+     */
+    getProxy: function() {
+        return this.proxy;
+    },
 
-    /* Begin Definitions */
+    //saves any phantom records
+    create: function(data, options) {
+        var me = this,
+            instance = Ext.ModelManager.create(Ext.applyIf(data, me.modelDefaults), me.model.modelName),
+            operation;
+        
+        options = options || {};
 
-    extend: 'Ext.chart.axis.Axis',
+        Ext.applyIf(options, {
+            action : 'create',
+            records: [instance]
+        });
 
-    alternateClassName: 'Ext.chart.CategoryAxis',
+        operation = Ext.create('Ext.data.Operation', options);
 
-    alias: 'axis.category',
+        me.proxy.create(operation, me.onProxyWrite, me);
+        
+        return instance;
+    },
 
-    /* End Definitions */
+    read: function() {
+        return this.load.apply(this, arguments);
+    },
+
+    onProxyRead: Ext.emptyFn,
+
+    update: function(options) {
+        var me = this,
+            operation;
+        options = options || {};
+
+        Ext.applyIf(options, {
+            action : 'update',
+            records: me.getUpdatedRecords()
+        });
+
+        operation = Ext.create('Ext.data.Operation', options);
+
+        return me.proxy.update(operation, me.onProxyWrite, me);
+    },
 
     /**
-     * A list of category names to display along this axis.
-     *
-     * @property categoryNames
-     * @type Array
+     * @private
+     * Callback for any write Operation over the Proxy. Updates the Store's MixedCollection to reflect
+     * the updates provided by the Proxy
      */
-    categoryNames: null,
+    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);
+        }
+        //this is a callback that would have been passed to the 'create', 'update' or 'destroy' function and is optional
+        Ext.callback(operation.callback, operation.scope || me, [records, operation, success]);
+    },
+
+
+    //tells the attached proxy to destroy the given records
+    destroy: function(options) {
+        var me = this,
+            operation;
+            
+        options = options || {};
+
+        Ext.applyIf(options, {
+            action : 'destroy',
+            records: me.getRemovedRecords()
+        });
+
+        operation = Ext.create('Ext.data.Operation', options);
+
+        return me.proxy.destroy(operation, me.onProxyWrite, me);
+    },
 
     /**
-     * Indicates whether or not to calculate the number of categories (ticks and
-     * labels) when there is not enough room to display all labels on the axis.
-     * If set to true, the axis will determine the number of categories to plot.
-     * If not, all categories will be plotted.
-     *
-     * @property calculateCategoryCount
-     * @type Boolean
+     * @private
+     * Attached as the 'operationcomplete' event listener to a proxy's Batch object. By default just calls through
+     * to onProxyWrite.
      */
-    calculateCategoryCount: false,
+    onBatchOperationComplete: function(batch, operation) {
+        return this.onProxyWrite(operation);
+    },
 
-    // @private creates an array of labels to be used when rendering.
-    setLabels: function() {
-        var store = this.chart.store,
-            fields = this.fields,
-            ln = fields.length,
+    /**
+     * @private
+     * Attached as the 'complete' event listener to a proxy's Batch object. Iterates over the batch operations
+     * and updates the Store's internal data MixedCollection.
+     */
+    onBatchComplete: function(batch, operation) {
+        var me = this,
+            operations = batch.operations,
+            length = operations.length,
             i;
 
-        this.labels = [];
-        store.each(function(record) {
-            for (i = 0; i < ln; i++) {
-                this.labels.push(record.get(fields[i]));
-            }
-        }, this);
-    },
+        me.suspendEvents();
 
-    // @private calculates labels positions and marker positions for rendering.
-    applyData: function() {
-        this.callParent();
-        this.setLabels();
-        var count = this.chart.store.getCount();
-        return {
-            from: 0,
-            to: count,
-            power: 1,
-            step: 1,
-            steps: count - 1
-        };
-    }
-});
+        for (i = 0; i < length; i++) {
+            me.onProxyWrite(operations[i]);
+        }
 
-/**
- * @class Ext.chart.axis.Gauge
- * @extends Ext.chart.axis.Abstract
- *
- * Gauge Axis is the axis to be used with a Gauge series. The Gauge axis
- * displays numeric data from an interval defined by the `minimum`, `maximum` and
- * `step` configuration properties. The placement of the numeric data can be changed
- * by altering the `margin` option that is set to `10` by default.
- *
- * A possible configuration for this axis would look like:
- *
- *     axes: [{
- *         type: 'gauge',
- *         position: 'gauge',
- *         minimum: 0,
- *         maximum: 100,
- *         steps: 10,
- *         margin: 7
- *     }],
- */
-Ext.define('Ext.chart.axis.Gauge', {
+        me.resumeEvents();
 
-    /* Begin Definitions */
+        me.fireEvent('datachanged', me);
+    },
 
-    extend: 'Ext.chart.axis.Abstract',
+    onBatchException: function(batch, operation) {
+        // //decide what to do... could continue with the next operation
+        // batch.start();
+        //
+        // //or retry the last operation
+        // batch.retry();
+    },
 
-    /* End Definitions */
-    
     /**
-     * @cfg {Number} minimum (required) the minimum value of the interval to be displayed in the axis.
+     * @private
+     * Filter function for new records.
      */
+    filterNew: function(item) {
+        // only want phantom records that are valid
+        return item.phantom === true && item.isValid();
+    },
 
     /**
-     * @cfg {Number} maximum (required) the maximum value of the interval to be displayed in the axis.
+     * Returns all Model instances that are either currently a phantom (e.g. have no id), or have an ID but have not
+     * yet been saved on this Store (this happens when adding a non-phantom record from another Store into this one)
+     * @return {Ext.data.Model[]} The Model instances
      */
+    getNewRecords: function() {
+        return [];
+    },
 
     /**
-     * @cfg {Number} steps (required) the number of steps and tick marks to add to the interval.
+     * Returns all Model instances that have been updated in the Store but not yet synchronized with the Proxy
+     * @return {Ext.data.Model[]} The updated Model instances
      */
+    getUpdatedRecords: function() {
+        return [];
+    },
 
     /**
-     * @cfg {Number} margin (optional) the offset positioning of the tick marks and labels in pixels. Default's 10.
+     * @private
+     * Filter function for updated records.
      */
+    filterUpdated: function(item) {
+        // only want dirty records, not phantoms that are valid
+        return item.dirty === true && item.phantom !== true && item.isValid();
+    },
 
-    position: 'gauge',
+    /**
+     * Returns any records that have been removed from the store but not yet destroyed on the proxy.
+     * @return {Ext.data.Model[]} The removed Model instances
+     */
+    getRemovedRecords: function() {
+        return this.removed;
+    },
 
-    alias: 'axis.gauge',
+    filter: function(filters, value) {
 
-    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;
+    /**
+     * @private
+     * Normalizes an array of filter objects, ensuring that they are all Ext.util.Filter instances
+     * @param {Object[]} filters The filters array
+     * @return {Ext.util.Filter[]} Array of Ext.util.Filter objects
+     */
+    decodeFilters: function(filters) {
+        if (!Ext.isArray(filters)) {
+            if (filters === undefined) {
+                filters = [];
+            } else {
+                filters = [filters];
+            }
         }
 
-        if (this.margin >= 0) {
-            if (!this.sprites) {
-                //draw circles
-                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);
+        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'
+                });
+
+                //support for 3.x style filters where a function can be defined as 'fn'
+                if (config.fn) {
+                    config.filterFn = config.fn;
                 }
-            } else {
-                sprites = this.sprites;
-                //draw circles
-                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);
+
+                //support a function to be passed as a filter definition
+                if (typeof config == 'function') {
+                    config = {
+                        filterFn: config
+                    };
                 }
+
+                filters[i] = new Filter(config);
             }
         }
-        this.sprites = sprites;
-        this.drawLabel();
-        if (this.title) {
-            this.drawTitle();
-        }
+
+        return filters;
     },
-    
-    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);
+
+    clearFilter: function(supressEvent) {
+
     },
 
-    /**
-     * Updates the {@link #title} of this axis.
-     * @param {String} title
-     */
-    setTitle: function(title) {
-        this.title = title;
-        this.drawTitle();
+    isFiltered: function() {
+
     },
 
-    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,
-            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; };
+    filterBy: function(fn, scope) {
 
-        if (!this.labelArray) {
-            //draw scale
-            for (i = 0; i <= steps; i++) {
-                // TODO Adjust for height of text / 2 instead
-                adjY = (i === 0 || i === steps) ? 7 : 0;
-                label = surface.add({
-                    type: 'text',
-                    text: renderer(round(i / steps * maxValue)),
-                    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);
-            }
+    },
+    
+    /**
+     * Synchronizes the Store with its Proxy. This asks the Proxy to batch together any new, updated
+     * and deleted records in the store, updating the Store's internal representation of the records
+     * as each operation completes.
+     */
+    sync: function() {
+        var me        = this,
+            options   = {},
+            toCreate  = me.getNewRecords(),
+            toUpdate  = me.getUpdatedRecords(),
+            toDestroy = me.getRemovedRecords(),
+            needsSync = false;
+
+        if (toCreate.length > 0) {
+            options.create = toCreate;
+            needsSync = true;
         }
-        else {
-            labelArray = this.labelArray;
-            //draw values
-            for (i = 0; i <= steps; i++) {
-                // TODO Adjust for height of text / 2 instead
-                adjY = (i === 0 || i === steps) ? 7 : 0;
-                labelArray[i].setAttributes({
-                    text: renderer(round(i / steps * maxValue)),
-                    x: centerX + rho * cos(i / steps * pi - pi),
-                    y: centerY + rho * sin(i / steps * pi - pi) - adjY
-                }, true);
-            }
+
+        if (toUpdate.length > 0) {
+            options.update = toUpdate;
+            needsSync = true;
+        }
+
+        if (toDestroy.length > 0) {
+            options.destroy = toDestroy;
+            needsSync = true;
         }
-        this.labelArray = labelArray;
-    }
-});
-/**
- * @class Ext.chart.axis.Numeric
- * @extends Ext.chart.axis.Axis
- *
- * An axis to handle numeric values. This axis is used for quantitative data as
- * opposed to the category axis. You can set mininum and maximum values to the
- * axis so that the values are bound to that. If no values are set, then the
- * scale will auto-adjust to the values.
- *
- * {@img Ext.chart.axis.Numeric/Ext.chart.axis.Numeric.png Ext.chart.axis.Numeric chart axis}
- *
- * For example:
- *
- *     var store = Ext.create('Ext.data.JsonStore', {
- *          fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
- *          data: [
- *              {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- *              {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- *              {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- *              {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *              {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
- *          ]
- *     });
- *  
- *     Ext.create('Ext.chart.Chart', {
- *         renderTo: Ext.getBody(),
- *         width: 500,
- *         height: 300,
- *         store: store,
- *         axes: [{
- *             type: 'Numeric',
- *             grid: true,
- *             position: 'left',
- *             fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
- *             title: 'Sample Values',
- *             grid: {
- *                 odd: {
- *                     opacity: 1,
- *                     fill: '#ddd',
- *                     stroke: '#bbb',
- *                     'stroke-width': 1
- *                 }
- *             },
- *             minimum: 0,
- *             adjustMinimumByMajorUnit: 0
- *         }, {
- *             type: 'Category',
- *             position: 'bottom',
- *             fields: ['name'],
- *             title: 'Sample Metrics',
- *             grid: true,
- *             label: {
- *                 rotate: {
- *                     degrees: 315
- *                 }
- *             }
- *         }],
- *         series: [{
- *             type: 'area',
- *             highlight: false,
- *             axis: 'left',
- *             xField: 'name',
- *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
- *             style: {
- *                 opacity: 0.93
- *             }
- *         }]
- *     });
- *
- * In this example we create an axis of Numeric type. We set a minimum value so that
- * even if all series have values greater than zero, the grid starts at zero. We bind
- * the axis onto the left part of the surface by setting <em>position</em> to <em>left</em>.
- * We bind three different store fields to this axis by setting <em>fields</em> to an array.
- * We set the title of the axis to <em>Number of Hits</em> by using the <em>title</em> property.
- * We use a <em>grid</em> configuration to set odd background rows to a certain style and even rows
- * to be transparent/ignored.
- *
- */
-Ext.define('Ext.chart.axis.Numeric', {
 
-    /* Begin Definitions */
+        if (needsSync && me.fireEvent('beforesync', options) !== false) {
+            me.proxy.batch(options, me.getBatchListeners());
+        }
+    },
 
-    extend: 'Ext.chart.axis.Axis',
 
-    alternateClassName: 'Ext.chart.NumericAxis',
+    /**
+     * @private
+     * Returns an object which is passed in as the listeners argument to proxy.batch inside this.sync.
+     * This is broken out into a separate function to allow for customisation of the listeners
+     * @return {Object} The listeners object
+     */
+    getBatchListeners: function() {
+        var me = this,
+            listeners = {
+                scope: me,
+                exception: me.onBatchException
+            };
 
-    /* End Definitions */
+        if (me.batchUpdateMode == 'operation') {
+            listeners.operationcomplete = me.onBatchOperationComplete;
+        } else {
+            listeners.complete = me.onBatchComplete;
+        }
 
-    type: 'numeric',
+        return listeners;
+    },
 
-    alias: 'axis.numeric',
+    //deprecated, will be removed in 5.0
+    save: function() {
+        return this.sync.apply(this, arguments);
+    },
 
-    constructor: function(config) {
+    /**
+     * Loads the Store using its configured {@link #proxy}.
+     * @param {Object} options (optional) config object. This is passed into the {@link Ext.data.Operation Operation}
+     * object that is created and then sent to the proxy's {@link Ext.data.proxy.Proxy#read} function
+     */
+    load: function(options) {
         var me = this,
-            hasLabel = !!(config.label && config.label.renderer),
-            label;
+            operation;
+
+        options = options || {};
+
+        Ext.applyIf(options, {
+            action : 'read',
+            filters: me.filters.items,
+            sorters: me.getSorters()
+        });
         
-        me.callParent([config]);
-        label = me.label;
-        if (me.roundToDecimal === false) {
-            return;
+        operation = Ext.create('Ext.data.Operation', options);
+
+        if (me.fireEvent('beforeload', me, operation) !== false) {
+            me.loading = true;
+            me.proxy.read(operation, me.onProxyLoad, me);
         }
-        if (!hasLabel) {
-            label.renderer = function(v) {
-                return me.roundToDecimal(v, me.decimals);
-            };
-        } 
-    },
-    
-    roundToDecimal: function(v, dec) {
-        var val = Math.pow(10, dec || 0);
-        return ((v * val) >> 0) / val;
+        
+        return me;
     },
-    
-    /**
-     * The minimum value drawn by the axis. If not set explicitly, the axis
-     * minimum will be calculated automatically.
-     *
-     * @property minimum
-     * @type Number
-     */
-    minimum: NaN,
 
     /**
-     * The maximum value drawn by the axis. If not set explicitly, the axis
-     * maximum will be calculated automatically.
-     *
-     * @property maximum
-     * @type Number
+     * @private
+     * A model instance should call this method on the Store it has been {@link Ext.data.Model#join joined} to.
+     * @param {Ext.data.Model} record The model instance that was edited
      */
-    maximum: NaN,
+    afterEdit : function(record) {
+        var me = this;
+        
+        if (me.autoSync) {
+            me.sync();
+        }
+        
+        me.fireEvent('update', me, record, Ext.data.Model.EDIT);
+    },
 
     /**
-     * The number of decimals to round the value to.
-     * Default's 2.
-     *
-     * @property decimals
-     * @type Number
+     * @private
+     * A model instance should call this method on the Store it has been {@link Ext.data.Model#join joined} to..
+     * @param {Ext.data.Model} record The model instance that was edited
      */
-    decimals: 2,
+    afterReject : function(record) {
+        this.fireEvent('update', this, record, Ext.data.Model.REJECT);
+    },
 
     /**
-     * The scaling algorithm to use on this axis. May be "linear" or
-     * "logarithmic".
-     *
-     * @property scale
-     * @type String
+     * @private
+     * A model instance should call this method on the Store it has been {@link Ext.data.Model#join joined} to.
+     * @param {Ext.data.Model} record The model instance that was edited
      */
-    scale: "linear",
+    afterCommit : function(record) {
+        this.fireEvent('update', this, record, Ext.data.Model.COMMIT);
+    },
 
-    /**
-     * Indicates the position of the axis relative to the chart
-     *
-     * @property position
-     * @type String
-     */
-    position: 'left',
+    clearData: Ext.emptyFn,
+
+    destroyStore: function() {
+        var me = this;
+        
+        if (!me.isDestroyed) {
+            if (me.storeId) {
+                Ext.data.StoreManager.unregister(me);
+            }
+            me.clearData();
+            me.data = null;
+            me.tree = null;
+            // Ext.destroy(this.proxy);
+            me.reader = me.writer = null;
+            me.clearListeners();
+            me.isDestroyed = true;
+
+            if (me.implicitModel) {
+                Ext.destroy(me.model);
+            }
+        }
+    },
+    
+    doSort: function(sorterFn) {
+        var me = this;
+        if (me.remoteSort) {
+            //the load function will pick up the new sorters and request the sorted data from the proxy
+            me.load();
+        } else {
+            me.data.sortBy(sorterFn);
+            me.fireEvent('datachanged', me);
+        }
+    },
+
+    getCount: Ext.emptyFn,
 
+    getById: Ext.emptyFn,
+    
     /**
-     * Indicates whether to extend maximum beyond data's maximum to the nearest
-     * majorUnit.
-     *
-     * @property adjustMaximumByMajorUnit
-     * @type Boolean
+     * Removes all records from the store. This method does a "fast remove",
+     * individual remove events are not called. The {@link #clear} event is
+     * fired upon completion.
+     * @method
      */
-    adjustMaximumByMajorUnit: false,
+    removeAll: Ext.emptyFn,
+    // individual substores should implement a "fast" remove
+    // and fire a clear event afterwards
 
     /**
-     * Indicates whether to extend the minimum beyond data's minimum to the
-     * nearest majorUnit.
-     *
-     * @property adjustMinimumByMajorUnit
-     * @type Boolean
+     * Returns true if the Store is currently performing a load operation
+     * @return {Boolean} True if the Store is currently loading
      */
-    adjustMinimumByMajorUnit: false,
-
-    // @private apply data.
-    applyData: function() {
-        this.callParent();
-        return this.calcEnds();
-    }
+    isLoading: function() {
+        return !!this.loading;
+     }
 });
 
 /**
- * @class Ext.chart.axis.Radial
- * @extends Ext.chart.axis.Abstract
- * @ignore
+ * @class Ext.util.Grouper
+ * @extends Ext.util.Sorter
+
+Represents a single grouper that can be applied to a Store. The grouper works
+in the same fashion as the {@link Ext.util.Sorter}.
+
+ * @markdown
  */
-Ext.define('Ext.chart.axis.Radial', {
+Ext.define('Ext.util.Grouper', {
 
     /* Begin Definitions */
 
-    extend: 'Ext.chart.axis.Abstract',
+    extend: 'Ext.util.Sorter',
 
     /* End Definitions */
 
-    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;
-        }
+    /**
+     * Returns the value for grouping to be used.
+     * @param {Ext.data.Model} instance The Model instance
+     * @return {String} The group string for this model
+     */
+    getGroupString: function(instance) {
+        return instance.get(this.property);
+    }
+});
+/**
+ * @author Ed Spencer
+ * @class Ext.data.Store
+ * @extends Ext.data.AbstractStore
+ *
+ * <p>The Store class encapsulates a client side cache of {@link Ext.data.Model Model} objects. Stores load
+ * data via a {@link Ext.data.proxy.Proxy Proxy}, and also provide functions for {@link #sort sorting},
+ * {@link #filter filtering} and querying the {@link Ext.data.Model model} instances contained within it.</p>
+ *
+ * <p>Creating a Store is easy - we just tell it the Model and the Proxy to use to load and save its data:</p>
+ *
+<pre><code>
+// Set up a {@link Ext.data.Model model} to use in our Store
+Ext.define('User', {
+    extend: 'Ext.data.Model',
+    fields: [
+        {name: 'firstName', type: 'string'},
+        {name: 'lastName',  type: 'string'},
+        {name: 'age',       type: 'int'},
+        {name: 'eyeColor',  type: 'string'}
+    ]
+});
 
-        if (!this.sprites) {
-            //draw circles
-            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);
-            }
-            //draw lines
-            store.each(function(rec, 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;
-            //draw circles
-            for (i = 0; i < steps; i++) {
-                sprites[i].setAttributes({
-                    x: centerX,
-                    y: centerY,
-                    radius: Math.max(rho * (i + 1) / steps, 0),
-                    stroke: '#ccc'
-                }, true);
-            }
-            //draw lines
-            store.each(function(rec, 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);
-            });
+var myStore = Ext.create('Ext.data.Store', {
+    model: 'User',
+    proxy: {
+        type: 'ajax',
+        url : '/users.json',
+        reader: {
+            type: 'json',
+            root: 'users'
         }
-        this.sprites = sprites;
-
-        this.drawLabel();
     },
+    autoLoad: true
+});
+</code></pre>
 
-    drawLabel: function() {
-        var chart = this.chart,
-            surface = chart.surface,
-            bbox = chart.chartBBox,
-            store = chart.store,
-            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;
+ * <p>In the example above we configured an AJAX proxy to load data from the url '/users.json'. We told our Proxy
+ * to use a {@link Ext.data.reader.Json JsonReader} to parse the response from the server into Model object -
+ * {@link Ext.data.reader.Json see the docs on JsonReader} for details.</p>
+ *
+ * <p><u>Inline data</u></p>
+ *
+ * <p>Stores can also load data inline. Internally, Store converts each of the objects we pass in as {@link #data}
+ * into Model instances:</p>
+ *
+<pre><code>
+Ext.create('Ext.data.Store', {
+    model: 'User',
+    data : [
+        {firstName: 'Ed',    lastName: 'Spencer'},
+        {firstName: 'Tommy', lastName: 'Maintz'},
+        {firstName: 'Aaron', lastName: 'Conran'},
+        {firstName: 'Jamie', lastName: 'Avins'}
+    ]
+});
+</code></pre>
+ *
+ * <p>Loading inline data using the method above is great if the data is in the correct format already (e.g. it doesn't need
+ * to be processed by a {@link Ext.data.reader.Reader reader}). If your inline data requires processing to decode the data structure,
+ * use a {@link Ext.data.proxy.Memory MemoryProxy} instead (see the {@link Ext.data.proxy.Memory MemoryProxy} docs for an example).</p>
+ *
+ * <p>Additional data can also be loaded locally using {@link #add}.</p>
+ *
+ * <p><u>Loading Nested Data</u></p>
+ *
+ * <p>Applications often need to load sets of associated data - for example a CRM system might load a User and her Orders.
+ * Instead of issuing an AJAX request for the User and a series of additional AJAX requests for each Order, we can load a nested dataset
+ * and allow the Reader to automatically populate the associated models. Below is a brief example, see the {@link Ext.data.reader.Reader} intro
+ * docs for a full explanation:</p>
+ *
+<pre><code>
+var store = Ext.create('Ext.data.Store', {
+    autoLoad: true,
+    model: "User",
+    proxy: {
+        type: 'ajax',
+        url : 'users.json',
+        reader: {
+            type: 'json',
+            root: 'users'
         }
-
-        //get all rendered fields
-        chart.series.each(function(series) {
-            fields.push(series.yField);
-            xField = series.xField;
-        });
-        
-        //get maxValue to interpolate
-        store.each(function(record, i) {
-            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') {
-                //draw scale
-                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') {
-                //draw text
-                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);
+    }
+});
+</code></pre>
+ *
+ * <p>Which would consume a response like this:</p>
+ *
+<pre><code>
+{
+    "users": [
+        {
+            "id": 1,
+            "name": "Ed",
+            "orders": [
+                {
+                    "id": 10,
+                    "total": 10.76,
+                    "status": "invoiced"
+                },
+                {
+                    "id": 11,
+                    "total": 13.45,
+                    "status": "shipped"
                 }
-            }
+            ]
         }
-        else {
-            labelArray = this.labelArray;
-            if (display != 'categories') {
-                //draw values
-                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') {
-                //draw text
-                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);
-                    }
-                }
-            }
+    ]
+}
+</code></pre>
+ *
+ * <p>See the {@link Ext.data.reader.Reader} intro docs for a full explanation.</p>
+ *
+ * <p><u>Filtering and Sorting</u></p>
+ *
+ * <p>Stores can be sorted and filtered - in both cases either remotely or locally. The {@link #sorters} and {@link #filters} are
+ * held inside {@link Ext.util.MixedCollection MixedCollection} instances to make them easy to manage. Usually it is sufficient to
+ * either just specify sorters and filters in the Store configuration or call {@link #sort} or {@link #filter}:
+ *
+<pre><code>
+var store = Ext.create('Ext.data.Store', {
+    model: 'User',
+    sorters: [
+        {
+            property : 'age',
+            direction: 'DESC'
+        },
+        {
+            property : 'firstName',
+            direction: 'ASC'
+        }
+    ],
+
+    filters: [
+        {
+            property: 'firstName',
+            value   : /Ed/
         }
-        this.labelArray = labelArray;
-    }
+    ]
 });
-/**
- * @author Ed Spencer
- * @class Ext.data.AbstractStore
+</code></pre>
+ *
+ * <p>The new Store will keep the configured sorters and filters in the MixedCollection instances mentioned above. By default, sorting
+ * and filtering are both performed locally by the Store - see {@link #remoteSort} and {@link #remoteFilter} to allow the server to
+ * perform these operations instead.</p>
+ *
+ * <p>Filtering and sorting after the Store has been instantiated is also easy. Calling {@link #filter} adds another filter to the Store
+ * and automatically filters the dataset (calling {@link #filter} with no arguments simply re-applies all existing filters). Note that by
+ * default {@link #sortOnFilter} is set to true, which means that your sorters are automatically reapplied if using local sorting.</p>
+ *
+<pre><code>
+store.filter('eyeColor', 'Brown');
+</code></pre>
+ *
+ * <p>Change the sorting at any time by calling {@link #sort}:</p>
+ *
+<pre><code>
+store.sort('height', 'ASC');
+</code></pre>
+ *
+ * <p>Note that all existing sorters will be removed in favor of the new sorter data (if {@link #sort} is called with no arguments,
+ * the existing sorters are just reapplied instead of being removed). To keep existing sorters and add new ones, just add them
+ * to the MixedCollection:</p>
+ *
+<pre><code>
+store.sorters.add(new Ext.util.Sorter({
+    property : 'shoeSize',
+    direction: 'ASC'
+}));
+
+store.sort();
+</code></pre>
+ *
+ * <p><u>Registering with StoreManager</u></p>
+ *
+ * <p>Any Store that is instantiated with a {@link #storeId} will automatically be registed with the {@link Ext.data.StoreManager StoreManager}.
+ * This makes it easy to reuse the same store in multiple views:</p>
+ *
+ <pre><code>
+//this store can be used several times
+Ext.create('Ext.data.Store', {
+    model: 'User',
+    storeId: 'usersStore'
+});
+
+new Ext.List({
+    store: 'usersStore',
+
+    //other config goes here
+});
+
+new Ext.view.View({
+    store: 'usersStore',
+
+    //other config goes here
+});
+</code></pre>
+ *
+ * <p><u>Further Reading</u></p>
+ *
+ * <p>Stores are backed up by an ecosystem of classes that enables their operation. To gain a full understanding of these
+ * pieces and how they fit together, see:</p>
+ *
+ * <ul style="list-style-type: disc; padding-left: 25px">
+ * <li>{@link Ext.data.proxy.Proxy Proxy} - overview of what Proxies are and how they are used</li>
+ * <li>{@link Ext.data.Model Model} - the core class in the data package</li>
+ * <li>{@link Ext.data.reader.Reader Reader} - used by any subclass of {@link Ext.data.proxy.Server ServerProxy} to read a response</li>
+ * </ul>
  *
- * <p>AbstractStore is a superclass of {@link Ext.data.Store} and {@link Ext.data.TreeStore}. It's never used directly,
- * but offers a set of methods used by both of those subclasses.</p>
- * 
- * <p>We've left it here in the docs for reference purposes, but unless you need to make a whole new type of Store, what
- * you're probably looking for is {@link Ext.data.Store}. If you're still interested, here's a brief description of what 
- * AbstractStore is and is not.</p>
- * 
- * <p>AbstractStore provides the basic configuration for anything that can be considered a Store. It expects to be 
- * given a {@link Ext.data.Model Model} that represents the type of data in the Store. It also expects to be given a 
- * {@link Ext.data.proxy.Proxy Proxy} that handles the loading of data into the Store.</p>
- * 
- * <p>AbstractStore provides a few helpful methods such as {@link #load} and {@link #sync}, which load and save data
- * respectively, passing the requests through the configured {@link #proxy}. Both built-in Store subclasses add extra
- * behavior to each of these functions. Note also that each AbstractStore subclass has its own way of storing data - 
- * in {@link Ext.data.Store} the data is saved as a flat {@link Ext.util.MixedCollection MixedCollection}, whereas in
- * {@link Ext.data.TreeStore TreeStore} we use a {@link Ext.data.Tree} to maintain the data's hierarchy.</p>
- * 
- * The store provides filtering and sorting support. This sorting/filtering can happen on the client side
- * or can be completed on the server. This is controlled by the {@link #remoteSort} and (@link #remoteFilter{ config
- * options. For more information see the {@link #sort} and {@link #filter} methods.
  */
-Ext.define('Ext.data.AbstractStore', {
-    requires: ['Ext.util.MixedCollection', '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,
+Ext.define('Ext.data.Store', {
+    extend: 'Ext.data.AbstractStore',
+
+    alias: 'store.store',
+
+    requires: ['Ext.data.StoreManager', 'Ext.ModelManager', 'Ext.data.Model', 'Ext.util.Grouper'],
+    uses: ['Ext.data.proxy.Memory'],
+
+    /**
+     * @cfg {Boolean} remoteSort
+     * True to defer any sorting operation to the server. If false, sorting is done locally on the client. Defaults to <tt>false</tt>.
+     */
+    remoteSort: false,
+
+    /**
+     * @cfg {Boolean} remoteFilter
+     * True to defer any filtering operation to the server. If false, filtering is done locally on the client. Defaults to <tt>false</tt>.
+     */
     remoteFilter: false,
 
+    /**
+     * @cfg {Boolean} remoteGroup
+     * True if the grouping should apply on the server side, false if it is local only.  If the
+     * grouping is local, it can be applied immediately to the data.  If it is remote, then it will simply act as a
+     * helper, automatically sending the grouping information to the server.
+     */
+    remoteGroup : false,
+
     /**
      * @cfg {String/Ext.data.proxy.Proxy/Object} proxy The Proxy to use for this Store. This can be either a string, a config
      * object or a Proxy instance - see {@link #setProxy} for details.
      */
 
     /**
-     * @cfg {Boolean/Object} autoLoad If data is not specified, and if autoLoad is true or an Object, this store's load method
-     * is automatically called after creation. If the value of autoLoad is an Object, this Object will be passed to the store's
-     * load method. Defaults to false.
+     * @cfg {Object[]/Ext.data.Model[]} data Optional array of Model instances or data objects to load locally. See "Inline data" above for details.
      */
-    autoLoad: false,
 
     /**
-     * @cfg {Boolean} autoSync True to automatically sync the Store with its Proxy after every edit to one of its Records.
-     * Defaults to false.
+     * @property {String} groupField
+     * The field by which to group data in the store. Internally, grouping is very similar to sorting - the
+     * groupField and {@link #groupDir} are injected as the first sorter (see {@link #sort}). Stores support a single
+     * level of grouping, and groups can be fetched via the {@link #getGroups} method.
      */
-    autoSync: false,
+    groupField: undefined,
 
     /**
-     * Sets the updating behavior based on batch synchronization. 'operation' (the default) will update the Store's
-     * internal representation of the data after each operation of the batch has completed, 'complete' will wait until
-     * the entire batch has been completed before updating the Store's data. 'complete' is a good choice for local
-     * storage proxies, 'operation' is better for remote proxies, where there is a comparatively high latency.
-     * @property batchUpdateMode
+     * The direction in which sorting should be applied when grouping. Defaults to "ASC" - the other supported value is "DESC"
+     * @property groupDir
      * @type String
      */
-    batchUpdateMode: 'operation',
+    groupDir: "ASC",
 
     /**
-     * If true, any filters attached to this Store will be run after loading data, before the datachanged event is fired.
-     * Defaults to true, ignored if {@link #remoteFilter} is true
-     * @property filterOnLoad
-     * @type Boolean
+     * @cfg {Number} pageSize
+     * The number of records considered to form a 'page'. This is used to power the built-in
+     * paging using the nextPage and previousPage functions. Defaults to 25.
      */
-    filterOnLoad: true,
+    pageSize: 25,
 
     /**
-     * If true, any sorters attached to this Store will be run after loading data, before the datachanged event is fired.
-     * Defaults to true, igored if {@link #remoteSort} is true
-     * @property sortOnLoad
-     * @type Boolean
+     * The page that the Store has most recently loaded (see {@link #loadPage})
+     * @property currentPage
+     * @type Number
      */
-    sortOnLoad: true,
+    currentPage: 1,
 
     /**
-     * True if a model was created implicitly for this Store. This happens if a fields array is passed to the Store's constructor
-     * instead of a model constructor or name.
-     * @property implicitModel
-     * @type Boolean
-     * @private
+     * @cfg {Boolean} clearOnPageLoad True to empty the store when loading another page via {@link #loadPage},
+     * {@link #nextPage} or {@link #previousPage}. Setting to false keeps existing records, allowing
+     * large data sets to be loaded one page at a time but rendered all together.
      */
-    implicitModel: false,
+    clearOnPageLoad: true,
 
     /**
-     * The string type of the Proxy to create if none is specified. This defaults to creating a {@link Ext.data.proxy.Memory memory proxy}.
-     * @property defaultProxyType
-     * @type String
+     * @property {Boolean} loading
+     * True if the Store is currently loading via its Proxy
+     * @private
      */
-    defaultProxyType: 'memory',
+    loading: false,
 
     /**
-     * True if the Store has already been destroyed via {@link #destroyStore}. If this is true, the reference to Store should be deleted
-     * as it will not function correctly any more.
-     * @property isDestroyed
-     * @type Boolean
+     * @cfg {Boolean} sortOnFilter For local filtering only, causes {@link #sort} to be called whenever {@link #filter} is called,
+     * causing the sorters to be reapplied after filtering. Defaults to true
      */
-    isDestroyed: false,
-
-    isStore: true,
+    sortOnFilter: true,
 
     /**
-     * @cfg {String} storeId Optional unique identifier for this store. If present, this Store will be registered with 
-     * the {@link Ext.data.StoreManager}, making it easy to reuse elsewhere. Defaults to undefined.
+     * @cfg {Boolean} buffered
+     * Allow the store to buffer and pre-fetch pages of records. This is to be used in conjunction with a view will
+     * tell the store to pre-fetch records ahead of a time.
      */
-    
+    buffered: false,
+
     /**
-     * @cfg {Array} fields
-     * This may be used in place of specifying a {@link #model} configuration. The fields should be a 
-     * set of {@link Ext.data.Field} configuration objects. The store will automatically create a {@link Ext.data.Model}
-     * with these fields. In general this configuration option should be avoided, it exists for the purposes of
-     * backwards compatibility. For anything more complicated, such as specifying a particular id property or
-     * assocations, a {@link Ext.data.Model} should be defined and specified for the {@link #model} config.
+     * @cfg {Number} purgePageCount
+     * The number of pages to keep in the cache before purging additional records. A value of 0 indicates to never purge the prefetched data.
+     * This option is only relevant when the {@link #buffered} option is set to true.
      */
+    purgePageCount: 5,
 
-    sortRoot: 'data',
-    
-    //documented above
+    isStore: true,
+
+    onClassExtended: function(cls, data) {
+        var model = data.model;
+
+        if (typeof model == 'string') {
+            var onBeforeClassCreated = data.onBeforeClassCreated;
+
+            data.onBeforeClassCreated = function(cls, data) {
+                var me = this;
+
+                Ext.require(model, function() {
+                    onBeforeClassCreated.call(me, cls, data);
+                });
+            };
+        }
+    },
+
+    /**
+     * Creates the store.
+     * @param {Object} config (optional) Config object
+     */
     constructor: function(config) {
-        var me = this,
-            filters;
-        
-        me.addEvents(
-            /**
-             * @event add
-             * Fired when a Model instance has been added to this Store
-             * @param {Ext.data.Store} store The store
-             * @param {Array} records The Model instances that were added
-             * @param {Number} index The index at which the instances were inserted
-             */
-            'add',
+        // Clone the config so we don't modify the original config object
+        config = Ext.Object.merge({}, config);
 
-            /**
-             * @event remove
-             * Fired when a Model instance has been removed from this Store
-             * @param {Ext.data.Store} store The Store object
-             * @param {Ext.data.Model} record The record that was removed
-             * @param {Number} index The index of the record that was removed
-             */
-            'remove',
-            
-            /**
-             * @event update
-             * Fires when a Record has been updated
-             * @param {Store} this
-             * @param {Ext.data.Model} record The Model instance that was updated
-             * @param {String} operation The update operation being performed. Value may be one of:
-             * <pre><code>
-               Ext.data.Model.EDIT
-               Ext.data.Model.REJECT
-               Ext.data.Model.COMMIT
-             * </code></pre>
-             */
-            'update',
+        var me = this,
+            groupers = config.groupers || me.groupers,
+            groupField = config.groupField || me.groupField,
+            proxy,
+            data;
 
-            /**
-             * @event datachanged
-             * Fires whenever the records in the Store have changed in some way - this could include adding or removing records,
-             * or updating the data in existing records
-             * @param {Ext.data.Store} this The data store
-             */
-            'datachanged',
+        if (config.buffered || me.buffered) {
+            me.prefetchData = Ext.create('Ext.util.MixedCollection', false, function(record) {
+                return record.index;
+            });
+            me.pendingRequests = [];
+            me.pagesRequested = [];
 
-            /**
-             * @event beforeload
-             * Event description
-             * @param {Ext.data.Store} store This Store
-             * @param {Ext.data.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to load the Store
-             */
-            'beforeload',
+            me.sortOnLoad = false;
+            me.filterOnLoad = false;
+        }
 
+        me.addEvents(
             /**
-             * @event load
-             * Fires whenever the store reads data from a remote data source.
+             * @event beforeprefetch
+             * Fires before a prefetch occurs. Return false to cancel.
              * @param {Ext.data.Store} this
-             * @param {Array} records An array of records
-             * @param {Boolean} successful True if the operation was successful.
+             * @param {Ext.data.Operation} operation The associated operation
              */
-            'load',
-
+            'beforeprefetch',
             /**
-             * @event beforesync
-             * Called before a call to {@link #sync} is executed. Return false from any listener to cancel the synv
-             * @param {Object} options Hash of all records to be synchronized, broken down into create, update and destroy
+             * @event groupchange
+             * Fired whenever the grouping in the grid changes
+             * @param {Ext.data.Store} store The store
+             * @param {Ext.util.Grouper[]} groupers The array of grouper objects
              */
-            'beforesync',
+            'groupchange',
             /**
-             * @event clear
-             * Fired after the {@link #removeAll} method is called.
+             * @event load
+             * Fires whenever records have been prefetched
              * @param {Ext.data.Store} this
+             * @param {Ext.util.Grouper[]} records An array of records
+             * @param {Boolean} successful True if the operation was successful.
+             * @param {Ext.data.Operation} operation The associated operation
              */
-            'clear'
+            'prefetch'
         );
-        
-        Ext.apply(me, config);
-        // don't use *config* anymore from here on... use *me* instead...
+        data = config.data || me.data;
 
         /**
-         * Temporary cache in which removed model instances are kept until successfully synchronised with a Proxy,
-         * at which point this is cleared.
-         * @private
-         * @property removed
-         * @type Array
+         * The MixedCollection that holds this store's local cache of records
+         * @property data
+         * @type Ext.util.MixedCollection
          */
-        me.removed = [];
+        me.data = Ext.create('Ext.util.MixedCollection', false, function(record) {
+            return record.internalId;
+        });
 
-        me.mixins.observable.constructor.apply(me, arguments);
-        me.model = Ext.ModelManager.getModel(me.model);
+        if (data) {
+            me.inlineData = data;
+            delete config.data;
+        }
+
+        if (!groupers && groupField) {
+            groupers = [{
+                property : groupField,
+                direction: config.groupDir || me.groupDir
+            }];
+        }
+        delete config.groupers;
 
         /**
-         * @property modelDefaults
-         * @type Object
-         * @private
-         * A set of default values to be applied to every model instance added via {@link #insert} or created via {@link #create}.
-         * This is used internally by associations to set foreign keys and other fields. See the Association classes source code
-         * for examples. This should not need to be used by application developers.
+         * The collection of {@link Ext.util.Grouper Groupers} currently applied to this Store
+         * @property groupers
+         * @type Ext.util.MixedCollection
          */
-        Ext.applyIf(me, {
-            modelDefaults: {}
-        });
-
-        //Supports the 3.x style of simply passing an array of fields to the store, implicitly creating a model
-        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
-            });
+        me.groupers = Ext.create('Ext.util.MixedCollection');
+        me.groupers.addAll(me.decodeGroupers(groupers));
 
-            delete me.fields;
+        this.callParent([config]);
+        // don't use *config* anymore from here on... use *me* instead...
 
-            me.implicitModel = true;
+        if (me.groupers.items.length) {
+            me.sort(me.groupers.items, 'prepend', false);
         }
 
-        //ensures that the Proxy is instantiated correctly
-        me.setProxy(me.proxy || me.model.getProxy());
+        proxy = me.proxy;
+        data = me.inlineData;
 
-        if (me.id && !me.storeId) {
-            me.storeId = me.id;
-            delete me.id;
+        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]);
+            // Remove the defer call, we may need reinstate this at some point, but currently it's not obvious why it's here.
+            // this.load(typeof this.autoLoad == 'object' ? this.autoLoad : undefined);
         }
+    },
 
-        if (me.storeId) {
-            Ext.data.StoreManager.register(me);
+    onBeforeSort: function() {
+        var groupers = this.groupers;
+        if (groupers.getCount() > 0) {
+            this.sort(groupers.items, 'prepend', false);
         }
-        
-        me.mixins.sortable.initSortable.call(me);        
-        
-        /**
-         * The collection of {@link Ext.util.Filter Filters} currently applied to this Store
-         * @property filters
-         * @type Ext.util.MixedCollection
-         */
-        filters = me.decodeFilters(me.filters);
-        me.filters = Ext.create('Ext.util.MixedCollection');
-        me.filters.addAll(filters);
     },
 
     /**
-     * Sets the Store's Proxy by string, config object or Proxy instance
-     * @param {String|Object|Ext.data.proxy.Proxy} proxy The new Proxy, which can be either a type string, a configuration object
-     * or an Ext.data.proxy.Proxy instance
-     * @return {Ext.data.proxy.Proxy} The attached Proxy object
+     * @private
+     * Normalizes an array of grouper objects, ensuring that they are all Ext.util.Grouper instances
+     * @param {Object[]} groupers The groupers array
+     * @return {Ext.util.Grouper[]} Array of Ext.util.Grouper objects
      */
-    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    
-                };
+    decodeGroupers: function(groupers) {
+        if (!Ext.isArray(groupers)) {
+            if (groupers === undefined) {
+                groupers = [];
+            } else {
+                groupers = [groupers];
             }
-            Ext.applyIf(proxy, {
-                model: me.model
-            });
-            
-            proxy = Ext.createByAlias('proxy.' + proxy.type, proxy);
         }
-        
-        me.proxy = proxy;
-        
-        return me.proxy;
-    },
 
-    /**
-     * Returns the proxy currently attached to this proxy instance
-     * @return {Ext.data.proxy.Proxy} The Proxy instance
-     */
-    getProxy: function() {
-        return this.proxy;
-    },
+        var length  = groupers.length,
+            Grouper = Ext.util.Grouper,
+            config, i;
 
-    //saves any phantom records
-    create: function(data, options) {
-        var me = this,
-            instance = Ext.ModelManager.create(Ext.applyIf(data, me.modelDefaults), me.model.modelName),
-            operation;
-        
-        options = options || {};
+        for (i = 0; i < length; i++) {
+            config = groupers[i];
 
-        Ext.applyIf(options, {
-            action : 'create',
-            records: [instance]
-        });
+            if (!(config instanceof Grouper)) {
+                if (Ext.isString(config)) {
+                    config = {
+                        property: config
+                    };
+                }
 
-        operation = Ext.create('Ext.data.Operation', options);
+                Ext.applyIf(config, {
+                    root     : 'data',
+                    direction: "ASC"
+                });
 
-        me.proxy.create(operation, me.onProxyWrite, me);
-        
-        return instance;
-    },
+                //support for 3.x style sorters where a function can be defined as 'fn'
+                if (config.fn) {
+                    config.sorterFn = config.fn;
+                }
 
-    read: function() {
-        return this.load.apply(this, arguments);
-    },
+                //support a function to be passed as a sorter definition
+                if (typeof config == 'function') {
+                    config = {
+                        sorterFn: config
+                    };
+                }
 
-    onProxyRead: Ext.emptyFn,
+                groupers[i] = new Grouper(config);
+            }
+        }
 
-    update: function(options) {
+        return groupers;
+    },
+
+    /**
+     * Group data in the store
+     * @param {String/Object[]} groupers Either a string name of one of the fields in this Store's configured {@link Ext.data.Model Model},
+     * or an Array of grouper configurations.
+     * @param {String} direction The overall direction to group the data by. Defaults to "ASC".
+     */
+    group: function(groupers, direction) {
         var me = this,
-            operation;
-        options = options || {};
+            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) {
+            me.load({
+                scope: me,
+                callback: me.fireGroupChange
+            });
+        } else {
+            // need to explicitly force a sort if we have groupers
+            me.sort(null, null, null, hasNew);
+            me.fireGroupChange();
+        }
+    },
 
-        Ext.applyIf(options, {
-            action : 'update',
-            records: me.getUpdatedRecords()
+    /**
+     * Clear any groupers in the store
+     */
+    clearGrouping: function(){
+        var me = this;
+        // Clear any groupers we pushed on to the sorters
+        me.groupers.each(function(grouper){
+            me.sorters.remove(grouper);
         });
+        me.groupers.clear();
+        if (me.remoteGroup) {
+            me.load({
+                scope: me,
+                callback: me.fireGroupChange
+            });
+        } else {
+            me.sort();
+            me.fireEvent('groupchange', me, me.groupers);
+        }
+    },
 
-        operation = Ext.create('Ext.data.Operation', options);
-
-        return me.proxy.update(operation, me.onProxyWrite, me);
+    /**
+     * Checks if the store is currently grouped
+     * @return {Boolean} True if the store is grouped.
+     */
+    isGrouped: function() {
+        return this.groupers.getCount() > 0;
     },
 
     /**
+     * Fires the groupchange event. Abstracted out so we can use it
+     * as a callback
      * @private
-     * Callback for any write Operation over the Proxy. Updates the Store's MixedCollection to reflect
-     * the updates provided by the Proxy
      */
-    onProxyWrite: function(operation) {
-        var me = this,
-            success = operation.wasSuccessful(),
-            records = operation.getRecords();
+    fireGroupChange: function(){
+        this.fireEvent('groupchange', this, this.groupers);
+    },
 
-        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;
-        }
+    /**
+     * Returns an array containing the result of applying grouping to the records in this store. See {@link #groupField},
+     * {@link #groupDir} and {@link #getGroupString}. Example for a store containing records with a color field:
+<pre><code>
+var myStore = Ext.create('Ext.data.Store', {
+    groupField: 'color',
+    groupDir  : 'DESC'
+});
 
-        if (success) {
-            me.fireEvent('write', me, operation);
-            me.fireEvent('datachanged', me);
-        }
-        //this is a callback that would have been passed to the 'create', 'update' or 'destroy' function and is optional
-        Ext.callback(operation.callback, operation.scope || me, [records, operation, success]);
+myStore.getGroups(); //returns:
+[
+    {
+        name: 'yellow',
+        children: [
+            //all records where the color field is 'yellow'
+        ]
     },
+    {
+        name: 'red',
+        children: [
+            //all records where the color field is 'red'
+        ]
+    }
+]
+</code></pre>
+     * @param {String} groupName (Optional) Pass in an optional groupName argument to access a specific group as defined by {@link #getGroupString}
+     * @return {Object/Object[]} The grouped data
+     */
+    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];
 
-    //tells the attached proxy to destroy the given records
-    destroy: function(options) {
-        var me = this,
-            operation;
-            
-        options = options || {};
+            if (group === undefined) {
+                group = {
+                    name: groupStr,
+                    children: []
+                };
 
-        Ext.applyIf(options, {
-            action : 'destroy',
-            records: me.getRemovedRecords()
-        });
+                groups.push(group);
+                pointers[groupStr] = group;
+            }
 
-        operation = Ext.create('Ext.data.Operation', options);
+            group.children.push(record);
+        }
 
-        return me.proxy.destroy(operation, me.onProxyWrite, me);
+        return requestGroupString ? pointers[requestGroupString] : groups;
     },
 
     /**
      * @private
-     * Attached as the 'operationcomplete' event listener to a proxy's Batch object. By default just calls through
-     * to onProxyWrite.
+     * For a given set of records and a Grouper, returns an array of arrays - each of which is the set of records
+     * matching a certain group.
      */
-    onBatchOperationComplete: function(batch, operation) {
-        return this.onProxyWrite(operation);
+    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;
     },
 
     /**
      * @private
-     * Attached as the 'complete' event listener to a proxy's Batch object. Iterates over the batch operations
-     * and updates the Store's internal data MixedCollection.
+     * This is used recursively to gather the records into the configured Groupers. The data MUST have been sorted for
+     * this to work properly (see {@link #getGroupData} and {@link #getGroupsForGrouper}) Most of the work is done by
+     * {@link #getGroupsForGrouper} - this function largely just handles the recursion.
+     * @param {Ext.data.Model[]} records The set or subset of records to group
+     * @param {Number} grouperIndex The grouper index to retrieve
+     * @return {Object[]} The grouped records
      */
-    onBatchComplete: function(batch, operation) {
+    getGroupsForGrouperIndex: function(records, grouperIndex) {
         var me = this,
-            operations = batch.operations,
-            length = operations.length,
+            groupers = me.groupers,
+            grouper = groupers.getAt(grouperIndex),
+            groups = me.getGroupsForGrouper(records, grouper),
+            length = groups.length,
             i;
 
-        me.suspendEvents();
+        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++) {
-            me.onProxyWrite(operations[i]);
+            groups[i].depth = grouperIndex;
         }
 
-        me.resumeEvents();
-
-        me.fireEvent('datachanged', me);
-    },
-
-    onBatchException: function(batch, operation) {
-        // //decide what to do... could continue with the next operation
-        // batch.start();
-        //
-        // //or retry the last operation
-        // batch.retry();
+        return groups;
     },
 
     /**
      * @private
-     * Filter function for new records.
+     * <p>Returns records grouped by the configured {@link #groupers grouper} configuration. Sample return value (in
+     * this case grouping by genre and then author in a fictional books dataset):</p>
+<pre><code>
+[
+    {
+        name: 'Fantasy',
+        depth: 0,
+        records: [
+            //book1, book2, book3, book4
+        ],
+        children: [
+            {
+                name: 'Rowling',
+                depth: 1,
+                records: [
+                    //book1, book2
+                ]
+            },
+            {
+                name: 'Tolkein',
+                depth: 1,
+                records: [
+                    //book3, book4
+                ]
+            }
+        ]
+    }
+]
+</code></pre>
+     * @param {Boolean} sort True to call {@link #sort} before finding groups. Sorting is required to make grouping
+     * function correctly so this should only be set to false if the Store is known to already be sorted correctly
+     * (defaults to true)
+     * @return {Object[]} The group data
      */
-    filterNew: function(item) {
-        // only want phantom records that are valid
-        return item.phantom === true && item.isValid();
-    },
+    getGroupData: function(sort) {
+        var me = this;
+        if (sort !== false) {
+            me.sort();
+        }
 
-    /**
-     * Returns all Model instances that are either currently a phantom (e.g. have no id), or have an ID but have not
-     * yet been saved on this Store (this happens when adding a non-phantom record from another Store into this one)
-     * @return {Array} The Model instances
-     */
-    getNewRecords: function() {
-        return [];
+        return me.getGroupsForGrouperIndex(me.data.items, 0);
     },
 
     /**
-     * Returns all Model instances that have been updated in the Store but not yet synchronized with the Proxy
-     * @return {Array} The updated Model instances
+     * <p>Returns the string to group on for a given model instance. The default implementation of this method returns
+     * the model's {@link #groupField}, but this can be overridden to group by an arbitrary string. For example, to
+     * group by the first letter of a model's 'name' field, use the following code:</p>
+<pre><code>
+Ext.create('Ext.data.Store', {
+    groupDir: 'ASC',
+    getGroupString: function(instance) {
+        return instance.get('name')[0];
+    }
+});
+</code></pre>
+     * @param {Ext.data.Model} instance The model instance
+     * @return {String} The string to compare when forming groups
      */
-    getUpdatedRecords: function() {
-        return [];
+    getGroupString: function(instance) {
+        var group = this.groupers.first();
+        if (group) {
+            return instance.get(group.property);
+        }
+        return '';
     },
-
     /**
-     * @private
-     * Filter function for updated records.
+     * Inserts Model instances into the Store at the given index and fires the {@link #add} event.
+     * See also <code>{@link #add}</code>.
+     * @param {Number} index The start index at which to insert the passed Records.
+     * @param {Ext.data.Model[]} records An Array of Ext.data.Model objects to add to the cache.
      */
-    filterUpdated: function(item) {
-        // only want dirty records, not phantoms that are valid
-        return item.dirty === true && item.phantom !== true && item.isValid();
-    },
+    insert: function(index, records) {
+        var me = this,
+            sync = false,
+            i,
+            record,
+            len;
 
-    /**
-     * Returns any records that have been removed from the store but not yet destroyed on the proxy.
-     * @return {Array} The removed Model instances
-     */
-    getRemovedRecords: function() {
-        return this.removed;
-    },
+        records = [].concat(records);
+        for (i = 0, len = records.length; i < len; i++) {
+            record = me.createModel(records[i]);
+            record.set(me.modelDefaults);
+            // reassign the model in the array in case it wasn't created yet
+            records[i] = record;
 
-    filter: function(filters, value) {
+            me.data.insert(index + i, record);
+            record.join(me);
 
+            sync = sync || record.phantom === true;
+        }
+
+        if (me.snapshot) {
+            me.snapshot.addAll(records);
+        }
+
+        me.fireEvent('add', me, records, index);
+        me.fireEvent('datachanged', me);
+        if (me.autoSync && sync) {
+            me.sync();
+        }
     },
 
     /**
-     * @private
-     * Normalizes an array of filter objects, ensuring that they are all Ext.util.Filter instances
-     * @param {Array} filters The filters array
-     * @return {Array} Array of Ext.util.Filter objects
+     * Adds Model instance to the Store. This method accepts either:
+     *
+     * - An array of Model instances or Model configuration objects.
+     * - Any number of Model instance or Model configuration object arguments.
+     *
+     * The new Model instances will be added at the end of the existing collection.
+     *
+     * Sample usage:
+     *
+     *     myStore.add({some: 'data'}, {some: 'other data'});
+     *
+     * @param {Ext.data.Model[]/Ext.data.Model...} model An array of Model instances
+     * or Model configuration objects, or variable number of Model instance or config arguments.
+     * @return {Ext.data.Model[]} The model instances that were added
      */
-    decodeFilters: function(filters) {
-        if (!Ext.isArray(filters)) {
-            if (filters === undefined) {
-                filters = [];
-            } else {
-                filters = [filters];
-            }
+    add: function(records) {
+        //accept both a single-argument array of records, or any number of record arguments
+        if (!Ext.isArray(records)) {
+            records = Array.prototype.slice.apply(arguments);
         }
 
-        var length = filters.length,
-            Filter = Ext.util.Filter,
-            config, i;
-
-        for (i = 0; i < length; i++) {
-            config = filters[i];
+        var me = this,
+            i = 0,
+            length = records.length,
+            record;
 
-            if (!(config instanceof Filter)) {
-                Ext.apply(config, {
-                    root: 'data'
-                });
+        for (; i < length; i++) {
+            record = me.createModel(records[i]);
+            // reassign the model in the array in case it wasn't created yet
+            records[i] = record;
+        }
 
-                //support for 3.x style filters where a function can be defined as 'fn'
-                if (config.fn) {
-                    config.filterFn = config.fn;
-                }
+        me.insert(me.data.length, records);
 
-                //support a function to be passed as a filter definition
-                if (typeof config == 'function') {
-                    config = {
-                        filterFn: config
-                    };
-                }
+        return records;
+    },
 
-                filters[i] = new Filter(config);
-            }
+    /**
+     * Converts a literal to a model, if it's not a model already
+     * @private
+     * @param record {Ext.data.Model/Object} The record to create
+     * @return {Ext.data.Model}
+     */
+    createModel: function(record) {
+        if (!record.isModel) {
+            record = Ext.ModelManager.create(record, this.model);
         }
 
-        return filters;
+        return record;
     },
 
-    clearFilter: function(supressEvent) {
-
+    /**
+     * Calls the specified function for each of the {@link Ext.data.Model Records} in the cache.
+     * @param {Function} fn The function to call. The {@link Ext.data.Model Record} is passed as the first parameter.
+     * Returning <tt>false</tt> aborts and exits the iteration.
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed.
+     * Defaults to the current {@link Ext.data.Model Record} in the iteration.
+     */
+    each: function(fn, scope) {
+        this.data.each(fn, scope);
     },
 
-    isFiltered: function() {
+    /**
+     * Removes the given record from the Store, firing the 'remove' event for each instance that is removed, plus a single
+     * 'datachanged' event after removal.
+     * @param {Ext.data.Model/Ext.data.Model[]} records The Ext.data.Model instance or array of instances to remove
+     */
+    remove: function(records, /* private */ isMove) {
+        if (!Ext.isArray(records)) {
+            records = [records];
+        }
 
-    },
+        /*
+         * Pass the isMove parameter if we know we're going to be re-inserting this record
+         */
+        isMove = isMove === true;
+        var me = this,
+            sync = false,
+            i = 0,
+            length = records.length,
+            isPhantom,
+            index,
+            record;
 
-    filterBy: function(fn, scope) {
+        for (; i < length; i++) {
+            record = records[i];
+            index = me.data.indexOf(record);
 
-    },
-    
-    /**
-     * Synchronizes the Store with its Proxy. This asks the Proxy to batch together any new, updated
-     * and deleted records in the store, updating the Store's internal representation of the records
-     * as each operation completes.
-     */
-    sync: function() {
-        var me        = this,
-            options   = {},
-            toCreate  = me.getNewRecords(),
-            toUpdate  = me.getUpdatedRecords(),
-            toDestroy = me.getRemovedRecords(),
-            needsSync = false;
+            if (me.snapshot) {
+                me.snapshot.remove(record);
+            }
 
-        if (toCreate.length > 0) {
-            options.create = toCreate;
-            needsSync = true;
-        }
+            if (index > -1) {
+                isPhantom = record.phantom === true;
+                if (!isMove && !isPhantom) {
+                    // don't push phantom records onto removed
+                    me.removed.push(record);
+                }
 
-        if (toUpdate.length > 0) {
-            options.update = toUpdate;
-            needsSync = true;
-        }
+                record.unjoin(me);
+                me.data.remove(record);
+                sync = sync || !isPhantom;
 
-        if (toDestroy.length > 0) {
-            options.destroy = toDestroy;
-            needsSync = true;
+                me.fireEvent('remove', me, record, index);
+            }
         }
 
-        if (needsSync && me.fireEvent('beforesync', options) !== false) {
-            me.proxy.batch(options, me.getBatchListeners());
+        me.fireEvent('datachanged', me);
+        if (!isMove && me.autoSync && sync) {
+            me.sync();
         }
     },
 
-
     /**
-     * @private
-     * Returns an object which is passed in as the listeners argument to proxy.batch inside this.sync.
-     * This is broken out into a separate function to allow for customisation of the listeners
-     * @return {Object} The listeners object
+     * Removes the model instance at the given index
+     * @param {Number} index The record index
      */
-    getBatchListeners: function() {
-        var me = this,
-            listeners = {
-                scope: me,
-                exception: me.onBatchException
-            };
+    removeAt: function(index) {
+        var record = this.getAt(index);
 
-        if (me.batchUpdateMode == 'operation') {
-            listeners.operationcomplete = me.onBatchOperationComplete;
-        } else {
-            listeners.complete = me.onBatchComplete;
+        if (record) {
+            this.remove(record);
         }
-
-        return listeners;
-    },
-
-    //deprecated, will be removed in 5.0
-    save: function() {
-        return this.sync.apply(this, arguments);
     },
 
     /**
-     * Loads the Store using its configured {@link #proxy}.
-     * @param {Object} options Optional config object. This is passed into the {@link Ext.data.Operation Operation}
-     * object that is created and then sent to the proxy's {@link Ext.data.proxy.Proxy#read} function
+     * <p>Loads data into the Store via the configured {@link #proxy}. This uses the Proxy to make an
+     * asynchronous call to whatever storage backend the Proxy uses, automatically adding the retrieved
+     * instances into the Store and calling an optional callback if required. Example usage:</p>
+     *
+<pre><code>
+store.load({
+    scope   : this,
+    callback: function(records, operation, success) {
+        //the {@link Ext.data.Operation operation} object contains all of the details of the load operation
+        console.log(records);
+    }
+});
+</code></pre>
+     *
+     * <p>If the callback scope does not need to be set, a function can simply be passed:</p>
+     *
+<pre><code>
+store.load(function(records, operation, success) {
+    console.log('loaded records');
+});
+</code></pre>
+     *
+     * @param {Object/Function} options (Optional) config object, passed into the Ext.data.Operation object before loading.
      */
     load: function(options) {
-        var me = this,
-            operation;
+        var me = this;
 
         options = options || {};
 
+        if (Ext.isFunction(options)) {
+            options = {
+                callback: options
+            };
+        }
+
         Ext.applyIf(options, {
-            action : 'read',
-            filters: me.filters.items,
-            sorters: me.getSorters()
+            groupers: me.groupers.items,
+            page: me.currentPage,
+            start: (me.currentPage - 1) * me.pageSize,
+            limit: me.pageSize,
+            addRecords: false
         });
-        
-        operation = Ext.create('Ext.data.Operation', options);
 
-        if (me.fireEvent('beforeload', me, operation) !== false) {
-            me.loading = true;
-            me.proxy.read(operation, me.onProxyLoad, me);
-        }
-        
-        return me;
+        return me.callParent([options]);
     },
 
     /**
      * @private
-     * A model instance should call this method on the Store it has been {@link Ext.data.Model#join joined} to.
-     * @param {Ext.data.Model} record The model instance that was edited
+     * Called internally when a Proxy has completed a load request
      */
-    afterEdit : function(record) {
-        var me = this;
-        
-        if (me.autoSync) {
-            me.sync();
+    onProxyLoad: function(operation) {
+        var me = this,
+            resultSet = operation.getResultSet(),
+            records = operation.getRecords(),
+            successful = operation.wasSuccessful();
+
+        if (resultSet) {
+            me.totalCount = resultSet.total;
         }
-        
-        me.fireEvent('update', me, record, Ext.data.Model.EDIT);
+
+        if (successful) {
+            me.loadRecords(records, operation);
+        }
+
+        me.loading = false;
+        me.fireEvent('load', me, records, successful);
+
+        //TODO: deprecate this event, it should always have been 'load' instead. 'load' is now documented, 'read' is not.
+        //People are definitely using this so can't deprecate safely until 2.x
+        me.fireEvent('read', me, records, operation.wasSuccessful());
+
+        //this is a callback that would have been passed to the 'read' function and is optional
+        Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
     },
 
     /**
+     * Create any new records when a write is returned from the server.
      * @private
-     * A model instance should call this method on the Store it has been {@link Ext.data.Model#join joined} to..
-     * @param {Ext.data.Model} record The model instance that was edited
+     * @param {Ext.data.Model[]} records The array of new records
+     * @param {Ext.data.Operation} operation The operation that just completed
+     * @param {Boolean} success True if the operation was successful
      */
-    afterReject : function(record) {
-        this.fireEvent('update', this, record, Ext.data.Model.REJECT);
+    onCreateRecords: function(records, operation, success) {
+        if (success) {
+            var i = 0,
+                data = this.data,
+                snapshot = this.snapshot,
+                length = records.length,
+                originalRecords = operation.records,
+                record,
+                original,
+                index;
+
+            /*
+             * Loop over each record returned from the server. Assume they are
+             * returned in order of how they were sent. If we find a matching
+             * record, replace it with the newly created one.
+             */
+            for (; i < length; ++i) {
+                record = records[i];
+                original = originalRecords[i];
+                if (original) {
+                    index = data.indexOf(original);
+                    if (index > -1) {
+                        data.removeAt(index);
+                        data.insert(index, record);
+                    }
+                    if (snapshot) {
+                        index = snapshot.indexOf(original);
+                        if (index > -1) {
+                            snapshot.removeAt(index);
+                            snapshot.insert(index, record);
+                        }
+                    }
+                    record.phantom = false;
+                    record.join(this);
+                }
+            }
+        }
     },
 
     /**
+     * Update any records when a write is returned from the server.
      * @private
-     * A model instance should call this method on the Store it has been {@link Ext.data.Model#join joined} to.
-     * @param {Ext.data.Model} record The model instance that was edited
+     * @param {Ext.data.Model[]} records The array of updated records
+     * @param {Ext.data.Operation} operation The operation that just completed
+     * @param {Boolean} success True if the operation was successful
      */
-    afterCommit : function(record) {
-        this.fireEvent('update', this, record, Ext.data.Model.COMMIT);
-    },
-
-    clearData: Ext.emptyFn,
-
-    destroyStore: function() {
-        var me = this;
-        
-        if (!me.isDestroyed) {
-            if (me.storeId) {
-                Ext.data.StoreManager.unregister(me);
-            }
-            me.clearData();
-            me.data = null;
-            me.tree = null;
-            // Ext.destroy(this.proxy);
-            me.reader = me.writer = null;
-            me.clearListeners();
-            me.isDestroyed = true;
+    onUpdateRecords: function(records, operation, success){
+        if (success) {
+            var i = 0,
+                length = records.length,
+                data = this.data,
+                snapshot = this.snapshot,
+                record;
 
-            if (me.implicitModel) {
-                Ext.destroy(me.model);
+            for (; i < length; ++i) {
+                record = records[i];
+                data.replace(record);
+                if (snapshot) {
+                    snapshot.replace(record);
+                }
+                record.join(this);
             }
         }
     },
-    
-    doSort: function(sorterFn) {
-        var me = this;
-        if (me.remoteSort) {
-            //the load function will pick up the new sorters and request the sorted data from the proxy
-            me.load();
-        } else {
-            me.data.sortBy(sorterFn);
-            me.fireEvent('datachanged', me);
-        }
-    },
-
-    getCount: Ext.emptyFn,
-
-    getById: Ext.emptyFn,
-    
-    /**
-     * Removes all records from the store. This method does a "fast remove",
-     * individual remove events are not called. The {@link #clear} event is
-     * fired upon completion.
-     * @method
-     */
-    removeAll: Ext.emptyFn,
-    // individual substores should implement a "fast" remove
-    // and fire a clear event afterwards
 
     /**
-     * Returns true if the Store is currently performing a load operation
-     * @return {Boolean} True if the Store is currently loading
+     * Remove any records when a write is returned from the server.
+     * @private
+     * @param {Ext.data.Model[]} records The array of removed records
+     * @param {Ext.data.Operation} operation The operation that just completed
+     * @param {Boolean} success True if the operation was successful
      */
-    isLoading: function() {
-        return this.loading;
-     }
-});
-
-/**
- * @class Ext.util.Grouper
- * @extends Ext.util.Sorter
-
-Represents a single grouper that can be applied to a Store. The grouper works
-in the same fashion as the {@link Ext.util.Sorter}.
-
- * @markdown
- */
-Ext.define('Ext.util.Grouper', {
+    onDestroyRecords: function(records, operation, success){
+        if (success) {
+            var me = this,
+                i = 0,
+                length = records.length,
+                data = me.data,
+                snapshot = me.snapshot,
+                record;
 
-    /* Begin Definitions */
+            for (; i < length; ++i) {
+                record = records[i];
+                record.unjoin(me);
+                data.remove(record);
+                if (snapshot) {
+                    snapshot.remove(record);
+                }
+            }
+            me.removed = [];
+        }
+    },
 
-    extend: 'Ext.util.Sorter',
+    //inherit docs
+    getNewRecords: function() {
+        return this.data.filterBy(this.filterNew).items;
+    },
 
-    /* End Definitions */
+    //inherit docs
+    getUpdatedRecords: function() {
+        return this.data.filterBy(this.filterUpdated).items;
+    },
 
     /**
-     * Returns the value for grouping to be used.
-     * @param {Ext.data.Model} instance The Model instance
-     * @return {String} The group string for this model
+     * Filters the loaded set of records by a given set of filters.
+     *
+     * Filtering by single field:
+     *
+     *     store.filter("email", /\.com$/);
+     *
+     * Using multiple filters:
+     *
+     *     store.filter([
+     *         {property: "email", value: /\.com$/},
+     *         {filterFn: function(item) { return item.get("age") > 10; }}
+     *     ]);
+     *
+     * Using Ext.util.Filter instances instead of config objects
+     * (note that we need to specify the {@link Ext.util.Filter#root root} config option in this case):
+     *
+     *     store.filter([
+     *         Ext.create('Ext.util.Filter', {property: "email", value: /\.com$/, root: 'data'}),
+     *         Ext.create('Ext.util.Filter', {filterFn: function(item) { return item.get("age") > 10; }, root: 'data'})
+     *     ]);
+     *
+     * @param {Object[]/Ext.util.Filter[]/String} filters The set of filters to apply to the data. These are stored internally on the store,
+     * but the filtering itself is done on the Store's {@link Ext.util.MixedCollection MixedCollection}. See
+     * MixedCollection's {@link Ext.util.MixedCollection#filter filter} method for filter syntax. Alternatively,
+     * pass in a property string
+     * @param {String} value (optional) value to filter by (only if using a property string as the first argument)
      */
-    getGroupString: function(instance) {
-        return instance.get(this.property);
-    }
-});
-/**
- * @author Ed Spencer
- * @class Ext.data.Store
- * @extends Ext.data.AbstractStore
- *
- * <p>The Store class encapsulates a client side cache of {@link Ext.data.Model Model} objects. Stores load
- * data via a {@link Ext.data.proxy.Proxy Proxy}, and also provide functions for {@link #sort sorting},
- * {@link #filter filtering} and querying the {@link Ext.data.Model model} instances contained within it.</p>
- *
- * <p>Creating a Store is easy - we just tell it the Model and the Proxy to use to load and save its data:</p>
- *
-<pre><code>
-// Set up a {@link Ext.data.Model model} to use in our Store
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'firstName', type: 'string'},
-        {name: 'lastName',  type: 'string'},
-        {name: 'age',       type: 'int'},
-        {name: 'eyeColor',  type: 'string'}
-    ]
-});
-
-var myStore = new Ext.data.Store({
-    model: 'User',
-    proxy: {
-        type: 'ajax',
-        url : '/users.json',
-        reader: {
-            type: 'json',
-            root: 'users'
+    filter: function(filters, value) {
+        if (Ext.isString(filters)) {
+            filters = {
+                property: filters,
+                value: value
+            };
         }
-    },
-    autoLoad: true
-});
-</code></pre>
 
- * <p>In the example above we configured an AJAX proxy to load data from the url '/users.json'. We told our Proxy
- * to use a {@link Ext.data.reader.Json JsonReader} to parse the response from the server into Model object -
- * {@link Ext.data.reader.Json see the docs on JsonReader} for details.</p>
- *
- * <p><u>Inline data</u></p>
- *
- * <p>Stores can also load data inline. Internally, Store converts each of the objects we pass in as {@link #data}
- * into Model instances:</p>
- *
-<pre><code>
-new Ext.data.Store({
-    model: 'User',
-    data : [
-        {firstName: 'Ed',    lastName: 'Spencer'},
-        {firstName: 'Tommy', lastName: 'Maintz'},
-        {firstName: 'Aaron', lastName: 'Conran'},
-        {firstName: 'Jamie', lastName: 'Avins'}
-    ]
-});
-</code></pre>
- *
- * <p>Loading inline data using the method above is great if the data is in the correct format already (e.g. it doesn't need
- * to be processed by a {@link Ext.data.reader.Reader reader}). If your inline data requires processing to decode the data structure,
- * use a {@link Ext.data.proxy.Memory MemoryProxy} instead (see the {@link Ext.data.proxy.Memory MemoryProxy} docs for an example).</p>
- *
- * <p>Additional data can also be loaded locally using {@link #add}.</p>
- *
- * <p><u>Loading Nested Data</u></p>
- *
- * <p>Applications often need to load sets of associated data - for example a CRM system might load a User and her Orders.
- * Instead of issuing an AJAX request for the User and a series of additional AJAX requests for each Order, we can load a nested dataset
- * and allow the Reader to automatically populate the associated models. Below is a brief example, see the {@link Ext.data.reader.Reader} intro
- * docs for a full explanation:</p>
- *
-<pre><code>
-var store = new Ext.data.Store({
-    autoLoad: true,
-    model: "User",
-    proxy: {
-        type: 'ajax',
-        url : 'users.json',
-        reader: {
-            type: 'json',
-            root: 'users'
-        }
-    }
-});
-</code></pre>
- *
- * <p>Which would consume a response like this:</p>
- *
-<pre><code>
-{
-    "users": [
-        {
-            "id": 1,
-            "name": "Ed",
-            "orders": [
-                {
-                    "id": 10,
-                    "total": 10.76,
-                    "status": "invoiced"
-                },
-                {
-                    "id": 11,
-                    "total": 13.45,
-                    "status": "shipped"
-                }
-            ]
-        }
-    ]
-}
-</code></pre>
- *
- * <p>See the {@link Ext.data.reader.Reader} intro docs for a full explanation.</p>
- *
- * <p><u>Filtering and Sorting</u></p>
- *
- * <p>Stores can be sorted and filtered - in both cases either remotely or locally. The {@link #sorters} and {@link #filters} are
- * held inside {@link Ext.util.MixedCollection MixedCollection} instances to make them easy to manage. Usually it is sufficient to
- * either just specify sorters and filters in the Store configuration or call {@link #sort} or {@link #filter}:
- *
-<pre><code>
-var store = new Ext.data.Store({
-    model: 'User',
-    sorters: [
-        {
-            property : 'age',
-            direction: 'DESC'
-        },
-        {
-            property : 'firstName',
-            direction: 'ASC'
-        }
-    ],
+        var me = this,
+            decoded = me.decodeFilters(filters),
+            i = 0,
+            doLocalSort = me.sortOnFilter && !me.remoteSort,
+            length = decoded.length;
 
-    filters: [
-        {
-            property: 'firstName',
-            value   : /Ed/
+        for (; i < length; i++) {
+            me.filters.replace(decoded[i]);
         }
-    ]
-});
-</code></pre>
- *
- * <p>The new Store will keep the configured sorters and filters in the MixedCollection instances mentioned above. By default, sorting
- * and filtering are both performed locally by the Store - see {@link #remoteSort} and {@link #remoteFilter} to allow the server to
- * perform these operations instead.</p>
- *
- * <p>Filtering and sorting after the Store has been instantiated is also easy. Calling {@link #filter} adds another filter to the Store
- * and automatically filters the dataset (calling {@link #filter} with no arguments simply re-applies all existing filters). Note that by
- * default {@link #sortOnFilter} is set to true, which means that your sorters are automatically reapplied if using local sorting.</p>
- *
-<pre><code>
-store.filter('eyeColor', 'Brown');
-</code></pre>
- *
- * <p>Change the sorting at any time by calling {@link #sort}:</p>
- *
-<pre><code>
-store.sort('height', 'ASC');
-</code></pre>
- *
- * <p>Note that all existing sorters will be removed in favor of the new sorter data (if {@link #sort} is called with no arguments,
- * the existing sorters are just reapplied instead of being removed). To keep existing sorters and add new ones, just add them
- * to the MixedCollection:</p>
- *
-<pre><code>
-store.sorters.add(new Ext.util.Sorter({
-    property : 'shoeSize',
-    direction: 'ASC'
-}));
-
-store.sort();
-</code></pre>
- *
- * <p><u>Registering with StoreManager</u></p>
- *
- * <p>Any Store that is instantiated with a {@link #storeId} will automatically be registed with the {@link Ext.data.StoreManager StoreManager}.
- * This makes it easy to reuse the same store in multiple views:</p>
- *
- <pre><code>
-//this store can be used several times
-new Ext.data.Store({
-    model: 'User',
-    storeId: 'usersStore'
-});
 
-new Ext.List({
-    store: 'usersStore',
+        if (me.remoteFilter) {
+            //the load function will pick up the new filters and request the filtered data from the proxy
+            me.load();
+        } else {
+            /**
+             * A pristine (unfiltered) collection of the records in this store. This is used to reinstate
+             * records when a filter is removed or changed
+             * @property snapshot
+             * @type Ext.util.MixedCollection
+             */
+            if (me.filters.getCount()) {
+                me.snapshot = me.snapshot || me.data.clone();
+                me.data = me.data.filter(me.filters.items);
 
-    //other config goes here
-});
+                if (doLocalSort) {
+                    me.sort();
+                }
+                // fire datachanged event if it hasn't already been fired by doSort
+                if (!doLocalSort || me.sorters.length < 1) {
+                    me.fireEvent('datachanged', me);
+                }
+            }
+        }
+    },
 
-new Ext.view.View({
-    store: 'usersStore',
+    /**
+     * Revert to a view of the Record cache with no filtering applied.
+     * @param {Boolean} suppressEvent If <tt>true</tt> the filter is cleared silently without firing the
+     * {@link #datachanged} event.
+     */
+    clearFilter: function(suppressEvent) {
+        var me = this;
 
-    //other config goes here
-});
-</code></pre>
- *
- * <p><u>Further Reading</u></p>
- *
- * <p>Stores are backed up by an ecosystem of classes that enables their operation. To gain a full understanding of these
- * pieces and how they fit together, see:</p>
- *
- * <ul style="list-style-type: disc; padding-left: 25px">
- * <li>{@link Ext.data.proxy.Proxy Proxy} - overview of what Proxies are and how they are used</li>
- * <li>{@link Ext.data.Model Model} - the core class in the data package</li>
- * <li>{@link Ext.data.reader.Reader Reader} - used by any subclass of {@link Ext.data.proxy.Server ServerProxy} to read a response</li>
- * </ul>
- *
- */
-Ext.define('Ext.data.Store', {
-    extend: 'Ext.data.AbstractStore',
+        me.filters.clear();
 
-    alias: 'store.store',
+        if (me.remoteFilter) {
+            me.load();
+        } else if (me.isFiltered()) {
+            me.data = me.snapshot.clone();
+            delete me.snapshot;
 
-    requires: ['Ext.ModelManager', 'Ext.data.Model', 'Ext.util.Grouper'],
-    uses: ['Ext.data.proxy.Memory'],
+            if (suppressEvent !== true) {
+                me.fireEvent('datachanged', me);
+            }
+        }
+    },
 
     /**
-     * @cfg {Boolean} remoteSort
-     * True to defer any sorting operation to the server. If false, sorting is done locally on the client. Defaults to <tt>false</tt>.
+     * Returns true if this store is currently filtered
+     * @return {Boolean}
      */
-    remoteSort: false,
+    isFiltered: function() {
+        var snapshot = this.snapshot;
+        return !! snapshot && snapshot !== this.data;
+    },
 
     /**
-     * @cfg {Boolean} remoteFilter
-     * True to defer any filtering operation to the server. If false, filtering is done locally on the client. Defaults to <tt>false</tt>.
-     */
-    remoteFilter: false,
-    
-    /**
-     * @cfg {Boolean} remoteGroup
-     * True if the grouping should apply on the server side, false if it is local only (defaults to false).  If the
-     * grouping is local, it can be applied immediately to the data.  If it is remote, then it will simply act as a
-     * helper, automatically sending the grouping information to the server.
+     * Filter by a function. The specified function will be called for each
+     * Record in this Store. If the function returns <tt>true</tt> the Record is included,
+     * otherwise it is filtered out.
+     * @param {Function} fn The function to be called. It will be passed the following parameters:<ul>
+     * <li><b>record</b> : Ext.data.Model<p class="sub-desc">The {@link Ext.data.Model record}
+     * to test for filtering. Access field values using {@link Ext.data.Model#get}.</p></li>
+     * <li><b>id</b> : Object<p class="sub-desc">The ID of the Record passed.</p></li>
+     * </ul>
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this Store.
      */
-    remoteGroup : false,
+    filterBy: function(fn, scope) {
+        var me = this;
 
-    /**
-     * @cfg {String/Ext.data.proxy.Proxy/Object} proxy The Proxy to use for this Store. This can be either a string, a config
-     * object or a Proxy instance - see {@link #setProxy} for details.
-     */
+        me.snapshot = me.snapshot || me.data.clone();
+        me.data = me.queryBy(fn, scope || me);
+        me.fireEvent('datachanged', me);
+    },
 
     /**
-     * @cfg {Array} data Optional array of Model instances or data objects to load locally. See "Inline data" above for details.
-     */
+     * Query the cached records in this Store using a filtering function. The specified function
+     * will be called with each record in this Store. If the function returns <tt>true</tt> the record is
+     * included in the results.
+     * @param {Function} fn The function to be called. It will be passed the following parameters:<ul>
+     * <li><b>record</b> : Ext.data.Model<p class="sub-desc">The {@link Ext.data.Model record}
+     * to test for filtering. Access field values using {@link Ext.data.Model#get}.</p></li>
+     * <li><b>id</b> : Object<p class="sub-desc">The ID of the Record passed.</p></li>
+     * </ul>
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this Store.
+     * @return {Ext.util.MixedCollection} Returns an Ext.util.MixedCollection of the matched records
+     **/
+    queryBy: function(fn, scope) {
+        var me = this,
+        data = me.snapshot || me.data;
+        return data.filterBy(fn, scope || me);
+    },
 
     /**
-     * @cfg {String} model The {@link Ext.data.Model} associated with this store
+     * Loads an array of data straight into the Store.
+     * 
+     * Using this method is great if the data is in the correct format already (e.g. it doesn't need to be
+     * processed by a reader). If your data requires processing to decode the data structure, use a
+     * {@link Ext.data.proxy.Memory MemoryProxy} instead.
+     * 
+     * @param {Ext.data.Model[]/Object[]} data Array of data to load. Any non-model instances will be cast
+     * into model instances.
+     * @param {Boolean} [append=false] True to add the records to the existing records in the store, false
+     * to remove the old ones first.
      */
+    loadData: function(data, append) {
+        var model = this.model,
+            length = data.length,
+            newData = [],
+            i,
+            record;
 
-    /**
-     * The (optional) field by which to group data in the store. Internally, grouping is very similar to sorting - the
-     * groupField and {@link #groupDir} are injected as the first sorter (see {@link #sort}). Stores support a single
-     * level of grouping, and groups can be fetched via the {@link #getGroups} method.
-     * @property groupField
-     * @type String
-     */
-    groupField: undefined,
+        //make sure each data element is an Ext.data.Model instance
+        for (i = 0; i < length; i++) {
+            record = data[i];
 
-    /**
-     * The direction in which sorting should be applied when grouping. Defaults to "ASC" - the other supported value is "DESC"
-     * @property groupDir
-     * @type String
-     */
-    groupDir: "ASC",
+            if (!(record instanceof Ext.data.Model)) {
+                record = Ext.ModelManager.create(record, model);
+            }
+            newData.push(record);
+        }
 
-    /**
-     * @cfg {Number} pageSize
-     * The number of records considered to form a 'page'. This is used to power the built-in
-     * paging using the nextPage and previousPage functions. Defaults to 25.
-     */
-    pageSize: 25,
+        this.loadRecords(newData, {addRecords: append});
+    },
 
-    /**
-     * The page that the Store has most recently loaded (see {@link #loadPage})
-     * @property currentPage
-     * @type Number
-     */
-    currentPage: 1,
 
     /**
-     * @cfg {Boolean} clearOnPageLoad True to empty the store when loading another page via {@link #loadPage},
-     * {@link #nextPage} or {@link #previousPage} (defaults to true). Setting to false keeps existing records, allowing
-     * large data sets to be loaded one page at a time but rendered all together.
-     */
-    clearOnPageLoad: true,
+     * Loads data via the bound Proxy's reader
+     *
+     * Use this method if you are attempting to load data and want to utilize the configured data reader.
+     *
+     * @param {Object[]} data The full JSON object you'd like to load into the Data store.
+     * @param {Boolean} [append=false] True to add the records to the existing records in the store, false
+     * to remove the old ones first.
+     */
+    loadRawData : function(data, append) {
+         var me      = this,
+             result  = me.proxy.reader.read(data),
+             records = result.records;
+
+         if (result.success) {
+             me.loadRecords(records, { addRecords: append });
+             me.fireEvent('load', me, records, true);
+         }
+     },
 
-    /**
-     * True if the Store is currently loading via its Proxy
-     * @property loading
-     * @type Boolean
-     * @private
-     */
-    loading: false,
 
     /**
-     * @cfg {Boolean} sortOnFilter For local filtering only, causes {@link #sort} to be called whenever {@link #filter} is called,
-     * causing the sorters to be reapplied after filtering. Defaults to true
-     */
-    sortOnFilter: true,
-    
-    /**
-     * @cfg {Boolean} buffered
-     * Allow the store to buffer and pre-fetch pages of records. This is to be used in conjunction with a view will
-     * tell the store to pre-fetch records ahead of a time.
-     */
-    buffered: false,
-    
-    /**
-     * @cfg {Number} purgePageCount 
-     * The number of pages to keep in the cache before purging additional records. A value of 0 indicates to never purge the prefetched data.
-     * This option is only relevant when the {@link #buffered} option is set to true.
+     * Loads an array of {@link Ext.data.Model model} instances into the store, fires the datachanged event. This should only usually
+     * be called internally when loading from the {@link Ext.data.proxy.Proxy Proxy}, when adding records manually use {@link #add} instead
+     * @param {Ext.data.Model[]} records The array of records to load
+     * @param {Object} options {addRecords: true} to add these records to the existing records, false to remove the Store's existing records first
      */
-    purgePageCount: 5,
+    loadRecords: function(records, options) {
+        var me     = this,
+            i      = 0,
+            length = records.length;
 
-    isStore: true,
+        options = options || {};
 
-    /**
-     * Creates the store.
-     * @param {Object} config (optional) Config object
-     */
-    constructor: function(config) {
-        config = config || {};
 
-        var me = this,
-            groupers = config.groupers || me.groupers,
-            groupField = config.groupField || me.groupField,
-            proxy,
-            data;
-            
-        if (config.buffered || me.buffered) {
-            me.prefetchData = Ext.create('Ext.util.MixedCollection', false, function(record) {
-                return record.index;
-            });
-            me.pendingRequests = [];
-            me.pagesRequested = [];
-            
-            me.sortOnLoad = false;
-            me.filterOnLoad = false;
+        if (!options.addRecords) {
+            delete me.snapshot;
+            me.clearData();
         }
-            
-        me.addEvents(
-            /**
-             * @event beforeprefetch
-             * Fires before a prefetch occurs. Return false to cancel.
-             * @param {Ext.data.store} this
-             * @param {Ext.data.Operation} operation The associated operation
-             */
-            'beforeprefetch',
-            /**
-             * @event groupchange
-             * Fired whenever the grouping in the grid changes
-             * @param {Ext.data.Store} store The store
-             * @param {Array} groupers The array of grouper objects
-             */
-            'groupchange',
-            /**
-             * @event load
-             * Fires whenever records have been prefetched
-             * @param {Ext.data.store} this
-             * @param {Array} records An array of records
-             * @param {Boolean} successful True if the operation was successful.
-             * @param {Ext.data.Operation} operation The associated operation
-             */
-            'prefetch'
-        );
-        data = config.data || me.data;
 
-        /**
-         * The MixedCollection that holds this store's local cache of records
-         * @property data
-         * @type Ext.util.MixedCollection
-         */
-        me.data = Ext.create('Ext.util.MixedCollection', false, function(record) {
-            return record.internalId;
-        });
+        me.data.addAll(records);
 
-        if (data) {
-            me.inlineData = data;
-            delete config.data;
-        }
-        
-        if (!groupers && groupField) {
-            groupers = [{
-                property : groupField,
-                direction: config.groupDir || me.groupDir
-            }];
-        }
-        delete config.groupers;
-        
-        /**
-         * The collection of {@link Ext.util.Grouper Groupers} currently applied to this Store
-         * @property groupers
-         * @type Ext.util.MixedCollection
-         */
-        me.groupers = Ext.create('Ext.util.MixedCollection');
-        me.groupers.addAll(me.decodeGroupers(groupers));
+        //FIXME: this is not a good solution. Ed Spencer is totally responsible for this and should be forced to fix it immediately.
+        for (; i < length; i++) {
+            if (options.start !== undefined) {
+                records[i].index = options.start + i;
 
-        this.callParent([config]);
-        // don't use *config* anymore from here on... use *me* instead...
-        
-        if (me.groupers.items.length) {
-            me.sort(me.groupers.items, 'prepend', false);
+            }
+            records[i].join(me);
         }
 
-        proxy = me.proxy;
-        data = me.inlineData;
+        /*
+         * this rather inelegant suspension and resumption of events is required because both the filter and sort functions
+         * fire an additional datachanged event, which is not wanted. Ideally we would do this a different way. The first
+         * datachanged event is fired by the call to this.add, above.
+         */
+        me.suspendEvents();
 
-        if (data) {
-            if (proxy instanceof Ext.data.proxy.Memory) {
-                proxy.data = data;
-                me.read();
-            } else {
-                me.add.apply(me, data);
-            }
+        if (me.filterOnLoad && !me.remoteFilter) {
+            me.filter();
+        }
 
+        if (me.sortOnLoad && !me.remoteSort) {
             me.sort();
-            delete me.inlineData;
-        } else if (me.autoLoad) {
-            Ext.defer(me.load, 10, me, [typeof me.autoLoad === 'object' ? me.autoLoad: undefined]);
-            // Remove the defer call, we may need reinstate this at some point, but currently it's not obvious why it's here.
-            // this.load(typeof this.autoLoad == 'object' ? this.autoLoad : undefined);
         }
+
+        me.resumeEvents();
+        me.fireEvent('datachanged', me, records);
     },
-    
-    onBeforeSort: function() {
-        this.sort(this.groupers.items, 'prepend', false);
-    },
-    
+
+    // PAGING METHODS
     /**
-     * @private
-     * Normalizes an array of grouper objects, ensuring that they are all Ext.util.Grouper instances
-     * @param {Array} groupers The groupers array
-     * @return {Array} Array of Ext.util.Grouper objects
+     * Loads a given 'page' of data by setting the start and limit values appropriately. Internally this just causes a normal
+     * load operation, passing in calculated 'start' and 'limit' params
+     * @param {Number} page The number of the page to load
+     * @param {Object} options See options for {@link #load}
      */
-    decodeGroupers: function(groupers) {
-        if (!Ext.isArray(groupers)) {
-            if (groupers === undefined) {
-                groupers = [];
-            } else {
-                groupers = [groupers];
-            }
-        }
-
-        var length  = groupers.length,
-            Grouper = Ext.util.Grouper,
-            config, i;
+    loadPage: function(page, options) {
+        var me = this;
+        options = Ext.apply({}, options);
 
-        for (i = 0; i < length; i++) {
-            config = groupers[i];
+        me.currentPage = page;
 
-            if (!(config instanceof Grouper)) {
-                if (Ext.isString(config)) {
-                    config = {
-                        property: config
-                    };
-                }
-                
-                Ext.applyIf(config, {
-                    root     : 'data',
-                    direction: "ASC"
-                });
+        me.read(Ext.applyIf(options, {
+            page: page,
+            start: (page - 1) * me.pageSize,
+            limit: me.pageSize,
+            addRecords: !me.clearOnPageLoad
+        }));
+    },
 
-                //support for 3.x style sorters where a function can be defined as 'fn'
-                if (config.fn) {
-                    config.sorterFn = config.fn;
-                }
+    /**
+     * Loads the next 'page' in the current data set
+     * @param {Object} options See options for {@link #load}
+     */
+    nextPage: function(options) {
+        this.loadPage(this.currentPage + 1, options);
+    },
 
-                //support a function to be passed as a sorter definition
-                if (typeof config == 'function') {
-                    config = {
-                        sorterFn: config
-                    };
-                }
+    /**
+     * Loads the previous 'page' in the current data set
+     * @param {Object} options See options for {@link #load}
+     */
+    previousPage: function(options) {
+        this.loadPage(this.currentPage - 1, options);
+    },
 
-                groupers[i] = new Grouper(config);
-            }
-        }
+    // private
+    clearData: function() {
+        var me = this;
+        me.data.each(function(record) {
+            record.unjoin(me);
+        });
 
-        return groupers;
+        me.data.clear();
     },
-    
+
+    // Buffering
     /**
-     * Group data in the store
-     * @param {String|Array} groupers Either a string name of one of the fields in this Store's configured {@link Ext.data.Model Model},
-     * or an Array of grouper configurations.
-     * @param {String} direction The overall direction to group the data by. Defaults to "ASC".
+     * Prefetches data into the store using its configured {@link #proxy}.
+     * @param {Object} options (Optional) config object, passed into the Ext.data.Operation object before loading.
+     * See {@link #load}
      */
-    group: function(groupers, direction) {
+    prefetch: function(options) {
         var me = this,
-            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);
+            operation,
+            requestId = me.getRequestId();
 
-            if (!grouper) {
-                grouper = {
-                    property : groupers,
-                    direction: direction
-                };
-                newGroupers = [grouper];
-            } else if (direction === undefined) {
-                grouper.toggle();
-            } else {
-                grouper.setDirection(direction);
-            }
-        }
-        
-        if (newGroupers && newGroupers.length) {
-            newGroupers = me.decodeGroupers(newGroupers);
-            me.groupers.clear();
-            me.groupers.addAll(newGroupers);
-        }
-        
-        if (me.remoteGroup) {
-            me.load({
-                scope: me,
-                callback: me.fireGroupChange
-            });
-        } else {
-            me.sort();
-            me.fireEvent('groupchange', me, me.groupers);
+        options = options || {};
+
+        Ext.applyIf(options, {
+            action : 'read',
+            filters: me.filters.items,
+            sorters: me.sorters.items,
+            requestId: requestId
+        });
+        me.pendingRequests.push(requestId);
+
+        operation = Ext.create('Ext.data.Operation', options);
+
+        // HACK to implement loadMask support.
+        //if (operation.blocking) {
+        //    me.fireEvent('beforeload', me, operation);
+        //}
+        if (me.fireEvent('beforeprefetch', me, operation) !== false) {
+            me.loading = true;
+            me.proxy.read(operation, me.onProxyPrefetch, me);
         }
+
+        return me;
     },
-    
+
     /**
-     * Clear any groupers in the store
+     * Prefetches a page of data.
+     * @param {Number} page The page to prefetch
+     * @param {Object} options (Optional) config object, passed into the Ext.data.Operation object before loading.
+     * See {@link #load}
      */
-    clearGrouping: function(){
-        var me = this;
-        // Clear any groupers we pushed on to the sorters
-        me.groupers.each(function(grouper){
-            me.sorters.remove(grouper);
-        });
-        me.groupers.clear();
-        if (me.remoteGroup) {
-            me.load({
-                scope: me,
-                callback: me.fireGroupChange
+    prefetchPage: function(page, options) {
+        var me = this,
+            pageSize = me.pageSize,
+            start = (page - 1) * me.pageSize,
+            end = start + pageSize;
+
+        // Currently not requesting this page and range isn't already satisified
+        if (Ext.Array.indexOf(me.pagesRequested, page) === -1 && !me.rangeSatisfied(start, end)) {
+            options = options || {};
+            me.pagesRequested.push(page);
+            Ext.applyIf(options, {
+                page : page,
+                start: start,
+                limit: pageSize,
+                callback: me.onWaitForGuarantee,
+                scope: me
             });
-        } else {
-            me.sort();
-            me.fireEvent('groupchange', me, me.groupers);
+
+            me.prefetch(options);
         }
+
     },
-    
+
     /**
-     * Checks if the store is currently grouped
-     * @return {Boolean} True if the store is grouped.
+     * Returns a unique requestId to track requests.
+     * @private
      */
-    isGrouped: function() {
-        return this.groupers.getCount() > 0;    
+    getRequestId: function() {
+        this.requestSeed = this.requestSeed || 1;
+        return this.requestSeed++;
     },
-    
+
     /**
-     * Fires the groupchange event. Abstracted out so we can use it
-     * as a callback
+     * Called after the configured proxy completes a prefetch operation.
      * @private
+     * @param {Ext.data.Operation} operation The operation that completed
      */
-    fireGroupChange: function(){
-        this.fireEvent('groupchange', this, this.groupers);    
-    },
+    onProxyPrefetch: function(operation) {
+        var me         = this,
+            resultSet  = operation.getResultSet(),
+            records    = operation.getRecords(),
 
-    /**
-     * Returns an object containing the result of applying grouping to the records in this store. See {@link #groupField},
-     * {@link #groupDir} and {@link #getGroupString}. Example for a store containing records with a color field:
-<pre><code>
-var myStore = new Ext.data.Store({
-    groupField: 'color',
-    groupDir  : 'DESC'
-});
+            successful = operation.wasSuccessful();
 
-myStore.getGroups(); //returns:
-[
-    {
-        name: 'yellow',
-        children: [
-            //all records where the color field is 'yellow'
-        ]
+        if (resultSet) {
+            me.totalCount = resultSet.total;
+            me.fireEvent('totalcountchange', me.totalCount);
+        }
+
+        if (successful) {
+            me.cacheRecords(records, operation);
+        }
+        Ext.Array.remove(me.pendingRequests, operation.requestId);
+        if (operation.page) {
+            Ext.Array.remove(me.pagesRequested, operation.page);
+        }
+
+        me.loading = false;
+        me.fireEvent('prefetch', me, records, successful, operation);
+
+        // HACK to support loadMask
+        if (operation.blocking) {
+            me.fireEvent('load', me, records, successful);
+        }
+
+        //this is a callback that would have been passed to the 'read' function and is optional
+        Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
     },
-    {
-        name: 'red',
-        children: [
-            //all records where the color field is 'red'
-        ]
-    }
-]
-</code></pre>
-     * @param {String} groupName (Optional) Pass in an optional groupName argument to access a specific group as defined by {@link #getGroupString}
-     * @return {Array} The grouped data
+
+    /**
+     * Caches the records in the prefetch and stripes them with their server-side
+     * index.
+     * @private
+     * @param {Ext.data.Model[]} records The records to cache
+     * @param {Ext.data.Operation} The associated operation
      */
-    getGroups: function(requestGroupString) {
-        var records = this.data.items,
+    cacheRecords: function(records, operation) {
+        var me     = this,
+            i      = 0,
             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];
+            start  = operation ? operation.start : 0;
 
-            if (group === undefined) {
-                group = {
-                    name: groupStr,
-                    children: []
-                };
+        if (!Ext.isDefined(me.totalCount)) {
+            me.totalCount = records.length;
+            me.fireEvent('totalcountchange', me.totalCount);
+        }
 
-                groups.push(group);
-                pointers[groupStr] = group;
-            }
+        for (; i < length; i++) {
+            // this is the true index, not the viewIndex
+            records[i].index = start + i;
+        }
 
-            group.children.push(record);
+        me.prefetchData.addAll(records);
+        if (me.purgePageCount) {
+            me.purgeRecords();
         }
 
-        return requestGroupString ? pointers[requestGroupString] : groups;
+    },
+
+
+    /**
+     * Purge the least recently used records in the prefetch if the purgeCount
+     * has been exceeded.
+     */
+    purgeRecords: function() {
+        var me = this,
+            prefetchCount = me.prefetchData.getCount(),
+            purgeCount = me.purgePageCount * me.pageSize,
+            numRecordsToPurge = prefetchCount - purgeCount - 1,
+            i = 0;
+
+        for (; i <= numRecordsToPurge; i++) {
+            me.prefetchData.removeAt(0);
+        }
     },
 
     /**
+     * Determines if the range has already been satisfied in the prefetchData.
      * @private
-     * For a given set of records and a Grouper, returns an array of arrays - each of which is the set of records
-     * matching a certain group.
+     * @param {Number} start The start index
+     * @param {Number} end The end index in the range
      */
-    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);
+    rangeSatisfied: function(start, end) {
+        var me = this,
+            i = start,
+            satisfied = true;
 
-            if (newValue !== oldValue) {
-                group = {
-                    name: newValue,
-                    grouper: grouper,
-                    records: []
-                };
-                groups.push(group);
+        for (; i < end; i++) {
+            if (!me.prefetchData.getByKey(i)) {
+                satisfied = false;
+                //<debug>
+                if (end - i > me.pageSize) {
+                    Ext.Error.raise("A single page prefetch could never satisfy this request.");
+                }
+                //</debug>
+                break;
             }
-
-            group.records.push(record);
-
-            oldValue = newValue;
         }
+        return satisfied;
+    },
 
-        return groups;
+    /**
+     * Determines the page from a record index
+     * @param {Number} index The record index
+     * @return {Number} The page the record belongs to
+     */
+    getPageFromRecordIndex: function(index) {
+        return Math.floor(index / this.pageSize) + 1;
     },
 
     /**
+     * Handles a guaranteed range being loaded
      * @private
-     * This is used recursively to gather the records into the configured Groupers. The data MUST have been sorted for
-     * this to work properly (see {@link #getGroupData} and {@link #getGroupsForGrouper}) Most of the work is done by
-     * {@link #getGroupsForGrouper} - this function largely just handles the recursion.
-     * @param {Array} records The set or subset of records to group
-     * @param {Number} grouperIndex The grouper index to retrieve
-     * @return {Array} The grouped records
      */
-    getGroupsForGrouperIndex: function(records, grouperIndex) {
+    onGuaranteedRange: function() {
         var me = this,
-            groupers = me.groupers,
-            grouper = groupers.getAt(grouperIndex),
-            groups = me.getGroupsForGrouper(records, grouper),
-            length = groups.length,
-            i;
+            totalCount = me.getTotalCount(),
+            start = me.requestStart,
+            end = ((totalCount - 1) < me.requestEnd) ? totalCount - 1 : me.requestEnd,
+            range = [],
+            record,
+            i = start;
 
-        if (grouperIndex + 1 < groupers.length) {
-            for (i = 0; i < length; i++) {
-                groups[i].children = me.getGroupsForGrouperIndex(groups[i].records, grouperIndex + 1);
-            }
-        }
+        end = Math.max(0, end);
 
-        for (i = 0; i < length; i++) {
-            groups[i].depth = grouperIndex;
+        //<debug>
+        if (start > end) {
+            Ext.log({
+                level: 'warn',
+                msg: 'Start (' + start + ') was greater than end (' + end +
+                    ') for the range of records requested (' + me.requestStart + '-' +
+                    me.requestEnd + ')' + (this.storeId ? ' from store "' + this.storeId + '"' : '')
+            });
         }
+        //</debug>
 
-        return groups;
-    },
+        if (start !== me.guaranteedStart && end !== me.guaranteedEnd) {
+            me.guaranteedStart = start;
+            me.guaranteedEnd = end;
 
-    /**
-     * @private
-     * <p>Returns records grouped by the configured {@link #groupers grouper} configuration. Sample return value (in
-     * this case grouping by genre and then author in a fictional books dataset):</p>
-<pre><code>
-[
-    {
-        name: 'Fantasy',
-        depth: 0,
-        records: [
-            //book1, book2, book3, book4
-        ],
-        children: [
-            {
-                name: 'Rowling',
-                depth: 1,
-                records: [
-                    //book1, book2
-                ]
-            },
-            {
-                name: 'Tolkein',
-                depth: 1,
-                records: [
-                    //book3, book4
-                ]
+            for (; i <= end; i++) {
+                record = me.prefetchData.getByKey(i);
+                //<debug>
+//                if (!record) {
+//                    Ext.log('Record with key "' + i + '" was not found and store said it was guaranteed');
+//                }
+                //</debug>
+                if (record) {
+                    range.push(record);
+                }
+            }
+            me.fireEvent('guaranteedrange', range, start, end);
+            if (me.cb) {
+                me.cb.call(me.scope || me, range);
             }
-        ]
-    }
-]
-</code></pre>
-     * @param {Boolean} sort True to call {@link #sort} before finding groups. Sorting is required to make grouping
-     * function correctly so this should only be set to false if the Store is known to already be sorted correctly
-     * (defaults to true)
-     * @return {Array} The group data
-     */
-    getGroupData: function(sort) {
-        var me = this;
-        if (sort !== false) {
-            me.sort();
         }
 
-        return me.getGroupsForGrouperIndex(me.data.items, 0);
+        me.unmask();
+    },
+
+    // hack to support loadmask
+    mask: function() {
+        this.masked = true;
+        this.fireEvent('beforeload');
+    },
+
+    // hack to support loadmask
+    unmask: function() {
+        if (this.masked) {
+            this.fireEvent('load');
+        }
     },
 
     /**
-     * <p>Returns the string to group on for a given model instance. The default implementation of this method returns
-     * the model's {@link #groupField}, but this can be overridden to group by an arbitrary string. For example, to
-     * group by the first letter of a model's 'name' field, use the following code:</p>
-<pre><code>
-new Ext.data.Store({
-    groupDir: 'ASC',
-    getGroupString: function(instance) {
-        return instance.get('name')[0];
-    }
-});
-</code></pre>
-     * @param {Ext.data.Model} instance The model instance
-     * @return {String} The string to compare when forming groups
+     * Returns the number of pending requests out.
      */
-    getGroupString: function(instance) {
-        var group = this.groupers.first();
-        if (group) {
-            return instance.get(group.property);
+    hasPendingRequests: function() {
+        return this.pendingRequests.length;
+    },
+
+
+    // wait until all requests finish, until guaranteeing the range.
+    onWaitForGuarantee: function() {
+        if (!this.hasPendingRequests()) {
+            this.onGuaranteedRange();
         }
-        return '';
     },
+
     /**
-     * Inserts Model instances into the Store at the given index and fires the {@link #add} event.
-     * See also <code>{@link #add}</code>.
-     * @param {Number} index The start index at which to insert the passed Records.
-     * @param {Ext.data.Model[]} records An Array of Ext.data.Model objects to add to the cache.
+     * Guarantee a specific range, this will load the store with a range (that
+     * must be the pageSize or smaller) and take care of any loading that may
+     * be necessary.
      */
-    insert: function(index, records) {
+    guaranteeRange: function(start, end, cb, scope) {
+        //<debug>
+        if (start && end) {
+            if (end - start > this.pageSize) {
+                Ext.Error.raise({
+                    start: start,
+                    end: end,
+                    pageSize: this.pageSize,
+                    msg: "Requested a bigger range than the specified pageSize"
+                });
+            }
+        }
+        //</debug>
+
+        end = (end > this.totalCount) ? this.totalCount - 1 : end;
+
         var me = this,
-            sync = false,
-            i,
-            record,
-            len;
+            i = start,
+            prefetchData = me.prefetchData,
+            range = [],
+            startLoaded = !!prefetchData.getByKey(start),
+            endLoaded = !!prefetchData.getByKey(end),
+            startPage = me.getPageFromRecordIndex(start),
+            endPage = me.getPageFromRecordIndex(end);
 
-        records = [].concat(records);
-        for (i = 0, len = records.length; i < len; i++) {
-            record = me.createModel(records[i]);
-            record.set(me.modelDefaults);
-            // reassign the model in the array in case it wasn't created yet
-            records[i] = record;
-            
-            me.data.insert(index + i, record);
-            record.join(me);
+        me.cb = cb;
+        me.scope = scope;
 
-            sync = sync || record.phantom === true;
+        me.requestStart = start;
+        me.requestEnd = end;
+        // neither beginning or end are loaded
+        if (!startLoaded || !endLoaded) {
+            // same page, lets load it
+            if (startPage === endPage) {
+                me.mask();
+                me.prefetchPage(startPage, {
+                    //blocking: true,
+                    callback: me.onWaitForGuarantee,
+                    scope: me
+                });
+            // need to load two pages
+            } else {
+                me.mask();
+                me.prefetchPage(startPage, {
+                    //blocking: true,
+                    callback: me.onWaitForGuarantee,
+                    scope: me
+                });
+                me.prefetchPage(endPage, {
+                    //blocking: true,
+                    callback: me.onWaitForGuarantee,
+                    scope: me
+                });
+            }
+        // Request was already satisfied via the prefetch
+        } else {
+            me.onGuaranteedRange();
         }
+    },
 
-        if (me.snapshot) {
-            me.snapshot.addAll(records);
+    // because prefetchData is stored by index
+    // this invalidates all of the prefetchedData
+    sort: function() {
+        var me = this,
+            prefetchData = me.prefetchData,
+            sorters,
+            start,
+            end,
+            range;
+
+        if (me.buffered) {
+            if (me.remoteSort) {
+                prefetchData.clear();
+                me.callParent(arguments);
+            } else {
+                sorters = me.getSorters();
+                start = me.guaranteedStart;
+                end = me.guaranteedEnd;
+
+                if (sorters.length) {
+                    prefetchData.sort(sorters);
+                    range = prefetchData.getRange();
+                    prefetchData.clear();
+                    me.cacheRecords(range);
+                    delete me.guaranteedStart;
+                    delete me.guaranteedEnd;
+                    me.guaranteeRange(start, end);
+                }
+                me.callParent(arguments);
+            }
+        } else {
+            me.callParent(arguments);
         }
+    },
 
-        me.fireEvent('add', me, records, index);
-        me.fireEvent('datachanged', me);
-        if (me.autoSync && sync) {
-            me.sync();
+    // overriden to provide striping of the indexes as sorting occurs.
+    // this cannot be done inside of sort because datachanged has already
+    // fired and will trigger a repaint of the bound view.
+    doSort: function(sorterFn) {
+        var me = this;
+        if (me.remoteSort) {
+            //the load function will pick up the new sorters and request the sorted data from the proxy
+            me.load();
+        } else {
+            me.data.sortBy(sorterFn);
+            if (!me.buffered) {
+                var range = me.getRange(),
+                    ln = range.length,
+                    i  = 0;
+                for (; i < ln; i++) {
+                    range[i].index = i;
+                }
+            }
+            me.fireEvent('datachanged', me);
         }
     },
 
     /**
-     * Adds Model instances to the Store by instantiating them based on a JavaScript object. When adding already-
-     * instantiated Models, use {@link #insert} instead. The instances will be added at the end of the existing collection.
-     * This method accepts either a single argument array of Model instances or any number of model instance arguments.
-     * Sample usage:
-     *
-<pre><code>
-myStore.add({some: 'data'}, {some: 'other data'});
-</code></pre>
-     *
-     * @param {Object} data The data for each model
-     * @return {Array} The array of newly created model instances
+     * Finds the index of the first matching Record in this store by a specific field value.
+     * @param {String} fieldName The name of the Record field to test.
+     * @param {String/RegExp} value Either a string that the field value
+     * should begin with, or a RegExp to test against the field.
+     * @param {Number} startIndex (optional) The index to start searching at
+     * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
+     * @param {Boolean} caseSensitive (optional) True for case sensitive comparison
+     * @param {Boolean} exactMatch (optional) True to force exact match (^ and $ characters added to the regex). Defaults to false.
+     * @return {Number} The matched index or -1
      */
-    add: function(records) {
-        //accept both a single-argument array of records, or any number of record arguments
-        if (!Ext.isArray(records)) {
-            records = Array.prototype.slice.apply(arguments);
-        }
+    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;
+    },
 
+    /**
+     * Finds the first matching Record in this store by a specific field value.
+     * @param {String} fieldName The name of the Record field to test.
+     * @param {String/RegExp} value Either a string that the field value
+     * should begin with, or a RegExp to test against the field.
+     * @param {Number} startIndex (optional) The index to start searching at
+     * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
+     * @param {Boolean} caseSensitive (optional) True for case sensitive comparison
+     * @param {Boolean} exactMatch (optional) True to force exact match (^ and $ characters added to the regex). Defaults to false.
+     * @return {Ext.data.Model} The matched record or null
+     */
+    findRecord: function() {
         var me = this,
-            i = 0,
-            length = records.length,
-            record;
-
-        for (; i < length; i++) {
-            record = me.createModel(records[i]);
-            // reassign the model in the array in case it wasn't created yet
-            records[i] = record;
-        }
-
-        me.insert(me.data.length, records);
-
-        return records;
+            index = me.find.apply(me, arguments);
+        return index !== -1 ? me.getAt(index) : null;
     },
 
     /**
-     * Converts a literal to a model, if it's not a model already
      * @private
-     * @param record {Ext.data.Model/Object} The record to create
-     * @return {Ext.data.Model}
+     * Returns a filter function used to test a the given property's value. Defers most of the work to
+     * Ext.util.MixedCollection's createValueMatcher function
+     * @param {String} property The property to create the filter function for
+     * @param {String/RegExp} value The string/regex to compare the property value to
+     * @param {Boolean} [anyMatch=false] True if we don't care if the filter value is not the full value.
+     * @param {Boolean} [caseSensitive=false] True to create a case-sensitive regex.
+     * @param {Boolean} [exactMatch=false] True to force exact match (^ and $ characters added to the regex).
+     * Ignored if anyMatch is true.
      */
-    createModel: function(record) {
-        if (!record.isModel) {
-            record = Ext.ModelManager.create(record, this.model);
+    createFilterFn: function(property, value, anyMatch, caseSensitive, exactMatch) {
+        if (Ext.isEmpty(value)) {
+            return false;
         }
-
-        return record;
+        value = this.data.createValueMatcher(value, anyMatch, caseSensitive, exactMatch);
+        return function(r) {
+            return value.test(r.data[property]);
+        };
     },
 
     /**
-     * Calls the specified function for each of the {@link Ext.data.Model Records} in the cache.
-     * @param {Function} fn The function to call. The {@link Ext.data.Model Record} is passed as the first parameter.
-     * Returning <tt>false</tt> aborts and exits the iteration.
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed.
-     * Defaults to the current {@link Ext.data.Model Record} in the iteration.
+     * Finds the index of the first matching Record in this store by a specific field value.
+     * @param {String} fieldName The name of the Record field to test.
+     * @param {Object} value The value to match the field against.
+     * @param {Number} startIndex (optional) The index to start searching at
+     * @return {Number} The matched index or -1
      */
-    each: function(fn, scope) {
-        this.data.each(fn, scope);
+    findExact: function(property, value, start) {
+        return this.data.findIndexBy(function(rec) {
+            return rec.get(property) == value;
+        },
+        this, start);
     },
 
     /**
-     * Removes the given record from the Store, firing the 'remove' event for each instance that is removed, plus a single
-     * 'datachanged' event after removal.
-     * @param {Ext.data.Model/Array} records The Ext.data.Model instance or array of instances to remove
+     * Find the index of the first matching Record in this Store by a function.
+     * If the function returns <tt>true</tt> it is considered a match.
+     * @param {Function} fn The function to be called. It will be passed the following parameters:<ul>
+     * <li><b>record</b> : Ext.data.Model<p class="sub-desc">The {@link Ext.data.Model record}
+     * to test for filtering. Access field values using {@link Ext.data.Model#get}.</p></li>
+     * <li><b>id</b> : Object<p class="sub-desc">The ID of the Record passed.</p></li>
+     * </ul>
+     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this Store.
+     * @param {Number} startIndex (optional) The index to start searching at
+     * @return {Number} The matched index or -1
      */
-    remove: function(records, /* private */ isMove) {
-        if (!Ext.isArray(records)) {
-            records = [records];
-        }
+    findBy: function(fn, scope, start) {
+        return this.data.findIndexBy(fn, scope, start);
+    },
 
-        /*
-         * Pass the isMove parameter if we know we're going to be re-inserting this record
-         */
-        isMove = isMove === true;
+    /**
+     * Collects unique values for a particular dataIndex from this store.
+     * @param {String} dataIndex The property to collect
+     * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
+     * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
+     * @return {Object[]} An array of the unique values
+     **/
+    collect: function(dataIndex, allowNull, bypassFilter) {
         var me = this,
-            sync = false,
-            i = 0,
-            length = records.length,
-            isPhantom,
-            index,
-            record;
+            data = (bypassFilter === true && me.snapshot) ? me.snapshot: me.data;
 
-        for (; i < length; i++) {
-            record = records[i];
-            index = me.data.indexOf(record);
-            
-            if (me.snapshot) {
-                me.snapshot.remove(record);
-            }
-            
-            if (index > -1) {
-                isPhantom = record.phantom === true;
-                if (!isMove && !isPhantom) {
-                    // don't push phantom records onto removed
-                    me.removed.push(record);
-                }
+        return data.collect(dataIndex, 'data', allowNull);
+    },
 
-                record.unjoin(me);
-                me.data.remove(record);
-                sync = sync || !isPhantom;
+    /**
+     * Gets the number of cached records.
+     * <p>If using paging, this may not be the total size of the dataset. If the data object
+     * used by the Reader contains the dataset size, then the {@link #getTotalCount} function returns
+     * the dataset size.  <b>Note</b>: see the Important note in {@link #load}.</p>
+     * @return {Number} The number of Records in the Store's cache.
+     */
+    getCount: function() {
+        return this.data.length || 0;
+    },
 
-                me.fireEvent('remove', me, record, index);
-            }
-        }
+    /**
+     * Returns the total number of {@link Ext.data.Model Model} instances that the {@link Ext.data.proxy.Proxy Proxy}
+     * indicates exist. This will usually differ from {@link #getCount} when using paging - getCount returns the
+     * number of records loaded into the Store at the moment, getTotalCount returns the number of records that
+     * could be loaded into the Store if the Store contained all data
+     * @return {Number} The total number of Model instances available via the Proxy
+     */
+    getTotalCount: function() {
+        return this.totalCount;
+    },
 
-        me.fireEvent('datachanged', me);
-        if (!isMove && me.autoSync && sync) {
-            me.sync();
-        }
+    /**
+     * Get the Record at the specified index.
+     * @param {Number} index The index of the Record to find.
+     * @return {Ext.data.Model} The Record at the passed index. Returns undefined if not found.
+     */
+    getAt: function(index) {
+        return this.data.getAt(index);
     },
 
     /**
-     * Removes the model instance at the given index
-     * @param {Number} index The record index
+     * Returns a range of Records between specified indices.
+     * @param {Number} [startIndex=0] The starting index
+     * @param {Number} [endIndex] The ending index. Defaults to the last Record in the Store.
+     * @return {Ext.data.Model[]} An array of Records
      */
-    removeAt: function(index) {
-        var record = this.getAt(index);
+    getRange: function(start, end) {
+        return this.data.getRange(start, end);
+    },
 
-        if (record) {
-            this.remove(record);
-        }
+    /**
+     * Get the Record with the specified id.
+     * @param {String} id The id of the Record to find.
+     * @return {Ext.data.Model} The Record with the passed id. Returns null if not found.
+     */
+    getById: function(id) {
+        return (this.snapshot || this.data).findBy(function(record) {
+            return record.getId() === id;
+        });
+    },
+
+    /**
+     * Get the index within the cache of the passed Record.
+     * @param {Ext.data.Model} record The Ext.data.Model object to find.
+     * @return {Number} The index of the passed Record. Returns -1 if not found.
+     */
+    indexOf: function(record) {
+        return this.data.indexOf(record);
     },
 
+
     /**
-     * <p>Loads data into the Store via the configured {@link #proxy}. This uses the Proxy to make an
-     * asynchronous call to whatever storage backend the Proxy uses, automatically adding the retrieved
-     * instances into the Store and calling an optional callback if required. Example usage:</p>
-     *
-<pre><code>
-store.load({
-    scope   : this,
-    callback: function(records, operation, success) {
-        //the {@link Ext.data.Operation operation} object contains all of the details of the load operation
-        console.log(records);
-    }
-});
-</code></pre>
-     *
-     * <p>If the callback scope does not need to be set, a function can simply be passed:</p>
-     *
-<pre><code>
-store.load(function(records, operation, success) {
-    console.log('loaded records');
-});
-</code></pre>
-     *
-     * @param {Object/Function} options Optional config object, passed into the Ext.data.Operation object before loading.
+     * Get the index within the entire dataset. From 0 to the totalCount.
+     * @param {Ext.data.Model} record The Ext.data.Model object to find.
+     * @return {Number} The index of the passed Record. Returns -1 if not found.
      */
-    load: function(options) {
-        var me = this;
-            
-        options = options || {};
-
-        if (Ext.isFunction(options)) {
-            options = {
-                callback: options
-            };
+    indexOfTotal: function(record) {
+        var index = record.index;
+        if (index || index === 0) {
+            return index;
         }
+        return this.indexOf(record);
+    },
 
-        Ext.applyIf(options, {
-            groupers: me.groupers.items,
-            page: me.currentPage,
-            start: (me.currentPage - 1) * me.pageSize,
-            limit: me.pageSize,
-            addRecords: false
-        });      
-
-        return me.callParent([options]);
+    /**
+     * Get the index within the cache of the Record with the passed id.
+     * @param {String} id The id of the Record to find.
+     * @return {Number} The index of the Record. Returns -1 if not found.
+     */
+    indexOfId: function(id) {
+        return this.indexOf(this.getById(id));
     },
 
     /**
-     * @private
-     * Called internally when a Proxy has completed a load request
+     * Remove all items from the store.
+     * @param {Boolean} silent Prevent the `clear` event from being fired.
      */
-    onProxyLoad: function(operation) {
-        var me = this,
-            resultSet = operation.getResultSet(),
-            records = operation.getRecords(),
-            successful = operation.wasSuccessful();
+    removeAll: function(silent) {
+        var me = this;
 
-        if (resultSet) {
-            me.totalCount = resultSet.total;
+        me.clearData();
+        if (me.snapshot) {
+            me.snapshot.clear();
         }
-
-        if (successful) {
-            me.loadRecords(records, operation);
+        if (silent !== true) {
+            me.fireEvent('clear', me);
         }
+    },
 
-        me.loading = false;
-        me.fireEvent('load', me, records, successful);
-
-        //TODO: deprecate this event, it should always have been 'load' instead. 'load' is now documented, 'read' is not.
-        //People are definitely using this so can't deprecate safely until 2.x
-        me.fireEvent('read', me, records, operation.wasSuccessful());
+    /*
+     * Aggregation methods
+     */
 
-        //this is a callback that would have been passed to the 'read' function and is optional
-        Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
-    },
-    
     /**
-     * Create any new records when a write is returned from the server.
-     * @private
-     * @param {Array} records The array of new records
-     * @param {Ext.data.Operation} operation The operation that just completed
-     * @param {Boolean} success True if the operation was successful
+     * Convenience function for getting the first model instance in the store
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the first record being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @return {Ext.data.Model/undefined} The first model instance in the store, or undefined
      */
-    onCreateRecords: function(records, operation, success) {
-        if (success) {
-            var i = 0,
-                data = this.data,
-                snapshot = this.snapshot,
-                length = records.length,
-                originalRecords = operation.records,
-                record,
-                original,
-                index;
+    first: function(grouped) {
+        var me = this;
 
-            /*
-             * Loop over each record returned from the server. Assume they are
-             * returned in order of how they were sent. If we find a matching
-             * record, replace it with the newly created one.
-             */
-            for (; i < length; ++i) {
-                record = records[i];
-                original = originalRecords[i];
-                if (original) {
-                    index = data.indexOf(original);
-                    if (index > -1) {
-                        data.removeAt(index);
-                        data.insert(index, record);
-                    }
-                    if (snapshot) {
-                        index = snapshot.indexOf(original);
-                        if (index > -1) {
-                            snapshot.removeAt(index);
-                            snapshot.insert(index, record);
-                        }
-                    }
-                    record.phantom = false;
-                    record.join(this);
-                }
-            }
+        if (grouped && me.isGrouped()) {
+            return me.aggregate(function(records) {
+                return records.length ? records[0] : undefined;
+            }, me, true);
+        } else {
+            return me.data.first();
         }
     },
 
     /**
-     * Update any records when a write is returned from the server.
-     * @private
-     * @param {Array} records The array of updated records
-     * @param {Ext.data.Operation} operation The operation that just completed
-     * @param {Boolean} success True if the operation was successful
+     * Convenience function for getting the last model instance in the store
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the last record being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @return {Ext.data.Model/undefined} The last model instance in the store, or undefined
      */
-    onUpdateRecords: function(records, operation, success){
-        if (success) {
-            var i = 0,
-                length = records.length,
-                data = this.data,
-                snapshot = this.snapshot,
-                record;
+    last: function(grouped) {
+        var me = this;
 
-            for (; i < length; ++i) {
-                record = records[i];
-                data.replace(record);
-                if (snapshot) {
-                    snapshot.replace(record);
-                }
-                record.join(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();
         }
     },
 
     /**
-     * Remove any records when a write is returned from the server.
-     * @private
-     * @param {Array} records The array of removed records
-     * @param {Ext.data.Operation} operation The operation that just completed
-     * @param {Boolean} success True if the operation was successful
+     * Sums the value of <tt>property</tt> for each {@link Ext.data.Model record} between <tt>start</tt>
+     * and <tt>end</tt> and returns the result.
+     * @param {String} field A field in each record
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the sum for that group being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @return {Number} The sum
      */
-    onDestroyRecords: function(records, operation, success){
-        if (success) {
-            var me = this,
-                i = 0,
-                length = records.length,
-                data = me.data,
-                snapshot = me.snapshot,
-                record;
+    sum: function(field, grouped) {
+        var me = this;
 
-            for (; i < length; ++i) {
-                record = records[i];
-                record.unjoin(me);
-                data.remove(record);
-                if (snapshot) {
-                    snapshot.remove(record);
-                }
-            }
-            me.removed = [];
+        if (grouped && me.isGrouped()) {
+            return me.aggregate(me.getSum, me, true, [field]);
+        } else {
+            return me.getSum(me.data.items, field);
         }
     },
 
-    //inherit docs
-    getNewRecords: function() {
-        return this.data.filterBy(this.filterNew).items;
-    },
+    // @private, see sum
+    getSum: function(records, field) {
+        var total = 0,
+            i = 0,
+            len = records.length;
 
-    //inherit docs
-    getUpdatedRecords: function() {
-        return this.data.filterBy(this.filterUpdated).items;
+        for (; i < len; ++i) {
+            total += records[i].get(field);
+        }
+
+        return total;
     },
 
     /**
-     * Filters the loaded set of records by a given set of filters.
-     * @param {Mixed} filters The set of filters to apply to the data. These are stored internally on the store,
-     * but the filtering itself is done on the Store's {@link Ext.util.MixedCollection MixedCollection}. See
-     * MixedCollection's {@link Ext.util.MixedCollection#filter filter} method for filter syntax. Alternatively,
-     * pass in a property string
-     * @param {String} value Optional value to filter by (only if using a property string as the first argument)
+     * Gets the count of items in the store.
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the count for each group being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @return {Number} the count
      */
-    filter: function(filters, value) {
-        if (Ext.isString(filters)) {
-            filters = {
-                property: filters,
-                value: value
-            };
-        }
-
-        var me = this,
-            decoded = me.decodeFilters(filters),
-            i = 0,
-            doLocalSort = me.sortOnFilter && !me.remoteSort,
-            length = decoded.length;
-
-        for (; i < length; i++) {
-            me.filters.replace(decoded[i]);
-        }
+    count: function(grouped) {
+        var me = this;
 
-        if (me.remoteFilter) {
-            //the load function will pick up the new filters and request the filtered data from the proxy
-            me.load();
+        if (grouped && me.isGrouped()) {
+            return me.aggregate(function(records) {
+                return records.length;
+            }, me, true);
         } else {
-            /**
-             * A pristine (unfiltered) collection of the records in this store. This is used to reinstate
-             * records when a filter is removed or changed
-             * @property snapshot
-             * @type Ext.util.MixedCollection
-             */
-            if (me.filters.getCount()) {
-                me.snapshot = me.snapshot || me.data.clone();
-                me.data = me.data.filter(me.filters.items);
-
-                if (doLocalSort) {
-                    me.sort();
-                }
-                // fire datachanged event if it hasn't already been fired by doSort
-                if (!doLocalSort || me.sorters.length < 1) {
-                    me.fireEvent('datachanged', me);
-                }
-            }
+            return me.getCount();
         }
     },
 
     /**
-     * Revert to a view of the Record cache with no filtering applied.
-     * @param {Boolean} suppressEvent If <tt>true</tt> the filter is cleared silently without firing the
-     * {@link #datachanged} event.
+     * Gets the minimum value in the store.
+     * @param {String} field The field in each record
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the minimum in the group being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @return {Object} The minimum value, if no items exist, undefined.
      */
-    clearFilter: function(suppressEvent) {
+    min: function(field, grouped) {
         var me = this;
 
-        me.filters.clear();
+        if (grouped && me.isGrouped()) {
+            return me.aggregate(me.getMin, me, true, [field]);
+        } else {
+            return me.getMin(me.data.items, field);
+        }
+    },
 
-        if (me.remoteFilter) {
-            me.load();
-        } else if (me.isFiltered()) {
-            me.data = me.snapshot.clone();
-            delete me.snapshot;
+    // @private, see min
+    getMin: function(records, field){
+        var i = 1,
+            len = records.length,
+            value, min;
 
-            if (suppressEvent !== true) {
-                me.fireEvent('datachanged', me);
-            }
+        if (len > 0) {
+            min = records[0].get(field);
         }
-    },
 
-    /**
-     * Returns true if this store is currently filtered
-     * @return {Boolean}
-     */
-    isFiltered: function() {
-        var snapshot = this.snapshot;
-        return !! snapshot && snapshot !== this.data;
+        for (; i < len; ++i) {
+            value = records[i].get(field);
+            if (value < min) {
+                min = value;
+            }
+        }
+        return min;
     },
 
     /**
-     * Filter by a function. The specified function will be called for each
-     * Record in this Store. If the function returns <tt>true</tt> the Record is included,
-     * otherwise it is filtered out.
-     * @param {Function} fn The function to be called. It will be passed the following parameters:<ul>
-     * <li><b>record</b> : Ext.data.Model<p class="sub-desc">The {@link Ext.data.Model record}
-     * to test for filtering. Access field values using {@link Ext.data.Model#get}.</p></li>
-     * <li><b>id</b> : Object<p class="sub-desc">The ID of the Record passed.</p></li>
-     * </ul>
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this Store.
+     * Gets the maximum value in the store.
+     * @param {String} field The field in each record
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the maximum in the group being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @return {Object} The maximum value, if no items exist, undefined.
      */
-    filterBy: function(fn, scope) {
+    max: function(field, grouped) {
         var me = this;
 
-        me.snapshot = me.snapshot || me.data.clone();
-        me.data = me.queryBy(fn, scope || me);
-        me.fireEvent('datachanged', me);
-    },
-
-    /**
-     * Query the cached records in this Store using a filtering function. The specified function
-     * will be called with each record in this Store. If the function returns <tt>true</tt> the record is
-     * included in the results.
-     * @param {Function} fn The function to be called. It will be passed the following parameters:<ul>
-     * <li><b>record</b> : Ext.data.Model<p class="sub-desc">The {@link Ext.data.Model record}
-     * to test for filtering. Access field values using {@link Ext.data.Model#get}.</p></li>
-     * <li><b>id</b> : Object<p class="sub-desc">The ID of the Record passed.</p></li>
-     * </ul>
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this Store.
-     * @return {MixedCollection} Returns an Ext.util.MixedCollection of the matched records
-     **/
-    queryBy: function(fn, scope) {
-        var me = this,
-        data = me.snapshot || me.data;
-        return data.filterBy(fn, scope || me);
+        if (grouped && me.isGrouped()) {
+            return me.aggregate(me.getMax, me, true, [field]);
+        } else {
+            return me.getMax(me.data.items, field);
+        }
     },
 
-    /**
-     * Loads an array of data straight into the Store
-     * @param {Array} data Array of data to load. Any non-model instances will be cast into model instances first
-     * @param {Boolean} append True to add the records to the existing records in the store, false to remove the old ones first
-     */
-    loadData: function(data, append) {
-        var model = this.model,
-            length = data.length,
-            i,
-            record;
+    // @private, see max
+    getMax: function(records, field) {
+        var i = 1,
+            len = records.length,
+            value,
+            max;
 
-        //make sure each data element is an Ext.data.Model instance
-        for (i = 0; i < length; i++) {
-            record = data[i];
+        if (len > 0) {
+            max = records[0].get(field);
+        }
 
-            if (! (record instanceof Ext.data.Model)) {
-                data[i] = Ext.ModelManager.create(record, model);
+        for (; i < len; ++i) {
+            value = records[i].get(field);
+            if (value > max) {
+                max = value;
             }
         }
-
-        this.loadRecords(data, {addRecords: append});
+        return max;
     },
 
     /**
-     * Loads an array of {@Ext.data.Model model} instances into the store, fires the datachanged event. This should only usually
-     * be called internally when loading from the {@link Ext.data.proxy.Proxy Proxy}, when adding records manually use {@link #add} instead
-     * @param {Array} records The array of records to load
-     * @param {Object} options {addRecords: true} to add these records to the existing records, false to remove the Store's existing records first
+     * Gets the average value in the store.
+     * @param {String} field The field in each record
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the group average being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @return {Object} The average value, if no items exist, 0.
      */
-    loadRecords: function(records, options) {
-        var me     = this,
-            i      = 0,
-            length = records.length;
-
-        options = options || {};
-
-
-        if (!options.addRecords) {
-            delete me.snapshot;
-            me.clearData();
+    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);
         }
+    },
 
-        me.data.addAll(records);
-
-        //FIXME: this is not a good solution. Ed Spencer is totally responsible for this and should be forced to fix it immediately.
-        for (; i < length; i++) {
-            if (options.start !== undefined) {
-                records[i].index = options.start + i;
+    // @private, see average
+    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);
             }
-            records[i].join(me);
+            return sum / len;
         }
+        return 0;
+    },
 
-        /*
-         * this rather inelegant suspension and resumption of events is required because both the filter and sort functions
-         * fire an additional datachanged event, which is not wanted. Ideally we would do this a different way. The first
-         * datachanged event is fired by the call to this.add, above.
-         */
-        me.suspendEvents();
+    /**
+     * Runs the aggregate function for all the records in the store.
+     * @param {Function} fn The function to execute. The function is called with a single parameter,
+     * an array of records for that group.
+     * @param {Object} scope (optional) The scope to execute the function in. Defaults to the store.
+     * @param {Boolean} grouped (Optional) True to perform the operation for each group
+     * in the store. The value returned will be an object literal with the key being the group
+     * name and the group average being the value. The grouped parameter is only honored if
+     * the store has a groupField.
+     * @param {Array} args (optional) Any arguments to append to the function call
+     * @return {Object} An object literal with the group names and their appropriate values.
+     */
+    aggregate: function(fn, scope, grouped, args) {
+        args = args || [];
+        if (grouped && this.isGrouped()) {
+            var groups = this.getGroups(),
+                i = 0,
+                len = groups.length,
+                out = {},
+                group;
 
-        if (me.filterOnLoad && !me.remoteFilter) {
-            me.filter();
+            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));
         }
+    }
+}, function() {
+    // A dummy empty store with a fieldless Model defined in it.
+    // Just for binding to Views which are instantiated with no Store defined.
+    // They will be able to run and render fine, and be bound to a generated Store later.
+    Ext.regStore('ext-empty-store', {fields: [], proxy: 'proxy'});
+});
 
-        if (me.sortOnLoad && !me.remoteSort) {
-            me.sort();
-        }
+/**
+ * @author Ed Spencer
+ * @class Ext.data.JsonStore
+ * @extends Ext.data.Store
+ * @ignore
+ *
+ * <p>Small helper class to make creating {@link Ext.data.Store}s from JSON data easier.
+ * A JsonStore will be automatically configured with a {@link Ext.data.reader.Json}.</p>
+ *
+ * <p>A store configuration would be something like:</p>
+ *
+<pre><code>
+var store = new Ext.data.JsonStore({
+    // store configs
+    autoDestroy: true,
+    storeId: 'myStore',
 
-        me.resumeEvents();
-        me.fireEvent('datachanged', me, records);
+    proxy: {
+        type: 'ajax',
+        url: 'get-images.php',
+        reader: {
+            type: 'json',
+            root: 'images',
+            idProperty: 'name'
+        }
     },
 
-    // PAGING METHODS
+    //alternatively, a {@link Ext.data.Model} name can be given (see {@link Ext.data.Store} for an example)
+    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
+});
+</code></pre>
+ *
+ * <p>This store is configured to consume a returned object of the form:<pre><code>
+{
+    images: [
+        {name: 'Image one', url:'/GetImage.php?id=1', size:46.5, lastmod: new Date(2007, 10, 29)},
+        {name: 'Image Two', url:'/GetImage.php?id=2', size:43.2, lastmod: new Date(2007, 10, 30)}
+    ]
+}
+</code></pre>
+ *
+ * <p>An object literal of this form could also be used as the {@link #data} config option.</p>
+ *
+ * @xtype jsonstore
+ */
+Ext.define('Ext.data.JsonStore',  {
+    extend: 'Ext.data.Store',
+    alias: 'store.json',
+
     /**
-     * Loads a given 'page' of data by setting the start and limit values appropriately. Internally this just causes a normal
-     * load operation, passing in calculated 'start' and 'limit' params
-     * @param {Number} page The number of the page to load
+     * @cfg {Ext.data.DataReader} reader @hide
      */
-    loadPage: function(page) {
-        var me = this;
-
-        me.currentPage = page;
+    constructor: function(config) {
+        config = config || {};
 
-        me.read({
-            page: page,
-            start: (page - 1) * me.pageSize,
-            limit: me.pageSize,
-            addRecords: !me.clearOnPageLoad
+        Ext.applyIf(config, {
+            proxy: {
+                type  : 'ajax',
+                reader: 'json',
+                writer: 'json'
+            }
         });
-    },
 
-    /**
-     * Loads the next 'page' in the current data set
-     */
-    nextPage: function() {
-        this.loadPage(this.currentPage + 1);
-    },
+        this.callParent([config]);
+    }
+});
 
-    /**
-     * Loads the previous 'page' in the current data set
-     */
-    previousPage: function() {
-        this.loadPage(this.currentPage - 1);
-    },
+/**
+ * @class Ext.chart.axis.Time
+ * @extends Ext.chart.axis.Numeric
+ *
+ * A type of axis whose units are measured in time values. Use this axis
+ * for listing dates that you will want to group or dynamically change.
+ * If you just want to display dates as categories then use the
+ * Category class for axis instead.
+ *
+ * For example:
+ *
+ *     axes: [{
+ *         type: 'Time',
+ *         position: 'bottom',
+ *         fields: 'date',
+ *         title: 'Day',
+ *         dateFormat: 'M d',
+ *
+ *         constrain: true,
+ *         fromDate: new Date('1/1/11'),
+ *         toDate: new Date('1/7/11')
+ *     }]
+ *
+ * In this example we're creating a time axis that has as title *Day*.
+ * The field the axis is bound to is `date`.
+ * The date format to use to display the text for the axis labels is `M d`
+ * which is a three letter month abbreviation followed by the day number.
+ * The time axis will show values for dates between `fromDate` and `toDate`.
+ * Since `constrain` is set to true all other values for other dates not between
+ * the fromDate and toDate will not be displayed.
+ *
+ */
+Ext.define('Ext.chart.axis.Time', {
 
-    // private
-    clearData: function() {
-        this.data.each(function(record) {
-            record.unjoin();
-        });
+    /* Begin Definitions */
 
-        this.data.clear();
-    },
-    
-    // Buffering
-    /**
-     * Prefetches data the Store using its configured {@link #proxy}.
-     * @param {Object} options Optional config object, passed into the Ext.data.Operation object before loading.
-     * See {@link #load}
-     */
-    prefetch: function(options) {
-        var me = this,
-            operation,
-            requestId = me.getRequestId();
+    extend: 'Ext.chart.axis.Numeric',
 
-        options = options || {};
+    alternateClassName: 'Ext.chart.TimeAxis',
 
-        Ext.applyIf(options, {
-            action : 'read',
-            filters: me.filters.items,
-            sorters: me.sorters.items,
-            requestId: requestId
-        });
-        me.pendingRequests.push(requestId);
+    alias: 'axis.time',
 
-        operation = Ext.create('Ext.data.Operation', options);
+    requires: ['Ext.data.Store', 'Ext.data.JsonStore'],
+
+    /* End Definitions */
 
-        // HACK to implement loadMask support.
-        //if (operation.blocking) {
-        //    me.fireEvent('beforeload', me, operation);
-        //}
-        if (me.fireEvent('beforeprefetch', me, operation) !== false) {
-            me.loading = true;
-            me.proxy.read(operation, me.onProxyPrefetch, me);
-        }
-        
-        return me;
-    },
-    
     /**
-     * Prefetches a page of data.
-     * @param {Number} page The page to prefetch
-     * @param {Object} options Optional config object, passed into the Ext.data.Operation object before loading.
-     * See {@link #load}
-     * @param
+     * @cfg {String/Boolean} dateFormat
+     * Indicates the format the date will be rendered on.
+     * For example: 'M d' will render the dates as 'Jan 30', etc.
+     * For a list of possible format strings see {@link Ext.Date Date}
      */
-    prefetchPage: function(page, options) {
-        var me = this,
-            pageSize = me.pageSize,
-            start = (page - 1) * me.pageSize,
-            end = start + pageSize;
-        
-        // Currently not requesting this page and range isn't already satisified 
-        if (Ext.Array.indexOf(me.pagesRequested, page) === -1 && !me.rangeSatisfied(start, end)) {
-            options = options || {};
-            me.pagesRequested.push(page);
-            Ext.applyIf(options, {
-                page : page,
-                start: start,
-                limit: pageSize,
-                callback: me.onWaitForGuarantee,
-                scope: me
-            });
-            
-            me.prefetch(options);
-        }
-        
-    },
-    
+    dateFormat: false,
+
     /**
-     * Returns a unique requestId to track requests.
-     * @private
+     * @cfg {Date} fromDate The starting date for the time axis.
      */
-    getRequestId: function() {
-        this.requestSeed = this.requestSeed || 1;
-        return this.requestSeed++;
-    },
-    
+    fromDate: false,
+
     /**
-     * Handles a success pre-fetch
-     * @private
-     * @param {Ext.data.Operation} operation The operation that completed
+     * @cfg {Date} toDate The ending date for the time axis.
      */
-    onProxyPrefetch: function(operation) {
-        var me         = this,
-            resultSet  = operation.getResultSet(),
-            records    = operation.getRecords(),
-            
-            successful = operation.wasSuccessful();
-        
-        if (resultSet) {
-            me.totalCount = resultSet.total;
-            me.fireEvent('totalcountchange', me.totalCount);
-        }
-        
-        if (successful) {
-            me.cacheRecords(records, operation);
-        }
-        Ext.Array.remove(me.pendingRequests, operation.requestId);
-        if (operation.page) {
-            Ext.Array.remove(me.pagesRequested, operation.page);
-        }
-        
-        me.loading = false;
-        me.fireEvent('prefetch', me, records, successful, operation);
-        
-        // HACK to support loadMask
-        if (operation.blocking) {
-            me.fireEvent('load', me, records, successful);
-        }
+    toDate: false,
 
-        //this is a callback that would have been passed to the 'read' function and is optional
-        Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
-    },
-    
     /**
-     * Caches the records in the prefetch and stripes them with their server-side
-     * index.
-     * @private
-     * @param {Array} records The records to cache
-     * @param {Ext.data.Operation} The associated operation
+     * @cfg {Array/Boolean} step
+     * An array with two components: The first is the unit of the step (day, month, year, etc).
+     * The second one is the number of units for the step (1, 2, etc.).
+     * Defaults to `[Ext.Date.DAY, 1]`.
      */
-    cacheRecords: function(records, operation) {
-        var me     = this,
-            i      = 0,
-            length = records.length,
-            start  = operation ? operation.start : 0;
-        
-        if (!Ext.isDefined(me.totalCount)) {
-            me.totalCount = records.length;
-            me.fireEvent('totalcountchange', me.totalCount);
-        }
-        
-        for (; i < length; i++) {
-            // this is the true index, not the viewIndex
-            records[i].index = start + i;
-        }
-        
-        me.prefetchData.addAll(records);
-        if (me.purgePageCount) {
-            me.purgeRecords();
-        }
-        
-    },
-    
+    step: [Ext.Date.DAY, 1],
     
     /**
-     * Purge the least recently used records in the prefetch if the purgeCount
-     * has been exceeded.
+     * @cfg {Boolean} constrain
+     * If true, the values of the chart will be rendered only if they belong between the fromDate and toDate.
+     * If false, the time axis will adapt to the new values by adding/removing steps.
      */
-    purgeRecords: function() {
-        var me = this,
-            prefetchCount = me.prefetchData.getCount(),
-            purgeCount = me.purgePageCount * me.pageSize,
-            numRecordsToPurge = prefetchCount - purgeCount - 1,
-            i = 0;
+    constrain: false,
 
-        for (; i <= numRecordsToPurge; i++) {
-            me.prefetchData.removeAt(0);
-        }
-    },
+    // Avoid roundtoDecimal call in Numeric Axis's constructor
+    roundToDecimal: false,
     
-    /**
-     * Determines if the range has already been satisfied in the prefetchData.
-     * @private
-     * @param {Number} start The start index
-     * @param {Number} end The end index in the range
-     */
-    rangeSatisfied: function(start, end) {
-        var me = this,
-            i = start,
-            satisfied = true;
-
-        for (; i < end; i++) {
-            if (!me.prefetchData.getByKey(i)) {
-                satisfied = false;
-                //<debug>
-                if (end - i > me.pageSize) {
-                    Ext.Error.raise("A single page prefetch could never satisfy this request.");
-                }
-                //</debug>
-                break;
+    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);
+                };
             }
         }
-        return satisfied;
-    },
-    
-    /**
-     * Determines the page from a record index
-     * @param {Number} index The record index
-     * @return {Number} The page the record belongs to
-     */
-    getPageFromRecordIndex: function(index) {
-        return Math.floor(index / this.pageSize) + 1;
     },
-    
-    /**
-     * Handles a guaranteed range being loaded
-     * @private
-     */
-    onGuaranteedRange: function() {
+
+    doConstrain: function () {
         var me = this,
-            totalCount = me.getTotalCount(),
-            start = me.requestStart,
-            end = ((totalCount - 1) < me.requestEnd) ? totalCount - 1 : me.requestEnd,
-            range = [],
-            record,
-            i = start;
-            
-        //<debug>
-        if (start > end) {
-            Ext.Error.raise("Start (" + start + ") was greater than end (" + end + ")");
+            store = me.chart.store,
+            data = [],
+            series = me.chart.series.items,
+            math = Math,
+            mmax = math.max,
+            mmin = math.min,
+            fields = me.fields,
+            ln = fields.length,
+            range = me.getRange(),
+            min = range.min, max = range.max, i, l, excludes = [],
+            value, values, rec, data = [];
+        for (i = 0, l = series.length; i < l; i++) {
+            excludes[i] = series[i].__excludes;
         }
-        //</debug>
-        
-        if (start !== me.guaranteedStart && end !== me.guaranteedEnd) {
-            me.guaranteedStart = start;
-            me.guaranteedEnd = end;
-            
-            for (; i <= end; i++) {
-                record = me.prefetchData.getByKey(i);
-                //<debug>
-                if (!record) {
-                    Ext.Error.raise("Record was not found and store said it was guaranteed");
+        store.each(function(record) {
+            for (i = 0; i < ln; i++) {
+                if (excludes[i]) {
+                    continue;
                 }
-                //</debug>
-                range.push(record);
-            }
-            me.fireEvent('guaranteedrange', range, start, end);
-            if (me.cb) {
-                me.cb.call(me.scope || me, range);
+                value = record.get(fields[i]);
+                if (+value < +min) return;
+                if (+value > +max) return;
             }
-        }
-        
-        me.unmask();
-    },
-    
-    // hack to support loadmask
-    mask: function() {
-        this.masked = true;
-        this.fireEvent('beforeload');
+            data.push(record);
+        })
+        me.chart.substore = Ext.create('Ext.data.JsonStore', { model: store.model, data: data });
     },
-    
-    // hack to support loadmask
-    unmask: function() {
-        if (this.masked) {
-            this.fireEvent('load');
+
+    // Before rendering, set current default step count to be number of records.
+    processView: function () {
+        var me = this;
+        if (me.fromDate) {
+            me.minimum = +me.fromDate;
         }
-    },
-    
-    /**
-     * Returns the number of pending requests out.
-     */
-    hasPendingRequests: function() {
-        return this.pendingRequests.length;
-    },
-    
-    
-    // wait until all requests finish, until guaranteeing the range.
-    onWaitForGuarantee: function() {
-        if (!this.hasPendingRequests()) {
-            this.onGuaranteedRange();
+        if (me.toDate) {
+            me.maximum = +me.toDate;
         }
-    },
-    
-    /**
-     * Guarantee a specific range, this will load the store with a range (that
-     * must be the pageSize or smaller) and take care of any loading that may
-     * be necessary.
-     */
-    guaranteeRange: function(start, end, cb, scope) {
-        //<debug>
-        if (start && end) {
-            if (end - start > this.pageSize) {
-                Ext.Error.raise({
-                    start: start,
-                    end: end,
-                    pageSize: this.pageSize,
-                    msg: "Requested a bigger range than the specified pageSize"
-                });
-            }
+        if (me.constrain) {
+            me.doConstrain();
         }
-        //</debug>
-        
-        end = (end > this.totalCount) ? this.totalCount - 1 : end;
-        
-        var me = this,
-            i = start,
-            prefetchData = me.prefetchData,
-            range = [],
-            startLoaded = !!prefetchData.getByKey(start),
-            endLoaded = !!prefetchData.getByKey(end),
-            startPage = me.getPageFromRecordIndex(start),
-            endPage = me.getPageFromRecordIndex(end);
-            
-        me.cb = cb;
-        me.scope = scope;
+     },
 
-        me.requestStart = start;
-        me.requestEnd = end;
-        // neither beginning or end are loaded
-        if (!startLoaded || !endLoaded) {
-            // same page, lets load it
-            if (startPage === endPage) {
-                me.mask();
-                me.prefetchPage(startPage, {
-                    //blocking: true,
-                    callback: me.onWaitForGuarantee,
-                    scope: me
-                });
-            // need to load two pages
-            } else {
-                me.mask();
-                me.prefetchPage(startPage, {
-                    //blocking: true,
-                    callback: me.onWaitForGuarantee,
-                    scope: me
-                });
-                me.prefetchPage(endPage, {
-                    //blocking: true,
-                    callback: me.onWaitForGuarantee,
-                    scope: me
-                });
+    // @private modifies the store and creates the labels for the axes.
+    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;
             }
-        // Request was already satisfied via the prefetch
-        } else {
-            me.onGuaranteedRange();
-        }
-    },
-    
-    // because prefetchData is stored by index
-    // this invalidates all of the prefetchedData
-    sort: function() {
-        var me = this,
-            prefetchData = me.prefetchData,
-            sorters,
-            start,
-            end,
-            range;
-            
-        if (me.buffered) {
-            if (me.remoteSort) {
-                prefetchData.clear();
-                me.callParent(arguments);
-            } else {
-                sorters = me.getSorters();
-                start = me.guaranteedStart;
-                end = me.guaranteedEnd;
-                
-                if (sorters.length) {
-                    prefetchData.sort(sorters);
-                    range = prefetchData.getRange();
-                    prefetchData.clear();
-                    me.cacheRecords(range);
-                    delete me.guaranteedStart;
-                    delete me.guaranteedEnd;
-                    me.guaranteeRange(start, end);
-                }
-                me.callParent(arguments);
+            if (me.maximum) {
+                range.to = me.maximum;
             }
+            range.step = (range.to - range.from) / range.steps;
+            return range;
         } else {
-            me.callParent(arguments);
+            return me.callParent(arguments);
         }
-    },
+    }
+ });
 
-    // overriden to provide striping of the indexes as sorting occurs.
-    // this cannot be done inside of sort because datachanged has already
-    // fired and will trigger a repaint of the bound view.
-    doSort: function(sorterFn) {
-        var me = this;
-        if (me.remoteSort) {
-            //the load function will pick up the new sorters and request the sorted data from the proxy
-            me.load();
-        } else {
-            me.data.sortBy(sorterFn);
-            if (!me.buffered) {
-                var range = me.getRange(),
-                    ln = range.length,
-                    i  = 0;
-                for (; i < ln; i++) {
-                    range[i].index = i;
-                }
-            }
-            me.fireEvent('datachanged', me);
-        }
-    },
-    
-    /**
-     * Finds the index of the first matching Record in this store by a specific field value.
-     * @param {String} fieldName The name of the Record field to test.
-     * @param {String/RegExp} value Either a string that the field value
-     * should begin with, or a RegExp to test against the field.
-     * @param {Number} startIndex (optional) The index to start searching at
-     * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
-     * @param {Boolean} caseSensitive (optional) True for case sensitive comparison
-     * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false.
-     * @return {Number} The matched index or -1
-     */
-    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;
+
+/**
+ * @class Ext.chart.series.Series
+ *
+ * Series is the abstract class containing the common logic to all chart series. Series includes
+ * methods from Labels, Highlights, Tips and Callouts mixins. This class implements the logic of handling
+ * mouse events, animating, hiding, showing all elements and returning the color of the series to be used as a legend item.
+ *
+ * ## Listeners
+ *
+ * The series class supports listeners via the Observable syntax. Some of these listeners are:
+ *
+ *  - `itemmouseup` When the user interacts with a marker.
+ *  - `itemmousedown` When the user interacts with a marker.
+ *  - `itemmousemove` When the user iteracts with a marker.
+ *  - `afterrender` Will be triggered when the animation ends or when the series has been rendered completely.
+ *
+ * For example:
+ *
+ *     series: [{
+ *             type: 'column',
+ *             axis: 'left',
+ *             listeners: {
+ *                     'afterrender': function() {
+ *                             console('afterrender');
+ *                     }
+ *             },
+ *             xField: 'category',
+ *             yField: 'data1'
+ *     }]
+ */
+Ext.define('Ext.chart.series.Series', {
+
+    /* Begin Definitions */
+
+    mixins: {
+        observable: 'Ext.util.Observable',
+        labels: 'Ext.chart.Label',
+        highlights: 'Ext.chart.Highlight',
+        tips: 'Ext.chart.Tip',
+        callouts: 'Ext.chart.Callout'
     },
 
+    /* End Definitions */
+
     /**
-     * Finds the first matching Record in this store by a specific field value.
-     * @param {String} fieldName The name of the Record field to test.
-     * @param {String/RegExp} value Either a string that the field value
-     * should begin with, or a RegExp to test against the field.
-     * @param {Number} startIndex (optional) The index to start searching at
-     * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
-     * @param {Boolean} caseSensitive (optional) True for case sensitive comparison
-     * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false.
-     * @return {Ext.data.Model} The matched record or null
+     * @cfg {Boolean/Object} highlight
+     * If set to `true` it will highlight the markers or the series when hovering
+     * with the mouse. This parameter can also be an object with the same style
+     * properties you would apply to a {@link Ext.draw.Sprite} to apply custom
+     * styles to markers and series.
      */
-    findRecord: function() {
-        var me = this,
-            index = me.find.apply(me, arguments);
-        return index !== -1 ? me.getAt(index) : null;
-    },
 
     /**
-     * @private
-     * Returns a filter function used to test a the given property's value. Defers most of the work to
-     * Ext.util.MixedCollection's createValueMatcher function
-     * @param {String} property The property to create the filter function for
-     * @param {String/RegExp} value The string/regex to compare the property value to
-     * @param {Boolean} anyMatch True if we don't care if the filter value is not the full value (defaults to false)
-     * @param {Boolean} caseSensitive True to create a case-sensitive regex (defaults to false)
-     * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false.
-     * Ignored if anyMatch is true.
+     * @cfg {Object} tips
+     * Add tooltips to the visualization's markers. The options for the tips are the
+     * same configuration used with {@link Ext.tip.ToolTip}. For example:
+     *
+     *     tips: {
+     *       trackMouse: true,
+     *       width: 140,
+     *       height: 28,
+     *       renderer: function(storeItem, item) {
+     *         this.setTitle(storeItem.get('name') + ': ' + storeItem.get('data1') + ' views');
+     *       }
+     *     },
      */
-    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]);
-        };
-    },
 
     /**
-     * Finds the index of the first matching Record in this store by a specific field value.
-     * @param {String} fieldName The name of the Record field to test.
-     * @param {Mixed} value The value to match the field against.
-     * @param {Number} startIndex (optional) The index to start searching at
-     * @return {Number} The matched index or -1
+     * @cfg {String} type
+     * The type of series. Set in subclasses.
      */
-    findExact: function(property, value, start) {
-        return this.data.findIndexBy(function(rec) {
-            return rec.get(property) === value;
-        },
-        this, start);
-    },
+    type: null,
 
     /**
-     * Find the index of the first matching Record in this Store by a function.
-     * If the function returns <tt>true</tt> it is considered a match.
-     * @param {Function} fn The function to be called. It will be passed the following parameters:<ul>
-     * <li><b>record</b> : Ext.data.Model<p class="sub-desc">The {@link Ext.data.Model record}
-     * to test for filtering. Access field values using {@link Ext.data.Model#get}.</p></li>
-     * <li><b>id</b> : Object<p class="sub-desc">The ID of the Record passed.</p></li>
-     * </ul>
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this Store.
-     * @param {Number} startIndex (optional) The index to start searching at
-     * @return {Number} The matched index or -1
+     * @cfg {String} title
+     * The human-readable name of the series.
      */
-    findBy: function(fn, scope, start) {
-        return this.data.findIndexBy(fn, scope, start);
-    },
+    title: null,
 
     /**
-     * Collects unique values for a particular dataIndex from this store.
-     * @param {String} dataIndex The property to collect
-     * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
-     * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
-     * @return {Array} An array of the unique values
-     **/
-    collect: function(dataIndex, allowNull, bypassFilter) {
-        var me = this,
-            data = (bypassFilter === true && me.snapshot) ? me.snapshot: me.data;
-
-        return data.collect(dataIndex, 'data', allowNull);
-    },
+     * @cfg {Boolean} showInLegend
+     * Whether to show this series in the legend.
+     */
+    showInLegend: true,
 
     /**
-     * Gets the number of cached records.
-     * <p>If using paging, this may not be the total size of the dataset. If the data object
-     * used by the Reader contains the dataset size, then the {@link #getTotalCount} function returns
-     * the dataset size.  <b>Note</b>: see the Important note in {@link #load}.</p>
-     * @return {Number} The number of Records in the Store's cache.
+     * @cfg {Function} renderer
+     * A function that can be overridden to set custom styling properties to each rendered element.
+     * Passes in (sprite, record, attributes, index, store) to the function.
      */
-    getCount: function() {
-        return this.data.length || 0;
+    renderer: function(sprite, record, attributes, index, store) {
+        return attributes;
     },
 
     /**
-     * Returns the total number of {@link Ext.data.Model Model} instances that the {@link Ext.data.proxy.Proxy Proxy}
-     * indicates exist. This will usually differ from {@link #getCount} when using paging - getCount returns the
-     * number of records loaded into the Store at the moment, getTotalCount returns the number of records that
-     * could be loaded into the Store if the Store contained all data
-     * @return {Number} The total number of Model instances available via the Proxy
+     * @cfg {Array} shadowAttributes
+     * An array with shadow attributes
      */
-    getTotalCount: function() {
-        return this.totalCount;
-    },
+    shadowAttributes: null,
+
+    //@private triggerdrawlistener flag
+    triggerAfterDraw: false,
 
     /**
-     * Get the Record at the specified index.
-     * @param {Number} index The index of the Record to find.
-     * @return {Ext.data.Model} The Record at the passed index. Returns undefined if not found.
+     * @cfg {Object} listeners
+     * An (optional) object with event callbacks. All event callbacks get the target *item* as first parameter. The callback functions are:
+     *
+     *  - itemmouseover
+     *  - itemmouseout
+     *  - itemmousedown
+     *  - itemmouseup
      */
-    getAt: function(index) {
-        return this.data.getAt(index);
-    },
 
+    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,
+
+            /**
+             * @event titlechange
+             * Fires when the series title is changed via {@link #setTitle}.
+             * @param {String} title The new title value
+             * @param {Number} index The index in the collection of titles
+             */
+            titlechange: true
+        });
+
+        me.mixins.observable.constructor.call(me, config);
+
+        me.on({
+            scope: me,
+            itemmouseover: me.onItemMouseOver,
+            itemmouseout: me.onItemMouseOut,
+            mouseleave: me.onMouseLeave
+        });
+    },
+    
     /**
-     * Returns a range of Records between specified indices.
-     * @param {Number} startIndex (optional) The starting index (defaults to 0)
-     * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
-     * @return {Ext.data.Model[]} An array of Records
+     * Iterate over each of the records for this series. The default implementation simply iterates
+     * through the entire data store, but individual series implementations can override this to
+     * provide custom handling, e.g. adding/removing records.
+     * @param {Function} fn The function to execute for each record.
+     * @param {Object} scope Scope for the fn.
      */
-    getRange: function(start, end) {
-        return this.data.getRange(start, end);
+    eachRecord: function(fn, scope) {
+        var chart = this.chart;
+        (chart.substore || chart.store).each(fn, scope);
     },
 
     /**
-     * Get the Record with the specified id.
-     * @param {String} id The id of the Record to find.
-     * @return {Ext.data.Model} The Record with the passed id. Returns undefined if not found.
+     * Return the number of records being displayed in this series. Defaults to the number of
+     * records in the store; individual series implementations can override to provide custom handling.
      */
-    getById: function(id) {
-        return (this.snapshot || this.data).findBy(function(record) {
-            return record.getId() === id;
-        });
+    getRecordCount: function() {
+        var chart = this.chart,
+            store = chart.substore || chart.store;
+        return store ? store.getCount() : 0;
     },
 
     /**
-     * Get the index within the cache of the passed Record.
-     * @param {Ext.data.Model} record The Ext.data.Model object to find.
-     * @return {Number} The index of the passed Record. Returns -1 if not found.
+     * Determines whether the series item at the given index has been excluded, i.e. toggled off in the legend.
+     * @param index
      */
-    indexOf: function(record) {
-        return this.data.indexOf(record);
+    isExcluded: function(index) {
+        var excludes = this.__excludes;
+        return !!(excludes && excludes[index]);
     },
 
+    // @private set the bbox and clipBox for the series
+    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;
 
-    /**
-     * Get the index within the entire dataset. From 0 to the totalCount.
-     * @param {Ext.data.Model} record The Ext.data.Model object to find.
-     * @return {Number} The index of the passed Record. Returns -1 if not found.
-     */
-    indexOfTotal: function(record) {
-        return record.index || this.indexOf(record);
+        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;
     },
 
-    /**
-     * Get the index within the cache of the Record with the passed id.
-     * @param {String} id The id of the Record to find.
-     * @return {Number} The index of the Record. Returns -1 if not found.
-     */
-    indexOfId: function(id) {
-        return this.data.indexOfKey(id);
-    },
-        
-    /**
-     * Remove all items from the store.
-     * @param {Boolean} silent Prevent the `clear` event from being fired.
-     */
-    removeAll: function(silent) {
+    // @private set the animation for the sprite
+    onAnimate: function(sprite, attr) {
         var me = this;
+        sprite.stopAnimation();
+        if (me.triggerAfterDraw) {
+            return sprite.animate(Ext.applyIf(attr, me.chart.animate));
+        } else {
+            me.triggerAfterDraw = true;
+            return sprite.animate(Ext.apply(Ext.applyIf(attr, me.chart.animate), {
+                listeners: {
+                    'afteranimate': function() {
+                        me.triggerAfterDraw = false;
+                        me.fireEvent('afterrender');
+                    }
+                }
+            }));
+        }
+    },
 
-        me.clearData();
-        if (me.snapshot) {
-            me.snapshot.clear();
+    // @private return the gutter.
+    getGutters: function() {
+        return [0, 0];
+    },
+
+    // @private wrapper for the itemmouseover event.
+    onItemMouseOver: function(item) {
+        var me = this;
+        if (item.series === me) {
+            if (me.highlight) {
+                me.highlightItem(item);
+            }
+            if (me.tooltip) {
+                me.showTip(item);
+            }
         }
-        if (silent !== true) {
-            me.fireEvent('clear', me);
+    },
+
+    // @private wrapper for the itemmouseout event.
+    onItemMouseOut: function(item) {
+        var me = this;
+        if (item.series === me) {
+            me.unHighlightItem();
+            if (me.tooltip) {
+                me.hideTip(item);
+            }
         }
     },
 
-    /*
-     * Aggregation methods
-     */
+    // @private wrapper for the mouseleave event.
+    onMouseLeave: function() {
+        var me = this;
+        me.unHighlightItem();
+        if (me.tooltip) {
+            me.hideTip();
+        }
+    },
 
     /**
-     * Convenience function for getting the first model instance in the store
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the first record being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @return {Ext.data.Model/undefined} The first model instance in the store, or undefined
+     * For a given x/y point relative to the Surface, find a corresponding item from this
+     * series, if any.
+     * @param {Number} x
+     * @param {Number} y
+     * @return {Object} An object describing the item, or null if there is no matching item.
+     * The exact contents of this object will vary by series type, but should always contain the following:
+     * @return {Ext.chart.series.Series} return.series the Series object to which the item belongs
+     * @return {Object} return.value the value(s) of the item's data point
+     * @return {Array} return.point the x/y coordinates relative to the chart box of a single point
+     * for this data item, which can be used as e.g. a tooltip anchor point.
+     * @return {Ext.draw.Sprite} return.sprite the item's rendering Sprite.
      */
-    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();
+    getItemForPoint: function(x, y) {
+        //if there are no items to query just return null.
+        if (!this.items || !this.items.length || this.seriesIsHidden) {
+            return null;
+        }
+        var me = this,
+            items = me.items,
+            bbox = me.bbox,
+            item, i, ln;
+        // Check bounds
+        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;
     },
 
     /**
-     * Convenience function for getting the last model instance in the store
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the last record being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @return {Ext.data.Model/undefined} The last model instance in the store, or undefined
+     * Hides all the elements in the series.
      */
-    last: function(grouped) {
-        var me = this;
+    hideAll: function() {
+        var me = this,
+            items = me.items,
+            item, len, i, j, l, sprite, shadows;
 
-        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();
+        me.seriesIsHidden = true;
+        me._prevShowMarkers = me.showMarkers;
+
+        me.showMarkers = false;
+        //hide all labels
+        me.hideLabels(0);
+        //hide all sprites
+        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);
+                }
+            }
         }
     },
 
     /**
-     * Sums the value of <tt>property</tt> for each {@link Ext.data.Model record} between <tt>start</tt>
-     * and <tt>end</tt> and returns the result.
-     * @param {String} field A field in each record
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the sum for that group being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @return {Number} The sum
+     * Shows all the elements in the series.
      */
-    sum: function(field, grouped) {
-        var me = this;
+    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;
+    },
 
-        if (grouped && me.isGrouped()) {
-            return me.aggregate(me.getSum, me, true, [field]);
-        } else {
-            return me.getSum(me.data.items, field);
+    /**
+     * Returns a string with the color to be used for the series legend item.
+     */
+    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;
+            }
+            return stroke;
         }
+        return '#000';
     },
 
-    // @private, see sum
-    getSum: function(records, field) {
-        var total = 0,
-            i = 0,
-            len = records.length;
-
-        for (; i < len; ++i) {
-            total += records[i].get(field);
+    /**
+     * Checks whether the data field should be visible in the legend
+     * @private
+     * @param {Number} index The index of the current item
+     */
+    visibleInLegend: function(index){
+        var excludes = this.__excludes;
+        if (excludes) {
+            return !excludes[index];
         }
-
-        return total;
+        return !this.seriesIsHidden;
     },
 
     /**
-     * Gets the count of items in the store.
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the count for each group being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @return {Number} the count
+     * Changes the value of the {@link #title} for the series.
+     * Arguments can take two forms:
+     * <ul>
+     * <li>A single String value: this will be used as the new single title for the series (applies
+     * to series with only one yField)</li>
+     * <li>A numeric index and a String value: this will set the title for a single indexed yField.</li>
+     * </ul>
+     * @param {Number} index
+     * @param {String} title
      */
-    count: function(grouped) {
-        var me = this;
+    setTitle: function(index, title) {
+        var me = this,
+            oldTitle = me.title;
 
-        if (grouped && me.isGrouped()) {
-            return me.aggregate(function(records) {
-                return records.length;
-            }, me, true);
+        if (Ext.isString(index)) {
+            title = index;
+            index = 0;
+        }
+
+        if (Ext.isArray(oldTitle)) {
+            oldTitle[index] = title;
         } else {
-            return me.getCount();
+            me.title = title;
         }
-    },
+
+        me.fireEvent('titlechange', title, index);
+    }
+});
+
+/**
+ * @class Ext.chart.series.Cartesian
+ * @extends Ext.chart.series.Series
+ *
+ * Common base class for series implementations which plot values using x/y coordinates.
+ */
+Ext.define('Ext.chart.series.Cartesian', {
+
+    /* Begin Definitions */
+
+    extend: 'Ext.chart.series.Series',
+
+    alternateClassName: ['Ext.chart.CartesianSeries', 'Ext.chart.CartesianChart'],
+
+    /* End Definitions */
 
     /**
-     * Gets the minimum value in the store.
-     * @param {String} field The field in each record
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the minimum in the group being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @return {Mixed/undefined} The minimum value, if no items exist, undefined.
+     * The field used to access the x axis value from the items from the data
+     * source.
+     *
+     * @cfg xField
+     * @type String
      */
-    min: function(field, grouped) {
-        var me = this;
+    xField: null,
 
-        if (grouped && me.isGrouped()) {
-            return me.aggregate(me.getMin, me, true, [field]);
-        } else {
-            return me.getMin(me.data.items, field);
-        }
-    },
+    /**
+     * The field used to access the y-axis value from the items from the data
+     * source.
+     *
+     * @cfg yField
+     * @type String
+     */
+    yField: null,
+
+    /**
+     * @cfg {String} axis
+     * The position of the axis to bind the values to. Possible values are 'left', 'bottom', 'top' and 'right'.
+     * You must explicitly set this value to bind the values of the line series to the ones in the axis, otherwise a
+     * relative scale will be used.
+     */
+    axis: 'left',
 
-    // @private, see min
-    getMin: function(records, field){
-        var i = 1,
-            len = records.length,
-            value, min;
+    getLegendLabels: function() {
+        var me = this,
+            labels = [],
+            combinations = me.combinations;
 
-        if (len > 0) {
-            min = records[0].get(field);
-        }
+        Ext.each([].concat(me.yField), function(yField, i) {
+            var title = me.title;
+            // Use the 'title' config if present, otherwise use the raw yField name
+            labels.push((Ext.isArray(title) ? title[i] : title) || yField);
+        });
 
-        for (; i < len; ++i) {
-            value = records[i].get(field);
-            if (value < min) {
-                min = value;
-            }
+        // Handle yFields combined via legend drag-drop
+        if (combinations) {
+            Ext.each(combinations, function(combo) {
+                var label0 = labels[combo[0]],
+                    label1 = labels[combo[1]];
+                labels[combo[1]] = label0 + ' & ' + label1;
+                labels.splice(combo[0], 1);
+            });
         }
-        return min;
+
+        return labels;
     },
 
     /**
-     * Gets the maximum value in the store.
-     * @param {String} field The field in each record
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the maximum in the group being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @return {Mixed/undefined} The maximum value, if no items exist, undefined.
+     * @protected Iterates over a given record's values for each of this series's yFields,
+     * executing a given function for each value. Any yFields that have been combined
+     * via legend drag-drop will be treated as a single value.
+     * @param {Ext.data.Model} record
+     * @param {Function} fn
+     * @param {Object} scope
      */
-    max: function(field, grouped) {
-        var me = this;
+    eachYValue: function(record, fn, scope) {
+        Ext.each(this.getYValueAccessors(), function(accessor, i) {
+            fn.call(scope, accessor(record), i);
+        });
+    },
 
-        if (grouped && me.isGrouped()) {
-            return me.aggregate(me.getMax, me, true, [field]);
-        } else {
-            return me.getMax(me.data.items, field);
-        }
+    /**
+     * @protected Returns the number of yField values, taking into account fields combined
+     * via legend drag-drop.
+     * @return {Number}
+     */
+    getYValueCount: function() {
+        return this.getYValueAccessors().length;
     },
 
-    // @private, see max
-    getMax: function(records, field) {
-        var i = 1,
-            len = records.length,
-            value,
-            max;
+    combine: function(index1, index2) {
+        var me = this,
+            accessors = me.getYValueAccessors(),
+            accessor1 = accessors[index1],
+            accessor2 = accessors[index2];
 
-        if (len > 0) {
-            max = records[0].get(field);
-        }
+        // Combine the yValue accessors for the two indexes into a single accessor that returns their sum
+        accessors[index2] = function(record) {
+            return accessor1(record) + accessor2(record);
+        };
+        accessors.splice(index1, 1);
 
-        for (; i < len; ++i) {
-            value = records[i].get(field);
-            if (value > max) {
-                max = value;
-            }
-        }
-        return max;
+        me.callParent([index1, index2]);
+    },
+
+    clearCombinations: function() {
+        // Clear combined accessors, they'll get regenerated on next call to getYValueAccessors
+        delete this.yValueAccessors;
+        this.callParent();
     },
 
     /**
-     * Gets the average value in the store.
-     * @param {String} field The field in each record
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the group average being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @return {Mixed/undefined} The average value, if no items exist, 0.
+     * @protected Returns an array of functions, each of which returns the value of the yField
+     * corresponding to function's index in the array, for a given record (each function takes the
+     * record as its only argument.) If yFields have been combined by the user via legend drag-drop,
+     * this list of accessors will be kept in sync with those combinations.
+     * @return {Array} array of accessor functions
      */
-    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);
+    getYValueAccessors: function() {
+        var me = this,
+            accessors = me.yValueAccessors;
+        if (!accessors) {
+            accessors = me.yValueAccessors = [];
+            Ext.each([].concat(me.yField), function(yField) {
+                accessors.push(function(record) {
+                    return record.get(yField);
+                });
+            });
         }
+        return accessors;
     },
 
-    // @private, see average
-    getAverage: function(records, field) {
-        var i = 0,
-            len = records.length,
-            sum = 0;
+    /**
+     * Calculate the min and max values for this series's xField.
+     * @return {Array} [min, max]
+     */
+    getMinMaxXValues: function() {
+        var me = this,
+            min, max,
+            xField = me.xField;
 
-        if (records.length > 0) {
-            for (; i < len; ++i) {
-                sum += records[i].get(field);
-            }
-            return sum / len;
+        if (me.getRecordCount() > 0) {
+            min = Infinity;
+            max = -min;
+            me.eachRecord(function(record) {
+                var xValue = record.get(xField);
+                if (xValue > max) {
+                    max = xValue;
+                }
+                if (xValue < min) {
+                    min = xValue;
+                }
+            });
+        } else {
+            min = max = 0;
         }
-        return 0;
+        return [min, max];
     },
 
     /**
-     * Runs the aggregate function for all the records in the store.
-     * @param {Function} fn The function to execute. The function is called with a single parameter,
-     * an array of records for that group.
-     * @param {Object} scope (optional) The scope to execute the function in. Defaults to the store.
-     * @param {Boolean} grouped (Optional) True to perform the operation for each group
-     * in the store. The value returned will be an object literal with the key being the group
-     * name and the group average being the value. The grouped parameter is only honored if
-     * the store has a groupField.
-     * @param {Array} args (optional) Any arguments to append to the function call
-     * @return {Object} An object literal with the group names and their appropriate values.
+     * Calculate the min and max values for this series's yField(s). Takes into account yField
+     * combinations, exclusions, and stacking.
+     * @return {Array} [min, max]
      */
-    aggregate: function(fn, scope, grouped, args) {
-        args = args || [];
-        if (grouped && this.isGrouped()) {
-            var groups = this.getGroups(),
-                i = 0,
-                len = groups.length,
-                out = {},
-                group;
+    getMinMaxYValues: function() {
+        var me = this,
+            stacked = me.stacked,
+            min, max,
+            positiveTotal, negativeTotal;
 
-            for (; i < len; ++i) {
-                group = groups[i];
-                out[group.name] = fn.apply(scope || this, [group.children].concat(args));
+        function eachYValueStacked(yValue, i) {
+            if (!me.isExcluded(i)) {
+                if (yValue < 0) {
+                    negativeTotal += yValue;
+                } else {
+                    positiveTotal += yValue;
+                }
             }
-            return out;
-        } else {
-            return fn.apply(scope || this, [this.data.items].concat(args));
         }
-    }
-});
 
-/**
- * @author Ed Spencer
- * @class Ext.data.JsonStore
- * @extends Ext.data.Store
- * @ignore
- *
- * <p>Small helper class to make creating {@link Ext.data.Store}s from JSON data easier.
- * A JsonStore will be automatically configured with a {@link Ext.data.reader.Json}.</p>
- *
- * <p>A store configuration would be something like:</p>
- *
-<pre><code>
-var store = new Ext.data.JsonStore({
-    // store configs
-    autoDestroy: true,
-    storeId: 'myStore'
+        function eachYValue(yValue, i) {
+            if (!me.isExcluded(i)) {
+                if (yValue > max) {
+                    max = yValue;
+                }
+                if (yValue < min) {
+                    min = yValue;
+                }
+            }
+        }
 
-    proxy: {
-        type: 'ajax',
-        url: 'get-images.php',
-        reader: {
-            type: 'json',
-            root: 'images',
-            idProperty: 'name'
+        if (me.getRecordCount() > 0) {
+            min = Infinity;
+            max = -min;
+            me.eachRecord(function(record) {
+                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];
     },
 
-    //alternatively, a {@link Ext.data.Model} name can be given (see {@link Ext.data.Store} for an example)
-    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
-});
-</code></pre>
- *
- * <p>This store is configured to consume a returned object of the form:<pre><code>
-{
-    images: [
-        {name: 'Image one', url:'/GetImage.php?id=1', size:46.5, lastmod: new Date(2007, 10, 29)},
-        {name: 'Image Two', url:'/GetImage.php?id=2', size:43.2, lastmod: new Date(2007, 10, 30)}
-    ]
-}
-</code></pre>
- *
- * <p>An object literal of this form could also be used as the {@link #data} config option.</p>
- *
- * @xtype jsonstore
- */
-Ext.define('Ext.data.JsonStore',  {
-    extend: 'Ext.data.Store',
-    alias: 'store.json',
+    getAxesForXAndYFields: function() {
+        var me = this,
+            axes = me.chart.axes,
+            axis = [].concat(me.axis),
+            xAxis, yAxis;
 
-    /**
-     * @cfg {Ext.data.DataReader} reader @hide
-     */
-    constructor: function(config) {
-        config = config || {};
+        if (Ext.Array.indexOf(axis, 'top') > -1) {
+            xAxis = 'top';
+        } else if (Ext.Array.indexOf(axis, 'bottom') > -1) {
+            xAxis = 'bottom';
+        } else {
+            if (axes.get('top')) {
+                xAxis = 'top';
+            } else if (axes.get('bottom')) {
+                xAxis = 'bottom';
+            }
+        }
 
-        Ext.applyIf(config, {
-            proxy: {
-                type  : 'ajax',
-                reader: 'json',
-                writer: 'json'
+        if (Ext.Array.indexOf(axis, 'left') > -1) {
+            yAxis = 'left';
+        } else if (Ext.Array.indexOf(axis, 'right') > -1) {
+            yAxis = 'right';
+        } else {
+            if (axes.get('left')) {
+                yAxis = 'left';
+            } else if (axes.get('right')) {
+                yAxis = 'right';
             }
-        });
+        }
 
-        this.callParent([config]);
+        return {
+            xAxis: xAxis,
+            yAxis: yAxis
+        };
     }
+
+
 });
 
 /**
- * @class Ext.chart.axis.Time
- * @extends Ext.chart.axis.Axis
+ * @class Ext.chart.series.Area
+ * @extends Ext.chart.series.Cartesian
  *
- * A type of axis whose units are measured in time values. Use this axis
- * for listing dates that you will want to group or dynamically change.
- * If you just want to display dates as categories then use the
- * Category class for axis instead.
+ * Creates a Stacked Area Chart. The stacked area chart is useful when displaying multiple aggregated layers of information.
+ * As with all other series, the Area Series must be appended in the *series* Chart array configuration. See the Chart
+ * documentation for more information. A typical configuration object for the area series could be:
  *
- * For example:
+ *     @example
+ *     var store = Ext.create('Ext.data.JsonStore', {
+ *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
+ *         data: [
+ *             { 'name': 'metric one',   'data1':10, 'data2':12, 'data3':14, 'data4':8,  'data5':13 },
+ *             { 'name': 'metric two',   'data1':7,  'data2':8,  'data3':16, 'data4':10, 'data5':3  },
+ *             { 'name': 'metric three', 'data1':5,  'data2':2,  'data3':14, 'data4':12, 'data5':7  },
+ *             { 'name': 'metric four',  'data1':2,  'data2':14, 'data3':6,  'data4':1,  'data5':23 },
+ *             { 'name': 'metric five',  'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33 }
+ *         ]
+ *     });
  *
- *     axes: [{
- *         type: 'Time',
- *         position: 'bottom',
- *         fields: 'date',
- *         title: 'Day',
- *         dateFormat: 'M d',
- *         groupBy: 'year,month,day',
- *         aggregateOp: 'sum',
- *     
- *         constrain: true,
- *         fromDate: new Date('1/1/11'),
- *         toDate: new Date('1/7/11')
- *     }]
+ *     Ext.create('Ext.chart.Chart', {
+ *         renderTo: Ext.getBody(),
+ *         width: 500,
+ *         height: 300,
+ *         store: store,
+ *         axes: [
+ *             {
+ *                 type: 'Numeric',
+ *                 grid: true,
+ *                 position: 'left',
+ *                 fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *                 title: 'Sample Values',
+ *                 grid: {
+ *                     odd: {
+ *                         opacity: 1,
+ *                         fill: '#ddd',
+ *                         stroke: '#bbb',
+ *                         'stroke-width': 1
+ *                     }
+ *                 },
+ *                 minimum: 0,
+ *                 adjustMinimumByMajorUnit: 0
+ *             },
+ *             {
+ *                 type: 'Category',
+ *                 position: 'bottom',
+ *                 fields: ['name'],
+ *                 title: 'Sample Metrics',
+ *                 grid: true,
+ *                 label: {
+ *                     rotate: {
+ *                         degrees: 315
+ *                     }
+ *                 }
+ *             }
+ *         ],
+ *         series: [{
+ *             type: 'area',
+ *             highlight: false,
+ *             axis: 'left',
+ *             xField: 'name',
+ *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *             style: {
+ *                 opacity: 0.93
+ *             }
+ *         }]
+ *     });
  *
- * In this example we're creating a time axis that has as title *Day*.
- * The field the axis is bound to is `date`.
- * The date format to use to display the text for the axis labels is `M d`
- * which is a three letter month abbreviation followed by the day number.
- * The time axis will show values for dates between `fromDate` and `toDate`.
- * Since `constrain` is set to true all other values for other dates not between
- * the fromDate and toDate will not be displayed.
- * 
+ * In this configuration we set `area` as the type for the series, set highlighting options to true for highlighting elements on hover,
+ * take the left axis to measure the data in the area series, set as xField (x values) the name field of each element in the store,
+ * and as yFields (aggregated layers) seven data fields from the same store. Then we override some theming styles by adding some opacity
+ * to the style object.
+ *
+ * @xtype area
  */
-Ext.define('Ext.chart.axis.Time', {
+Ext.define('Ext.chart.series.Area', {
 
     /* Begin Definitions */
 
-    extend: 'Ext.chart.axis.Category',
-
-    alternateClassName: 'Ext.chart.TimeAxis',
+    extend: 'Ext.chart.series.Cartesian',
 
-    alias: 'axis.time',
+    alias: 'series.area',
 
-    requires: ['Ext.data.Store', 'Ext.data.JsonStore'],
+    requires: ['Ext.chart.axis.Axis', 'Ext.draw.Color', 'Ext.fx.Anim'],
 
     /* End Definitions */
 
-     /**
-      * The minimum value drawn by the axis. If not set explicitly, the axis
-      * minimum will be calculated automatically.
-      * @property calculateByLabelSize
-      * @type Boolean
-      */
-    calculateByLabelSize: true,
-    
-     /**
-     * Indicates the format the date will be rendered on. 
-     * For example: 'M d' will render the dates as 'Jan 30', etc.
-      *
-     * @property dateFormat
-     * @type {String|Boolean}
-      */
-    dateFormat: false,
-    
-     /**
-     * Indicates the time unit to use for each step. Can be 'day', 'month', 'year' or a comma-separated combination of all of them.
-     * Default's 'year,month,day'.
-     *
-     * @property timeUnit
-     * @type {String}
-     */
-    groupBy: 'year,month,day',
-    
-    /**
-     * Aggregation operation when grouping. Possible options are 'sum', 'avg', 'max', 'min'. Default's 'sum'.
-     * 
-     * @property aggregateOp
-     * @type {String}
-      */
-    aggregateOp: 'sum',
-    
-    /**
-     * The starting date for the time axis.
-     * @property fromDate
-     * @type Date
-     */
-    fromDate: false,
-    
-    /**
-     * The ending date for the time axis.
-     * @property toDate
-     * @type Date
-     */
-    toDate: false,
-    
-    /**
-     * An array with two components: The first is the unit of the step (day, month, year, etc). The second one is the number of units for the step (1, 2, etc.).
-     * Default's [Ext.Date.DAY, 1].
-     * 
-     * @property step 
-     * @type Array
-     */
-    step: [Ext.Date.DAY, 1],
-    
+    type: 'area',
+
+    // @private Area charts are alyways stacked
+    stacked: true,
+
     /**
-     * If true, the values of the chart will be rendered only if they belong between the fromDate and toDate. 
-     * If false, the time axis will adapt to the new values by adding/removing steps.
-     * Default's [Ext.Date.DAY, 1].
-     * 
-     * @property constrain 
-     * @type Boolean
+     * @cfg {Object} style
+     * Append styling properties to this object for it to override theme properties.
      */
-    constrain: false,
-    
-    // @private a wrapper for date methods.
-    dateMethods: {
-        'year': function(date) {
-            return date.getFullYear();
-        },
-        'month': function(date) {
-            return date.getMonth() + 1;
-        },
-        'day': function(date) {
-            return date.getDate();
-        },
-        'hour': function(date) {
-            return date.getHours();
-        },
-        'minute': function(date) {
-            return date.getMinutes();
-        },
-        'second': function(date) {
-            return date.getSeconds();
-        },
-        'millisecond': function(date) {
-            return date.getMilliseconds();
+    style: {},
+
+    constructor: function(config) {
+        this.callParent(arguments);
+        var me = this,
+            surface = me.chart.surface,
+            i, l;
+        Ext.apply(me, config, {
+            __excludes: [],
+            highlightCfg: {
+                lineWidth: 3,
+                stroke: '#55c',
+                opacity: 0.8,
+                color: '#f00'
+            }
+        });
+        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);
     },
-    
-    // @private holds aggregate functions.
-    aggregateFn: (function() {
-        var etype = (function() {
-            var rgxp = /^\[object\s(.*)\]$/,
-                toString = Object.prototype.toString;
-            return function(e) {
-                return toString.call(e).match(rgxp)[1];
-            };
-        })();
-        return {
-            'sum': function(list) {
-                var i = 0, l = list.length, acum = 0;
-                if (!list.length || etype(list[0]) != 'Number') {
-                    return list[0];
+
+    // @private Shrinks dataSets down to a smaller size
+    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 = [];
+        //initialize array
+        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) {
+                //push averages
+                xRes.push(xSum/ratio);
+                for (j = 0; j < yCompLen; ++j) {
+                    ySum[j] /= ratio;
                 }
-                for (; i < l; i++) {
-                    acum += list[i];
+                yRes.push(ySum);
+                //reset sum accumulators
+                xSum = 0;
+                for (j = 0, ySum = []; j < yCompLen; ++j) {
+                    ySum[j] = 0;
                 }
-                return acum;
-            },
-            'max': function(list) {
-                if (!list.length || etype(list[0]) != 'Number') {
-                    return list[0];
+            }
+        }
+        return {
+            x: xRes,
+            y: yRes
+        };
+    },
+
+    // @private Get chart and data boundaries
+    getBounds: function() {
+        var me = this,
+            chart = me.chart,
+            store = chart.getChartStore(),
+            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,
+            bbox, xScale, yScale, xValue, yValue, areaIndex, acumY, ln, sumValues, clipBox, areaElem;
+
+        me.setBBox();
+        bbox = me.bbox;
+
+        // Run through the axis
+        if (me.axis) {
+            axis = chart.axes.get(me.axis);
+            if (axis) {
+                out = axis.calcEnds();
+                minY = out.from || axis.prevMin;
+                maxY = mmax(out.to || axis.prevMax, 0);
+            }
+        }
+
+        if (me.yField && !Ext.isNumber(minY)) {
+            axis = Ext.create('Ext.chart.axis.Axis', {
+                chart: chart,
+                fields: [].concat(me.yField)
+            });
+            out = axis.calcEnds();
+            minY = out.from || axis.prevMin;
+            maxY = mmax(out.to || axis.prevMax, 0);
+        }
+
+        if (!Ext.isNumber(minY)) {
+            minY = 0;
+        }
+        if (!Ext.isNumber(maxY)) {
+            maxY = 0;
+        }
+
+        store.each(function(record, i) {
+            xValue = record.get(me.xField);
+            yValue = [];
+            if (typeof xValue != 'number') {
+                xValue = i;
+            }
+            xValues.push(xValue);
+            acumY = 0;
+            for (areaIndex = 0; areaIndex < areasLen; areaIndex++) {
+                areaElem = record.get(areas[areaIndex]);
+                if (typeof areaElem == 'number') {
+                    minY = mmin(minY, areaElem);
+                    yValue.push(areaElem);
+                    acumY += areaElem;
+                }
+            }
+            minX = mmin(minX, xValue);
+            maxX = mmax(maxX, xValue);
+            maxY = mmax(maxY, acumY);
+            yValues.push(yValue);
+        }, me);
+
+        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
+        };
+    },
+
+    // @private Build an array of paths for the chart
+    getPaths: function() {
+        var me = this,
+            chart = me.chart,
+            store = chart.getChartStore(),
+            first = true,
+            bounds = me.getBounds(),
+            bbox = bounds.bbox,
+            items = me.items = [],
+            componentPaths = [],
+            componentPath,
+            paths = [],
+            i, ln, x, y, xValue, yValue, acumY, areaIndex, prevAreaIndex, areaElem, path;
+
+        ln = bounds.xValues.length;
+        // Start the path
+        for (i = 0; i < ln; i++) {
+            xValue = bounds.xValues[i];
+            yValue = bounds.yValues[i];
+            x = bbox.x + (xValue - bounds.minX) * bounds.xScale;
+            acumY = 0;
+            for (areaIndex = 0; areaIndex < bounds.areasLen; areaIndex++) {
+                // Excluded series
+                if (me.__excludes[areaIndex]) {
+                    continue;
                 }
-                return Math.max.apply(Math, list);
-            },
-            'min': function(list) {
-                if (!list.length || etype(list[0]) != 'Number') {
-                    return list[0];
+                if (!componentPaths[areaIndex]) {
+                    componentPaths[areaIndex] = [];
                 }
-                return Math.min.apply(Math, list);
-            },
-            'avg': function(list) {
-                var i = 0, l = list.length, acum = 0;
-                if (!list.length || etype(list[0]) != 'Number') {
-                    return list[0];
+                areaElem = yValue[areaIndex];
+                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]);
                 }
-                for (; i < l; i++) {
-                    acum += list[i];
+                if (!items[areaIndex]) {
+                    items[areaIndex] = {
+                        pointsUp: [],
+                        pointsDown: [],
+                        series: me
+                    };
                 }
-                return acum / l;
+                items[areaIndex].pointsUp.push([x, y]);
             }
-        };
-    })(),
-    
-    // @private normalized the store to fill date gaps in the time interval.
-    constrainDates: function() {
-        var fromDate = Ext.Date.clone(this.fromDate),
-            toDate = Ext.Date.clone(this.toDate),
-            step = this.step,
-            field = this.fields,
-            store = this.chart.store,
-            record, recObj, fieldNames = [],
-            newStore = Ext.create('Ext.data.Store', {
-                model: store.model
-            });
-        
-        var getRecordByDate = (function() {
-            var index = 0, l = store.getCount();
-            return function(date) {
-                var rec, recDate;
-                for (; index < l; index++) {
-                    rec = store.getAt(index);
-                    recDate = rec.get(field);
-                    if (+recDate > +date) {
-                        return false;
-                    } else if (+recDate == +date) {
-                        return rec;
-                    }
-                }
-                return false;
-            };
-        })();
-        
-        if (!this.constrain) {
-            this.chart.filteredStore = this.chart.store;
-            return;
         }
 
-        while(+fromDate <= +toDate) {
-            record = getRecordByDate(fromDate);
-            recObj = {};
-            if (record) {
-                newStore.add(record.data);
-            } else {
-                newStore.model.prototype.fields.each(function(f) {
-                    recObj[f.name] = false;
-                });
-                recObj.date = fromDate;
-                newStore.add(recObj);
-            }
-            fromDate = Ext.Date.add(fromDate, step[0], step[1]);
-        }
-         
-        this.chart.filteredStore = newStore;
-    },
-    
-    // @private aggregates values if multiple store elements belong to the same time step.
-    aggregate: function() {
-        var aggStore = {}, 
-            aggKeys = [], key, value,
-            op = this.aggregateOp,
-            field = this.fields, i,
-            fields = this.groupBy.split(','),
-            curField,
-            recFields = [],
-            recFieldsLen = 0,
-            obj,
-            dates = [],
-            json = [],
-            l = fields.length,
-            dateMethods = this.dateMethods,
-            aggregateFn = this.aggregateFn,
-            store = this.chart.filteredStore || this.chart.store;
-        
-        store.each(function(rec) {
-            //get all record field names in a simple array
-            if (!recFields.length) {
-                rec.fields.each(function(f) {
-                    recFields.push(f.name);
-                });
-                recFieldsLen = recFields.length;
-            }
-            //get record date value
-            value = rec.get(field);
-            //generate key for grouping records
-            for (i = 0; i < l; i++) {
-                if (i == 0) {
-                    key = String(dateMethods[fields[i]](value));
-                } else {
-                    key += '||' + dateMethods[fields[i]](value);
-                }
+        // Close the paths
+        for (areaIndex = 0; areaIndex < bounds.areasLen; areaIndex++) {
+            // Excluded series
+            if (me.__excludes[areaIndex]) {
+                continue;
             }
-            //get aggregation record from hash
-            if (key in aggStore) {
-                obj = aggStore[key];
-            } else {
-                obj = aggStore[key] = {};
-                aggKeys.push(key);
-                dates.push(value);
+            path = paths[areaIndex];
+            // Close bottom path to the axis
+            if (areaIndex == 0 || first) {
+                first = false;
+                path.push('L', x, bbox.y + bbox.height,
+                          'L', bbox.x, bbox.y + bbox.height,
+                          'Z');
             }
-            //append record values to an aggregation record
-            for (i = 0; i < recFieldsLen; i++) {
-                curField = recFields[i];
-                if (!obj[curField]) {
-                    obj[curField] = [];
-                }
-                if (rec.get(curField) !== undefined) {
-                    obj[curField].push(rec.get(curField));
+            // Close other paths to the one before them
+            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');
             }
-        });
-        //perform aggregation operations on fields
-        for (key in aggStore) {
-            obj = aggStore[key];
-            for (i = 0; i < recFieldsLen; i++) {
-                curField = recFields[i];
-                obj[curField] = aggregateFn[op](obj[curField]);
-            }
-            json.push(obj);
-        }
-        this.chart.substore = Ext.create('Ext.data.JsonStore', {
-            fields: recFields,
-            data: json
-        });
-        
-        this.dates = dates;
-    },
-    
-    // @private creates a label array to be used as the axis labels.
-     setLabels: function() {
-        var store = this.chart.substore,
-            fields = this.fields,
-            format = this.dateFormat,
-            labels, i, dates = this.dates,
-            formatFn = Ext.Date.format;
-        this.labels = labels = [];
-        store.each(function(record, i) {
-            if (!format) {
-                labels.push(record.get(fields));
-            } else {
-                labels.push(formatFn(dates[i], format));
-            }
-         }, this);
-     },
-
-    processView: function() {
-         //TODO(nico): fix this eventually...
-         if (this.constrain) {
-             this.constrainDates();
-             this.aggregate();
-             this.chart.substore = this.chart.filteredStore;
-         } else {
-             this.aggregate();
-         }
-    },
-
-     // @private modifies the store and creates the labels for the axes.
-     applyData: function() {
-        this.setLabels();
-        var count = this.chart.substore.getCount();
-         return {
-             from: 0,
-             to: count,
-             steps: count - 1,
-             step: 1
-         };
-     }
- });
-
-
-/**
- * @class Ext.chart.series.Series
- * 
- * Series is the abstract class containing the common logic to all chart series. Series includes 
- * methods from Labels, Highlights, Tips and Callouts mixins. This class implements the logic of handling 
- * mouse events, animating, hiding, showing all elements and returning the color of the series to be used as a legend item.
- *
- * ## Listeners
- *
- * The series class supports listeners via the Observable syntax. Some of these listeners are:
- *
- *  - `itemmouseup` When the user interacts with a marker.
- *  - `itemmousedown` When the user interacts with a marker.
- *  - `itemmousemove` When the user iteracts with a marker.
- *  - `afterrender` Will be triggered when the animation ends or when the series has been rendered completely.
- *
- * For example:
- *
- *     series: [{
- *             type: 'column',
- *             axis: 'left',
- *             listeners: {
- *                     'afterrender': function() {
- *                             console('afterrender');
- *                     }
- *             },
- *             xField: 'category',
- *             yField: 'data1'
- *     }]
- *     
- */
-Ext.define('Ext.chart.series.Series', {
-
-    /* Begin Definitions */
-
-    mixins: {
-        observable: 'Ext.util.Observable',
-        labels: 'Ext.chart.Label',
-        highlights: 'Ext.chart.Highlight',
-        tips: 'Ext.chart.Tip',
-        callouts: 'Ext.chart.Callout'
+            prevAreaIndex = areaIndex;
+        }
+        return {
+            paths: paths,
+            areasLen: bounds.areasLen
+        };
     },
 
-    /* End Definitions */
-
-    /**
-     * @cfg {Boolean|Object} highlight
-     * If set to `true` it will highlight the markers or the series when hovering
-     * with the mouse. This parameter can also be an object with the same style
-     * properties you would apply to a {@link Ext.draw.Sprite} to apply custom
-     * styles to markers and series.
-     */
-
-    /**
-     * @cfg {Object} tips
-     * Add tooltips to the visualization's markers. The options for the tips are the
-     * same configuration used with {@link Ext.tip.ToolTip}. For example:
-     *
-     *     tips: {
-     *       trackMouse: true,
-     *       width: 140,
-     *       height: 28,
-     *       renderer: function(storeItem, item) {
-     *         this.setTitle(storeItem.get('name') + ': ' + storeItem.get('data1') + ' views');
-     *       }
-     *     },
-     */
-
-    /**
-     * @cfg {String} type
-     * The type of series. Set in subclasses.
-     */
-    type: null,
-
     /**
-     * @cfg {String} title
-     * The human-readable name of the series.
+     * Draws the series for the current chart.
      */
-    title: null,
+    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;
 
-    /**
-     * @cfg {Boolean} showInLegend
-     * Whether to show this series in the legend.
-     */
-    showInLegend: true,
+        me.unHighlightItem();
+        me.cleanHighlights();
 
-    /**
-     * @cfg {Function} renderer
-     * A function that can be overridden to set custom styling properties to each rendered element.
-     * Passes in (sprite, record, attributes, index, store) to the function.
-     */
-    renderer: function(sprite, record, attributes, index, store) {
-        return attributes;
-    },
+        if (!store || !store.getCount()) {
+            return;
+        }
 
-    /**
-     * @cfg {Array} shadowAttributes
-     * An array with shadow attributes
-     */
-    shadowAttributes: null,
-    
-    //@private triggerdrawlistener flag
-    triggerAfterDraw: false,
+        paths = me.getPaths();
 
-    /**
-     * @cfg {Object} listeners  
-     * An (optional) object with event callbacks. All event callbacks get the target *item* as first parameter. The callback functions are:
-     *  
-     *  <ul>
-     *      <li>itemmouseover</li>
-     *      <li>itemmouseout</li>
-     *      <li>itemmousedown</li>
-     *      <li>itemmouseup</li>
-     *  </ul>
-     */
-    
-    constructor: function(config) {
-        var me = this;
-        if (config) {
-            Ext.apply(me, config);
+        if (!me.areas) {
+            me.areas = [];
         }
-        
-        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,
+        for (areaIndex = 0; areaIndex < paths.areasLen; areaIndex++) {
+            // Excluded series
+            if (me.__excludes[areaIndex]) {
+                continue;
+            }
+            if (!me.areas[areaIndex]) {
+                me.items[areaIndex].sprite = me.areas[areaIndex] = surface.add(Ext.apply({}, {
+                    type: 'path',
+                    group: group,
+                    // 'clip-rect': me.clipBox,
+                    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) {
+                //Add renderer to line. There is not a unique record associated with this.
+                rendererAttributes = me.renderer(areaElem, false, {
+                    path: path,
+                    // 'clip-rect': me.clipBox,
+                    fill: colorArrayStyle[areaIndex % colorArrayLength],
+                    stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
+                }, areaIndex, store);
+                //fill should not be used here but when drawing the special fill path object
+                me.animation = me.onAnimate(areaElem, {
+                    to: rendererAttributes
+                });
+            } else {
+                rendererAttributes = me.renderer(areaElem, false, {
+                    path: path,
+                    // 'clip-rect': me.clipBox,
+                    hidden: false,
+                    fill: colorArrayStyle[areaIndex % colorArrayLength],
+                    stroke: endLineStyle.stroke || colorArrayStyle[areaIndex % colorArrayLength]
+                }, areaIndex, store);
+                me.areas[areaIndex].setAttributes(rendererAttributes, true);
+            }
+        }
+        me.renderLabels();
+        me.renderCallouts();
+    },
 
-            /**
-             * @event titlechange
-             * Fires when the series title is changed via {@link #setTitle}.
-             * @param {String} title The new title value
-             * @param {Number} index The index in the collection of titles
-             */
-            titlechange: true
-        });
+    // @private
+    onAnimate: function(sprite, attr) {
+        sprite.show();
+        return this.callParent(arguments);
+    },
 
-        me.mixins.observable.constructor.call(me, config);
+    // @private
+    onCreateLabel: function(storeItem, item, i, display) {
+        var me = this,
+            group = me.labelsGroup,
+            config = me.label,
+            bbox = me.bbox,
+            endLabelStyle = Ext.apply(config, me.seriesLabelStyle);
 
-        me.on({
-            scope: me,
-            itemmouseover: me.onItemMouseOver,
-            itemmouseout: me.onItemMouseOut,
-            mouseleave: me.onMouseLeave
-        });
+        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 || {}));
     },
 
-    // @private set the bbox and clipBox for the series
-    setBBox: function(noGutter) {
+    // @private
+    onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
         var me = this,
             chart = me.chart,
-            chartBBox = chart.chartBBox,
-            gutterX = noGutter ? 0 : chart.maxGutter[0],
-            gutterY = noGutter ? 0 : chart.maxGutter[1],
-            clipBox, bbox;
+            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;
 
-        clipBox = {
-            x: chartBBox.x,
-            y: chartBBox.y,
-            width: chartBBox.width,
-            height: chartBBox.height
-        };
-        me.clipBox = clipBox;
+        label.setAttributes({
+            text: format(storeItem.get(field[index])),
+            hidden: true
+        }, true);
 
-        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;
-    },
+        bb = label.getBBox();
+        width = bb.width / 2;
+        height = bb.height / 2;
 
-    // @private set the animation for the sprite
-    onAnimate: function(sprite, attr) {
-        var me = this;
-        sprite.stopAnimation();
-        if (me.triggerAfterDraw) {
-            return sprite.animate(Ext.applyIf(attr, me.chart.animate));
-        } else {
-            me.triggerAfterDraw = true;
-            return sprite.animate(Ext.apply(Ext.applyIf(attr, me.chart.animate), {
-                listeners: {
-                    'afteranimate': function() {
-                        me.triggerAfterDraw = false;
-                        me.fireEvent('afterrender');
-                    }    
-                }    
-            }));
-        }
-    },
-    
-    // @private return the gutter.
-    getGutters: function() {
-        return [0, 0];
-    },
+        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;
 
-    // @private wrapper for the itemmouseover event.
-    onItemMouseOver: function(item) { 
-        var me = this;
-        if (item.series === me) {
-            if (me.highlight) {
-                me.highlightItem(item);
-            }
-            if (me.tooltip) {
-                me.showTip(item);
+        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);
             }
         }
     },
 
-    // @private wrapper for the itemmouseout event.
-    onItemMouseOut: function(item) {
-        var me = this;
-        if (item.series === me) {
-            me.unHighlightItem();
-            if (me.tooltip) {
-                me.hideTip(item);
-            }
+    // @private
+    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;
+
+        //get the right two points
+        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]);
 
-    // @private wrapper for the mouseleave event.
-    onMouseLeave: function() {
-        var me = this;
-        me.unHighlightItem();
-        if (me.tooltip) {
-            me.hideTip();
+        norm = Math.sqrt(1 + a * a);
+        dir = [1 / norm, a / norm];
+        normal = [-dir[1], dir[0]];
+
+        //keep the label always on the outer part of the "elbow"
+        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;
         }
-    },
 
-    /**
-     * For a given x/y point relative to the Surface, find a corresponding item from this
-     * series, if any.
-     * @param {Number} x
-     * @param {Number} y
-     * @return {Object} An object describing the item, or null if there is no matching item. The exact contents of
-     *                  this object will vary by series type, but should always contain at least the following:
-     *                  <ul>
-     *                    <li>{Ext.chart.series.Series} series - the Series object to which the item belongs</li>
-     *                    <li>{Object} value - the value(s) of the item's data point</li>
-     *                    <li>{Array} point - the x/y coordinates relative to the chart box of a single point
-     *                        for this data item, which can be used as e.g. a tooltip anchor point.</li>
-     *                    <li>{Ext.draw.Sprite} sprite - the item's rendering Sprite.
-     *                  </ul>
-     */
-    getItemForPoint: function(x, y) {
-        //if there are no items to query just return null.
-        if (!this.items || !this.items.length || this.seriesIsHidden) {
-            return null;
+        //position
+        x = cur[0] + normal[0] * offsetFromViz;
+        y = cur[1] + normal[1] * offsetFromViz;
+
+        //box position and dimensions
+        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;
+
+        //now check if we're out of bounds and invert the normal vector correspondingly
+        //this may add new overlaps between labels (but labels won't be out of bounds).
+        if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
+            normal[0] *= -1;
         }
-        var me = this,
-            items = me.items,
-            bbox = me.bbox,
-            item, i, ln;
-        // Check bounds
-        if (!Ext.draw.Draw.withinBox(x, y, bbox)) {
-            return null;
+        if (boxy < clipRect[1] || (boxy + boxh) > (clipRect[1] + clipRect[3])) {
+            normal[1] *= -1;
         }
-        for (i = 0, ln = items.length; i < ln; i++) {
-            if (items[i] && this.isItemInPoint(x, y, items[i], i)) {
-                return items[i];
-            }
+
+        //update positions
+        x = cur[0] + normal[0] * offsetFromViz;
+        y = cur[1] + normal[1] * offsetFromViz;
+
+        //update box position and dimensions
+        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;
+
+        //set the line from the middle of the pie to the box.
+        callout.lines.setAttributes({
+            path: ["M", cur[0], cur[1], "L", x, y, "Z"]
+        }, true);
+        //set box position
+        callout.box.setAttributes({
+            x: boxx,
+            y: boxy,
+            width: boxw,
+            height: boxh
+        }, true);
+        //set text position
+        callout.label.setAttributes({
+            x: x + (normal[0] > 0? offsetBox : -(bbox.width + offsetBox)),
+            y: y
+        }, true);
+        for (p in callout) {
+            callout[p].show(true);
         }
-        
-        return null;
-    },
-    
-    isItemInPoint: function(x, y, item, i) {
-        return false;
     },
 
-    /**
-     * Hides all the elements in the series.
-     */
-    hideAll: function() {
+    isItemInPoint: function(x, y, item, i) {
         var me = this,
-            items = me.items,
-            item, len, i, sprite;
-
-        me.seriesIsHidden = true;
-        me._prevShowMarkers = me.showMarkers;
+            pointsUp = item.pointsUp,
+            pointsDown = item.pointsDown,
+            abs = Math.abs,
+            dist = Infinity, p, pln, point;
 
-        me.showMarkers = false;
-        //hide all labels
-        me.hideLabels(0);
-        //hide all sprites
-        for (i = 0, len = items.length; i < len; i++) {
-            item = items[i];
-            sprite = item.sprite;
-            if (sprite) {
-                sprite.setAttributes({
-                    hidden: true
-                }, true);
+        for (p = 0, pln = pointsUp.length; p < pln; p++) {
+            point = [pointsUp[p][0], pointsUp[p][1]];
+            if (dist > abs(x - point[0])) {
+                dist = abs(x - point[0]);
+            } else {
+                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;
     },
 
     /**
-     * Shows all the elements in the series.
+     * Highlight this entire series.
+     * @param {Object} item Info about the item; same format as returned by #getItemForPoint.
      */
-    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;
+    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 = Ext.create('Ext.fx.Anim', Ext.apply({
+                    target: area,
+                    to: to
+                }, this.chart.animate));
+            }
+            else {
+                area.setAttributes(to, true);
+            }
+        }
     },
-    
+
     /**
-     * Returns a string with the color to be used for the series legend item. 
+     * UnHighlight this entire series.
+     * @param {Object} item Info about the item; same format as returned by #getItemForPoint.
      */
-    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;
+    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 = Ext.create('Ext.fx.Anim', {
+                    target: area,
+                    to: {
+                        fill: area.__prevFill,
+                        opacity: area.__prevOpacity,
+                        lineWidth: area.__prevLineWidth
+                    }
+                });
             }
-            return stroke;
         }
-        return '#000';
     },
-    
+
     /**
-     * Checks whether the data field should be visible in the legend
-     * @private
-     * @param {Number} index The index of the current item
+     * Highlight the specified item. If no item is provided the whole series will be highlighted.
+     * @param item {Object} Info about the item; same format as returned by #getItemForPoint
      */
-    visibleInLegend: function(index){
-        var excludes = this.__excludes;
-        if (excludes) {
-            return !excludes[index];
+    highlightItem: function(item) {
+        var me = this,
+            points, path;
+        if (!item) {
+            this.highlightSeries();
+            return;
         }
-        return !this.seriesIsHidden;
+        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);
     },
 
     /**
-     * Changes the value of the {@link #title} for the series.
-     * Arguments can take two forms:
-     * <ul>
-     * <li>A single String value: this will be used as the new single title for the series (applies
-     * to series with only one yField)</li>
-     * <li>A numeric index and a String value: this will set the title for a single indexed yField.</li>
-     * </ul>
-     * @param {Number} index
-     * @param {String} title
+     * Un-highlights the specified item. If no item is provided it will un-highlight the entire series.
+     * @param {Object} item Info about the item; same format as returned by #getItemForPoint
      */
-    setTitle: function(index, title) {
-        var me = this,
-            oldTitle = me.title;
-
-        if (Ext.isString(index)) {
-            title = index;
-            index = 0;
+    unHighlightItem: function(item) {
+        if (!item) {
+            this.unHighlightSeries();
         }
 
-        if (Ext.isArray(oldTitle)) {
-            oldTitle[index] = title;
-        } else {
-            me.title = title;
+        if (this.highlightSprite) {
+            this.highlightSprite.hide(true);
         }
+    },
 
-        me.fireEvent('titlechange', title, index);
-    }
-});
-
-/**
- * @class Ext.chart.series.Cartesian
- * @extends Ext.chart.series.Series
- *
- * Common base class for series implementations which plot values using x/y coordinates.
- *
- */
-Ext.define('Ext.chart.series.Cartesian', {
-
-    /* Begin Definitions */
-
-    extend: 'Ext.chart.series.Series',
-
-    alternateClassName: ['Ext.chart.CartesianSeries', 'Ext.chart.CartesianChart'],
-
-    /* End Definitions */
-
-    /**
-     * The field used to access the x axis value from the items from the data
-     * source.
-     *
-     * @cfg xField
-     * @type String
-     */
-    xField: null,
+    // @private
+    hideAll: function() {
+        if (!isNaN(this._index)) {
+            this.__excludes[this._index] = true;
+            this.areas[this._index].hide(true);
+            this.drawSeries();
+        }
+    },
 
-    /**
-     * The field used to access the y-axis value from the items from the data
-     * source.
-     *
-     * @cfg yField
-     * @type String
-     */
-    yField: null,
+    // @private
+    showAll: function() {
+        if (!isNaN(this._index)) {
+            this.__excludes[this._index] = false;
+            this.areas[this._index].show(true);
+            this.drawSeries();
+        }
+    },
 
     /**
-     * Indicates which axis the series will bind to
-     *
-     * @property axis
-     * @type String
+     * Returns the color of the series (to be displayed as color for the series legend item).
+     * @param item {Object} Info about the item; same format as returned by #getItemForPoint
      */
-    axis: 'left'
+    getLegendColor: function(index) {
+        var me = this;
+        return me.colorArrayStyle[index % me.colorArrayStyle.length];
+    }
 });
-
 /**
  * @class Ext.chart.series.Area
  * @extends Ext.chart.series.Cartesian
- * 
- <p>
-    Creates a Stacked Area Chart. The stacked area chart is useful when displaying multiple aggregated layers of information.
-    As with all other series, the Area Series must be appended in the *series* Chart array configuration. See the Chart 
-    documentation for more information. A typical configuration object for the area series could be:
- </p>
-{@img Ext.chart.series.Area/Ext.chart.series.Area.png Ext.chart.series.Area chart series} 
-  <pre><code>
-   var store = Ext.create('Ext.data.JsonStore', {
-        fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
-        data: [
-            {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
-            {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
-            {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
-            {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
-            {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
-        ]
-    });
-    
-    Ext.create('Ext.chart.Chart', {
-        renderTo: Ext.getBody(),
-        width: 500,
-        height: 300,
-        store: store,
-        axes: [{
-            type: 'Numeric',
-            grid: true,
-            position: 'left',
-            fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
-            title: 'Sample Values',
-            grid: {
-                odd: {
-                    opacity: 1,
-                    fill: '#ddd',
-                    stroke: '#bbb',
-                    'stroke-width': 1
-                }
-            },
-            minimum: 0,
-            adjustMinimumByMajorUnit: 0
-        }, {
-            type: 'Category',
-            position: 'bottom',
-            fields: ['name'],
-            title: 'Sample Metrics',
-            grid: true,
-            label: {
-                rotate: {
-                    degrees: 315
-                }
-            }
-        }],
-        series: [{
-            type: 'area',
-            highlight: false,
-            axis: 'left',
-            xField: 'name',
-            yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
-            style: {
-                opacity: 0.93
-            }
-        }]
-    });
-   </code></pre>
-  
- <p>
-  In this configuration we set `area` as the type for the series, set highlighting options to true for highlighting elements on hover, 
-  take the left axis to measure the data in the area series, set as xField (x values) the name field of each element in the store, 
-  and as yFields (aggregated layers) seven data fields from the same store. Then we override some theming styles by adding some opacity 
-  to the style object.
- </p>
-  
+ *
+ * Creates a Stacked Area Chart. The stacked area chart is useful when displaying multiple aggregated layers of information.
+ * As with all other series, the Area Series must be appended in the *series* Chart array configuration. See the Chart
+ * documentation for more information. A typical configuration object for the area series could be:
+ *
+ *     @example
+ *     var store = Ext.create('Ext.data.JsonStore', {
+ *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
+ *         data: [
+ *             { 'name': 'metric one',   'data1':10, 'data2':12, 'data3':14, 'data4':8,  'data5':13 },
+ *             { 'name': 'metric two',   'data1':7,  'data2':8,  'data3':16, 'data4':10, 'data5':3  },
+ *             { 'name': 'metric three', 'data1':5,  'data2':2,  'data3':14, 'data4':12, 'data5':7  },
+ *             { 'name': 'metric four',  'data1':2,  'data2':14, 'data3':6,  'data4':1,  'data5':23 },
+ *             { 'name': 'metric five',  'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33 }
+ *         ]
+ *     });
+ *
+ *     Ext.create('Ext.chart.Chart', {
+ *         renderTo: Ext.getBody(),
+ *         width: 500,
+ *         height: 300,
+ *         store: store,
+ *         axes: [
+ *             {
+ *                 type: 'Numeric',
+ *                 grid: true,
+ *                 position: 'left',
+ *                 fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *                 title: 'Sample Values',
+ *                 grid: {
+ *                     odd: {
+ *                         opacity: 1,
+ *                         fill: '#ddd',
+ *                         stroke: '#bbb',
+ *                         'stroke-width': 1
+ *                     }
+ *                 },
+ *                 minimum: 0,
+ *                 adjustMinimumByMajorUnit: 0
+ *             },
+ *             {
+ *                 type: 'Category',
+ *                 position: 'bottom',
+ *                 fields: ['name'],
+ *                 title: 'Sample Metrics',
+ *                 grid: true,
+ *                 label: {
+ *                     rotate: {
+ *                         degrees: 315
+ *                     }
+ *                 }
+ *             }
+ *         ],
+ *         series: [{
+ *             type: 'area',
+ *             highlight: false,
+ *             axis: 'left',
+ *             xField: 'name',
+ *             yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
+ *             style: {
+ *                 opacity: 0.93
+ *             }
+ *         }]
+ *     });
+ *
+ * In this configuration we set `area` as the type for the series, set highlighting options to true for highlighting elements on hover,
+ * take the left axis to measure the data in the area series, set as xField (x values) the name field of each element in the store,
+ * and as yFields (aggregated layers) seven data fields from the same store. Then we override some theming styles by adding some opacity
+ * to the style object.
+ *
  * @xtype area
- * 
  */
 Ext.define('Ext.chart.series.Area', {
 
     /* Begin Definitions */
 
     extend: 'Ext.chart.series.Cartesian',
-    
+
     alias: 'series.area',
 
     requires: ['Ext.chart.axis.Axis', 'Ext.draw.Color', 'Ext.fx.Anim'],
@@ -47002,7 +49439,7 @@ Ext.define('Ext.chart.series.Area', {
     stacked: true,
 
     /**
-     * @cfg {Object} style 
+     * @cfg {Object} style
      * Append styling properties to this object for it to override theme properties.
      */
     style: {},
@@ -47078,7 +49515,7 @@ Ext.define('Ext.chart.series.Area', {
     getBounds: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             areas = [].concat(me.yField),
             areasLen = areas.length,
             xValues = [],
@@ -47145,8 +49582,8 @@ Ext.define('Ext.chart.series.Area', {
             yValues.push(yValue);
         }, me);
 
-        xScale = bbox.width / (maxX - minX);
-        yScale = bbox.height / (maxY - minY);
+        xScale = bbox.width / ((maxX - minX) || 1);
+        yScale = bbox.height / ((maxY - minY) || 1);
 
         ln = xValues.length;
         if ((ln > bbox.width) && me.areas) {
@@ -47171,7 +49608,7 @@ Ext.define('Ext.chart.series.Area', {
     getPaths: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             first = true,
             bounds = me.getBounds(),
             bbox = bounds.bbox,
@@ -47216,7 +49653,7 @@ Ext.define('Ext.chart.series.Area', {
                 items[areaIndex].pointsUp.push([x, y]);
             }
         }
-        
+
         // Close the paths
         for (areaIndex = 0; areaIndex < bounds.areasLen; areaIndex++) {
             // Excluded series
@@ -47258,7 +49695,7 @@ Ext.define('Ext.chart.series.Area', {
     drawSeries: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             surface = chart.surface,
             animate = chart.animate,
             group = me.group,
@@ -47273,7 +49710,7 @@ Ext.define('Ext.chart.series.Area', {
         if (!store || !store.getCount()) {
             return;
         }
-        
+
         paths = me.getPaths();
 
         if (!me.areas) {
@@ -47299,7 +49736,7 @@ Ext.define('Ext.chart.series.Area', {
             path = paths.paths[areaIndex];
             if (animate) {
                 //Add renderer to line. There is not a unique record associated with this.
-                rendererAttributes = me.renderer(areaElem, false, { 
+                rendererAttributes = me.renderer(areaElem, false, {
                     path: path,
                     // 'clip-rect': me.clipBox,
                     fill: colorArrayStyle[areaIndex % colorArrayLength],
@@ -47310,7 +49747,7 @@ Ext.define('Ext.chart.series.Area', {
                     to: rendererAttributes
                 });
             } else {
-                rendererAttributes = me.renderer(areaElem, false, { 
+                rendererAttributes = me.renderer(areaElem, false, {
                     path: path,
                     // 'clip-rect': me.clipBox,
                     hidden: false,
@@ -47359,16 +49796,16 @@ Ext.define('Ext.chart.series.Area', {
             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;
@@ -47427,11 +49864,11 @@ Ext.define('Ext.chart.series.Area', {
         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]];
-        
+
         //keep the label always on the outer part of the "elbow"
         if (aprev > 0 && anext < 0 && normal[1] < 0 || aprev < 0 && anext > 0 && normal[1] > 0) {
             normal[0] *= -1;
@@ -47444,13 +49881,13 @@ Ext.define('Ext.chart.series.Area', {
         //position
         x = cur[0] + normal[0] * offsetFromViz;
         y = cur[1] + normal[1] * offsetFromViz;
-        
+
         //box position and dimensions
         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;
-        
+
         //now check if we're out of bounds and invert the normal vector correspondingly
         //this may add new overlaps between labels (but labels won't be out of bounds).
         if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
@@ -47463,13 +49900,13 @@ Ext.define('Ext.chart.series.Area', {
         //update positions
         x = cur[0] + normal[0] * offsetFromViz;
         y = cur[1] + normal[1] * offsetFromViz;
-        
+
         //update box position and dimensions
         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;
-        
+
         //set the line from the middle of the pie to the box.
         callout.lines.setAttributes({
             path: ["M", cur[0], cur[1], "L", x, y, "Z"]
@@ -47490,14 +49927,14 @@ Ext.define('Ext.chart.series.Area', {
             callout[p].show(true);
         }
     },
-    
+
     isItemInPoint: function(x, y, item, i) {
         var me = this,
             pointsUp = item.pointsUp,
             pointsDown = item.pointsDown,
             abs = Math.abs,
             dist = Infinity, p, pln, point;
-        
+
         for (p = 0, pln = pointsUp.length; p < pln; p++) {
             point = [pointsUp[p][0], pointsUp[p][1]];
             if (dist > abs(x - point[0])) {
@@ -47648,19 +50085,18 @@ Ext.define('Ext.chart.series.Area', {
  * Series must be appended in the *series* Chart array configuration. See the Chart documentation for more information.
  * A typical configuration object for the bar series could be:
  *
- * {@img Ext.chart.series.Bar/Ext.chart.series.Bar.png Ext.chart.series.Bar chart series}
- *
+ *     @example
  *     var store = Ext.create('Ext.data.JsonStore', {
  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
  *         data: [
- *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
+ *             { 'name': 'metric one',   'data1':10, 'data2':12, 'data3':14, 'data4':8,  'data5':13 },
+ *             { 'name': 'metric two',   'data1':7,  'data2':8,  'data3':16, 'data4':10, 'data5':3  },
+ *             { 'name': 'metric three', 'data1':5,  'data2':2,  'data3':14, 'data4':12, 'data5':7  },
+ *             { 'name': 'metric four',  'data1':2,  'data2':14, 'data3':6,  'data4':1,  'data5':23 },
+ *             { 'name': 'metric five',  'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33 }
  *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.chart.Chart', {
  *         renderTo: Ext.getBody(),
  *         width: 500,
@@ -47734,12 +50170,12 @@ Ext.define('Ext.chart.series.Bar', {
      * @cfg {Boolean} column Whether to set the visualization as column chart or horizontal bar chart.
      */
     column: false,
-    
+
     /**
      * @cfg style Style properties that will override the theming series styles.
      */
     style: {},
-    
+
     /**
      * @cfg {Number} gutter The gutter space between single bars, as a percentage of the bar width
      */
@@ -47773,7 +50209,7 @@ Ext.define('Ext.chart.series.Bar', {
                 opacity: 0.8,
                 color: '#f00'
             },
-            
+
             shadowAttributes: [{
                 "stroke-width": 6,
                 "stroke-opacity": 0.05,
@@ -47811,11 +50247,11 @@ Ext.define('Ext.chart.series.Bar', {
     // @private sets the bar girth.
     getBarGirth: function() {
         var me = this,
-            store = me.chart.store,
+            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);
     },
 
@@ -47831,7 +50267,7 @@ Ext.define('Ext.chart.series.Bar', {
     getBounds: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             bars = [].concat(me.yField),
             barsLen = bars.length,
             groupBarsLen = barsLen,
@@ -47863,8 +50299,8 @@ Ext.define('Ext.chart.series.Bar', {
             axis = chart.axes.get(me.axis);
             if (axis) {
                 out = axis.calcEnds();
-                minY = out.from || axis.prevMin;
-                maxY = mmax(out.to || axis.prevMax, 0);
+                minY = out.from;
+                maxY = out.to;
             }
         }
 
@@ -47874,8 +50310,8 @@ Ext.define('Ext.chart.series.Bar', {
                 fields: [].concat(me.yField)
             });
             out = axis.calcEnds();
-            minY = out.from || axis.prevMin;
-            maxY = mmax(out.to || axis.prevMax, 0);
+            minY = out.from;
+            maxY = out.to;
         }
 
         if (!Ext.isNumber(minY)) {
@@ -47932,7 +50368,7 @@ Ext.define('Ext.chart.series.Bar', {
     getPaths: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             bounds = me.bounds = me.getBounds(),
             items = me.items = [],
             gutter = me.gutter / 100,
@@ -47963,14 +50399,14 @@ Ext.define('Ext.chart.series.Bar', {
             top = bounds.zero;
             totalDim = 0;
             totalNegDim = 0;
-            hasShadow = false; 
+            hasShadow = false;
             for (j = 0, counter = 0; j < barsLen; j++) {
                 // Excluded series
                 if (me.__excludes && me.__excludes[j]) {
                     continue;
                 }
                 yValue = record.get(bounds.bars[j]);
-                height = Math.round((yValue - ((bounds.minY < 0) ? 0 : bounds.minY)) * bounds.scale);
+                height = Math.round((yValue - mmax(bounds.minY, 0)) * bounds.scale);
                 barAttr = {
                     fill: colors[(barsLen > 1 ? j : 0) % colorLength]
                 };
@@ -48076,7 +50512,7 @@ Ext.define('Ext.chart.series.Bar', {
             shadowGroups = me.shadowGroups,
             shadowAttributes = me.shadowAttributes,
             shadowGroupsLn = shadowGroups.length,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             column = me.column,
             items = me.items,
             shadows = [],
@@ -48134,7 +50570,7 @@ Ext.define('Ext.chart.series.Bar', {
     drawSeries: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             surface = chart.surface,
             animate = chart.animate,
             stacked = me.stacked,
@@ -48146,11 +50582,11 @@ Ext.define('Ext.chart.series.Bar', {
             seriesStyle = me.seriesStyle,
             items, ln, i, j, baseAttrs, sprite, rendererAttributes, shadowIndex, shadowGroup,
             bounds, endSeriesStyle, barAttr, attrs, anim;
-        
+
         if (!store || !store.getCount()) {
             return;
         }
-        
+
         //fill colors are taken from the colors array.
         delete seriesStyle.fill;
         endSeriesStyle = Ext.apply(seriesStyle, this.style);
@@ -48224,7 +50660,7 @@ Ext.define('Ext.chart.series.Bar', {
         }
         me.renderLabels();
     },
-    
+
     // @private handled when creating a label.
     onCreateLabel: function(storeItem, item, i, display) {
         var me = this,
@@ -48238,7 +50674,7 @@ Ext.define('Ext.chart.series.Bar', {
             group: group
         }, endLabelStyle || {}));
     },
-    
+
     // @private callback used when placing a label.
     onPlaceLabel: function(label, storeItem, item, i, display, animate, j, index) {
         // Determine the label's final position. Starts with the configured preferred value but
@@ -48394,14 +50830,14 @@ Ext.define('Ext.chart.series.Bar', {
         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;
     },
-    
+
     // @private hide all markers
     hideAll: function() {
         var axes = this.chart.axes;
@@ -48431,7 +50867,7 @@ Ext.define('Ext.chart.series.Bar', {
             });
         }
     },
-    
+
     /**
      * Returns a string with the color to be used for the series legend item.
      * @param index
@@ -48439,7 +50875,7 @@ Ext.define('Ext.chart.series.Bar', {
     getLegendColor: function(index) {
         var me = this,
             colorLength = me.colorArrayStyle.length;
-        
+
         if (me.style && me.style.fill) {
             return me.style.fill;
         } else {
@@ -48465,50 +50901,33 @@ Ext.define('Ext.chart.series.Bar', {
 /**
  * @class Ext.chart.series.Column
  * @extends Ext.chart.series.Bar
- * 
- * Creates a Column Chart. Much of the methods are inherited from Bar. A Column Chart is a useful visualization technique to display quantitative information for different 
- * categories that can show some progression (or regression) in the data set.
- * As with all other series, the Column Series must be appended in the *series* Chart array configuration. See the Chart 
- * documentation for more information. A typical configuration object for the column series could be:
  *
- * {@img Ext.chart.series.Column/Ext.chart.series.Column.png Ext.chart.series.Column chart series}
+ * Creates a Column Chart. Much of the methods are inherited from Bar. A Column Chart is a useful
+ * visualization technique to display quantitative information for different categories that can
+ * show some progression (or regression) in the data set. As with all other series, the Column Series
+ * must be appended in the *series* Chart array configuration. See the Chart documentation for more
+ * information. A typical configuration object for the column series could be:
  *
- * ## Example
- * 
+ *     @example
  *     var store = Ext.create('Ext.data.JsonStore', {
  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
  *         data: [
- *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
+ *             { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
+ *             { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
+ *             { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
+ *             { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
+ *             { 'name': 'metric five',  'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
  *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.chart.Chart', {
  *         renderTo: Ext.getBody(),
  *         width: 500,
  *         height: 300,
  *         animate: true,
  *         store: store,
- *         axes: [{
- *             type: 'Numeric',
- *             position: 'bottom',
- *             fields: ['data1'],
- *             label: {
- *                 renderer: Ext.util.Format.numberRenderer('0,0')
- *             },
- *             title: 'Sample Values',
- *             grid: true,
- *             minimum: 0
- *         }, {
- *             type: 'Category',
- *             position: 'left',
- *             fields: ['name'],
- *             title: 'Sample Metrics'
- *         }],
- *             axes: [{
+ *         axes: [
+ *             {
  *                 type: 'Numeric',
  *                 position: 'left',
  *                 fields: ['data1'],
@@ -48518,13 +50937,16 @@ Ext.define('Ext.chart.series.Bar', {
  *                 title: 'Sample Values',
  *                 grid: true,
  *                 minimum: 0
- *             }, {
+ *             },
+ *             {
  *                 type: 'Category',
  *                 position: 'bottom',
  *                 fields: ['name'],
  *                 title: 'Sample Metrics'
- *             }],
- *             series: [{
+ *             }
+ *         ],
+ *         series: [
+ *             {
  *                 type: 'column',
  *                 axis: 'left',
  *                 highlight: true,
@@ -48546,11 +50968,13 @@ Ext.define('Ext.chart.series.Bar', {
  *                 },
  *                 xField: 'name',
  *                 yField: 'data1'
- *             }]
+ *             }
+ *         ]
  *     });
- *  
- * In this configuration we set `column` as the series type, bind the values of the bars to the bottom axis, set `highlight` to true so that bars are smoothly highlighted
- * when hovered and bind the `xField` or category field to the data store `name` property and the `yField` as the data1 property of a store element. 
+ *
+ * In this configuration we set `column` as the series type, bind the values of the bars to the bottom axis,
+ * set `highlight` to true so that bars are smoothly highlighted when hovered and bind the `xField` or category
+ * field to the data store `name` property and the `yField` as the data1 property of a store element.
  */
 Ext.define('Ext.chart.series.Column', {
 
@@ -48584,7 +51008,7 @@ Ext.define('Ext.chart.series.Column', {
  * @extends Ext.chart.series.Series
  * 
  * Creates a Gauge Chart. Gauge Charts are used to show progress in a certain variable. There are two ways of using the Gauge chart.
- * One is setting a store element into the Gauge and selecting the field to be used from that store. Another one is instanciating the
+ * One is setting a store element into the Gauge and selecting the field to be used from that store. Another one is instantiating the
  * visualization and using the `setValue` method to adjust the value you want.
  *
  * A chart/series configuration for the Gauge visualization could look like this:
@@ -48634,10 +51058,9 @@ Ext.define('Ext.chart.series.Gauge', {
     highlightDuration: 150,
 
     /**
-     * @cfg {String} angleField
+     * @cfg {String} angleField (required)
      * The store record field name to be used for the pie angles.
      * The values bound to this field name must be positive real numbers.
-     * This parameter is required.
      */
     angleField: false,
 
@@ -48648,7 +51071,7 @@ Ext.define('Ext.chart.series.Gauge', {
     needle: false,
     
     /**
-     * @cfg {Boolean|Number} donut
+     * @cfg {Boolean/Number} donut
      * Use the entire disk or just a fraction of it for the gauge. Default's false.
      */
     donut: false,
@@ -48715,7 +51138,7 @@ Ext.define('Ext.chart.series.Gauge', {
     //@private updates some onbefore render parameters.
     initialize: function() {
         var me = this,
-            store = me.chart.substore || me.chart.store;
+            store = me.chart.getChartStore();
         //Add yFields to be used in Legend.js
         me.yField = [];
         if (me.label.field) {
@@ -48816,7 +51239,7 @@ Ext.define('Ext.chart.series.Gauge', {
     drawSeries: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             group = me.group,
             animate = me.chart.animate,
             axis = me.chart.axes.get(0),
@@ -49037,91 +51460,96 @@ Ext.define('Ext.chart.series.Gauge', {
 /**
  * @class Ext.chart.series.Line
  * @extends Ext.chart.series.Cartesian
- * 
- * Creates a Line Chart. A Line Chart is a useful visualization technique to display quantitative information for different 
+ *
+ * Creates a Line Chart. A Line Chart is a useful visualization technique to display quantitative information for different
  * categories or other real values (as opposed to the bar chart), that can show some progression (or regression) in the dataset.
- * As with all other series, the Line Series must be appended in the *series* Chart array configuration. See the Chart 
+ * As with all other series, the Line Series must be appended in the *series* Chart array configuration. See the Chart
  * documentation for more information. A typical configuration object for the line series could be:
  *
- * {@img Ext.chart.series.Line/Ext.chart.series.Line.png Ext.chart.series.Line chart series}
- *
+ *     @example
  *     var store = Ext.create('Ext.data.JsonStore', {
  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
  *         data: [
- *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
+ *             { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
+ *             { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
+ *             { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
+ *             { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
+ *             { 'name': 'metric five',  'data1': 4,  'data2': 4,  'data3': 36, 'data4': 13, 'data5': 33 }
  *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.chart.Chart', {
  *         renderTo: Ext.getBody(),
  *         width: 500,
  *         height: 300,
  *         animate: true,
  *         store: store,
- *         axes: [{
- *             type: 'Numeric',
- *             position: 'bottom',
- *             fields: ['data1'],
- *             label: {
- *                 renderer: Ext.util.Format.numberRenderer('0,0')
- *             },
- *             title: 'Sample Values',
- *             grid: true,
- *             minimum: 0
- *         }, {
- *             type: 'Category',
- *             position: 'left',
- *             fields: ['name'],
- *             title: 'Sample Metrics'
- *         }],
- *         series: [{
- *             type: 'line',
- *             highlight: {
- *                 size: 7,
- *                 radius: 7
+ *         axes: [
+ *             {
+ *                 type: 'Numeric',
+ *                 position: 'left',
+ *                 fields: ['data1', 'data2'],
+ *                 label: {
+ *                     renderer: Ext.util.Format.numberRenderer('0,0')
+ *                 },
+ *                 title: 'Sample Values',
+ *                 grid: true,
+ *                 minimum: 0
  *             },
- *             axis: 'left',
- *             xField: 'name',
- *             yField: 'data1',
- *             markerCfg: {
- *                 type: 'cross',
- *                 size: 4,
- *                 radius: 4,
- *                 'stroke-width': 0
+ *             {
+ *                 type: 'Category',
+ *                 position: 'bottom',
+ *                 fields: ['name'],
+ *                 title: 'Sample Metrics'
  *             }
- *         }, {
- *             type: 'line',
- *             highlight: {
- *                 size: 7,
- *                 radius: 7
+ *         ],
+ *         series: [
+ *             {
+ *                 type: 'line',
+ *                 highlight: {
+ *                     size: 7,
+ *                     radius: 7
+ *                 },
+ *                 axis: 'left',
+ *                 xField: 'name',
+ *                 yField: 'data1',
+ *                 markerConfig: {
+ *                     type: 'cross',
+ *                     size: 4,
+ *                     radius: 4,
+ *                     'stroke-width': 0
+ *                 }
  *             },
- *             axis: 'left',
- *             fill: true,
- *             xField: 'name',
- *             yField: 'data3',
- *             markerCfg: {
- *                 type: 'circle',
- *                 size: 4,
- *                 radius: 4,
- *                 'stroke-width': 0
+ *             {
+ *                 type: 'line',
+ *                 highlight: {
+ *                     size: 7,
+ *                     radius: 7
+ *                 },
+ *                 axis: 'left',
+ *                 fill: true,
+ *                 xField: 'name',
+ *                 yField: 'data2',
+ *                 markerConfig: {
+ *                     type: 'circle',
+ *                     size: 4,
+ *                     radius: 4,
+ *                     'stroke-width': 0
+ *                 }
  *             }
- *         }]
+ *         ]
  *     });
- *  
- * In this configuration we're adding two series (or lines), one bound to the `data1` 
- * property of the store and the other to `data3`. The type for both configurations is 
- * `line`. The `xField` for both series is the same, the name propert of the store. 
- * Both line series share the same axis, the left axis. You can set particular marker 
- * configuration by adding properties onto the markerConfig object. Both series have 
- * an object as highlight so that markers animate smoothly to the properties in highlight 
- * when hovered. The second series has `fill=true` which means that the line will also 
+ *
+ * In this configuration we're adding two series (or lines), one bound to the `data1`
+ * property of the store and the other to `data3`. The type for both configurations is
+ * `line`. The `xField` for both series is the same, the name propert of the store.
+ * Both line series share the same axis, the left axis. You can set particular marker
+ * configuration by adding properties onto the markerConfig object. Both series have
+ * an object as highlight so that markers animate smoothly to the properties in highlight
+ * when hovered. The second series has `fill=true` which means that the line will also
  * have an area below it of the same color.
  *
- * **Note:** In the series definition remember to explicitly set the axis to bind the 
+ * **Note:** In the series definition remember to explicitly set the axis to bind the
  * values of the line series to. This can be done by using the `axis` configuration property.
  */
 Ext.define('Ext.chart.series.Line', {
@@ -49137,9 +51565,9 @@ Ext.define('Ext.chart.series.Line', {
     /* End Definitions */
 
     type: 'line',
-    
+
     alias: 'series.line',
-    
+
     /**
      * @cfg {String} axis
      * The position of the axis to bind the values to. Possible values are 'left', 'bottom', 'top' and 'right'.
@@ -49152,7 +51580,7 @@ Ext.define('Ext.chart.series.Line', {
      * The offset distance from the cursor position to the line series to trigger events (then used for highlighting series, etc).
      */
     selectionTolerance: 20,
-    
+
     /**
      * @cfg {Boolean} showMarkers
      * Whether markers should be displayed at the data points along the line. If true,
@@ -49174,17 +51602,31 @@ Ext.define('Ext.chart.series.Line', {
             'fill': '#f00'
         }
      </code></pre>
-     
+
      */
     markerConfig: {},
 
     /**
      * @cfg {Object} style
-     * An object containing styles for the visualization lines. These styles will override the theme styles. 
-     * Some options contained within the style object will are described next.
+     * An object containing style properties for the visualization lines and fill.
+     * These styles will override the theme styles.  The following are valid style properties:
+     *
+     * - `stroke` - an rgb or hex color string for the background color of the line
+     * - `stroke-width` - the width of the stroke (integer)
+     * - `fill` - the background fill color string (hex or rgb), only works if {@link #fill} is `true`
+     * - `opacity` - the opacity of the line and the fill color (decimal)
+     *
+     * Example usage:
+     *
+     *     style: {
+     *         stroke: '#00ff00',
+     *         'stroke-width': 10,
+     *         fill: '#80A080',
+     *         opacity: 0.2
+     *     }
      */
     style: {},
-    
+
     /**
      * @cfg {Boolean/Number} smooth
      * If set to `true` or a non-zero number, the line will be smoothed/rounded around its points; otherwise
@@ -49204,8 +51646,8 @@ Ext.define('Ext.chart.series.Line', {
 
     /**
      * @cfg {Boolean} fill
-     * If true, the area below the line will be filled in using the {@link #style.eefill} and
-     * {@link #style.opacity} config properties. Defaults to false.
+     * If true, the area below the line will be filled in using the {@link #style eefill} and
+     * {@link #style opacity} config properties. Defaults to false.
      */
     fill: false,
 
@@ -49250,12 +51692,12 @@ Ext.define('Ext.chart.series.Line', {
             me.markerGroup = surface.getGroup(me.seriesId + '-markers');
         }
         if (shadow) {
-            for (i = 0, l = this.shadowAttributes.length; i < l; i++) {
+            for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
                 me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
             }
         }
     },
-    
+
     // @private makes an average of points when there are more data points than pixels to be rendered.
     shrink: function(xValues, yValues, size) {
         // Start at the 2nd point...
@@ -49266,7 +51708,7 @@ Ext.define('Ext.chart.series.Line', {
             ySum = 0,
             xRes = [xValues[0]],
             yRes = [yValues[0]];
-        
+
         for (; i < len; ++i) {
             xSum += xValues[i] || 0;
             ySum += yValues[i] || 0;
@@ -49289,13 +51731,12 @@ Ext.define('Ext.chart.series.Line', {
     drawSeries: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
-            surface = chart.surface,
-            chartBBox = chart.chartBBox,
+            chartAxes = chart.axes,
+            store = chart.getChartStore(),
+            storeCount = store.getCount(),
+            surface = me.chart.surface,
             bbox = {},
             group = me.group,
-            gutterX = chart.maxGutter[0],
-            gutterY = chart.maxGutter[1],
             showMarkers = me.showMarkers,
             markerGroup = me.markerGroup,
             enableShadows = chart.shadow,
@@ -49305,43 +51746,53 @@ Ext.define('Ext.chart.series.Line', {
             lnsh = shadowGroups.length,
             dummyPath = ["M"],
             path = ["M"],
+            renderPath = ["M"],
+            smoothPath = ["M"],
             markerIndex = chart.markerIndex,
             axes = [].concat(me.axis),
-            shadowGroup,
             shadowBarAttr,
             xValues = [],
+            xValueMap = {},
             yValues = [],
-            storeIndices = [],
-            numericAxis = true,
-            axisCount = 0,
+            yValueMap = {},
             onbreak = false,
+            storeIndices = [],
             markerStyle = me.markerStyle,
-            seriesStyle = me.seriesStyle,
-            seriesLabelStyle = me.seriesLabelStyle,
+            seriesStyle = me.style,
             colorArrayStyle = me.colorArrayStyle,
             colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
-            posHash = {
-                'left': 'right',
-                'right': 'left',
-                'top': 'bottom',
-                'bottom': 'top'
-            },
             isNumber = Ext.isNumber,
-            seriesIdx = me.seriesIdx, shadows, shadow, shindex, fromPath, fill, fillPath, rendererAttributes,
-            x, y, prevX, prevY, firstY, markerCount, i, j, ln, axis, ends, marker, markerAux, item, xValue,
+            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, props, firstMarker, count, smoothPath, renderPath;
-        
-        //if store is empty then there's nothing to draw.
-        if (!store || !store.getCount()) {
+            endLineStyle, type, count, items;
+
+        if (me.fireEvent('beforedraw', me) === false) {
             return;
         }
-        
+
+        //if store is empty or the series is excluded in the legend then there's nothing to draw.
+        if (!storeCount || me.seriesIsHidden) {
+            items = this.items;
+            if (items) {
+                for (i = 0, ln = items.length; i < ln; ++i) {
+                    if (items[i].sprite) {
+                        items[i].sprite.hide(true);
+                    }
+                }
+            }
+            return;
+        }
+
         //prepare style objects for line and markers
-        endMarkerStyle = Ext.apply(markerStyle, me.markerConfig);
+        endMarkerStyle = Ext.apply(markerStyle || {}, me.markerConfig);
         type = endMarkerStyle.type;
         delete endMarkerStyle.type;
-        endLineStyle = Ext.apply(seriesStyle, me.style);
+        endLineStyle = seriesStyle;
         //if no stroke with is specified force it to 0.5 because this is
         //about making *lines*
         if (!endLineStyle['stroke-width']) {
@@ -49365,113 +51816,82 @@ Ext.define('Ext.chart.series.Line', {
                 }, true);
             }
         }
-        
+
         me.unHighlightItem();
         me.cleanHighlights();
 
         me.setBBox();
         bbox = me.bbox;
-
         me.clipRect = [bbox.x, bbox.y, bbox.width, bbox.height];
-
-        chart.axes.each(function(axis) {
-            //only apply position calculations to axes that affect this series
-            //this means the axis in the position referred by this series and also
-            //the axis in the other coordinate for this series. For example: (left, top|bottom),
-            //or (top, left|right), etc.
-            if (axis.position == me.axis || axis.position != posHash[me.axis]) {
-                axisCount++;
-                if (axis.type != 'Numeric') {
-                    numericAxis = false;
-                    return;
+        for (i = 0, ln = axes.length; i < ln; i++) {
+            axis = chartAxes.get(axes[i]);
+            if (axis) {
+                ends = axis.calcEnds();
+                if (axis.position == 'top' || axis.position == 'bottom') {
+                    minX = ends.from;
+                    maxX = ends.to;
                 }
-                numericAxis = (numericAxis && axis.type == 'Numeric');
-                if (axis) {
-                    ends = axis.calcEnds();
-                    if (axis.position == 'top' || axis.position == 'bottom') {
-                        minX = ends.from;
-                        maxX = ends.to;
-                    }
-                    else {
-                        minY = ends.from;
-                        maxY = ends.to;
-                    }
+                else {
+                    minY = ends.from;
+                    maxY = ends.to;
                 }
             }
-        });
-        
-        //If there's only one axis specified for a series, then we set the default type of the other
-        //axis to a category axis. So in this case numericAxis, which would be true if both axes affecting
-        //the series are numeric should be false.
-        if (numericAxis && axisCount == 1) {
-            numericAxis = false;
         }
-        
         // If a field was specified without a corresponding axis, create one to get bounds
         //only do this for the axis where real values are bound (that's why we check for
         //me.axis)
-        if (me.xField && !isNumber(minX)) {
-            if (me.axis == 'bottom' || me.axis == 'top') {
-                axis = Ext.create('Ext.chart.axis.Axis', {
-                    chart: chart,
-                    fields: [].concat(me.xField)
-                }).calcEnds();
-                minX = axis.from;
-                maxX = axis.to;
-            } else if (numericAxis) {
-                axis = Ext.create('Ext.chart.axis.Axis', {
-                    chart: chart,
-                    fields: [].concat(me.xField),
-                    forceMinMax: true
-                }).calcEnds();
-                minX = axis.from;
-                maxX = axis.to;
-            }
+        if (me.xField && !isNumber(minX) &&
+            (boundXAxis == 'bottom' || boundXAxis == 'top') && 
+            !chartAxes.get(boundXAxis)) {
+            axis = Ext.create('Ext.chart.axis.Axis', {
+                chart: chart,
+                fields: [].concat(me.xField)
+            }).calcEnds();
+            minX = axis.from;
+            maxX = axis.to;
         }
-        
-        if (me.yField && !isNumber(minY)) {
-            if (me.axis == 'right' || me.axis == 'left') {
-                axis = Ext.create('Ext.chart.axis.Axis', {
-                    chart: chart,
-                    fields: [].concat(me.yField)
-                }).calcEnds();
-                minY = axis.from;
-                maxY = axis.to;
-            } else if (numericAxis) {
-                axis = Ext.create('Ext.chart.axis.Axis', {
-                    chart: chart,
-                    fields: [].concat(me.yField),
-                    forceMinMax: true
-                }).calcEnds();
-                minY = axis.from;
-                maxY = axis.to;
-            }
+        if (me.yField && !isNumber(minY) &&
+            (boundYAxis == 'right' || boundYAxis == 'left') &&
+            !chartAxes.get(boundYAxis)) {
+            axis = Ext.create('Ext.chart.axis.Axis', {
+                chart: chart,
+                fields: [].concat(me.yField)
+            }).calcEnds();
+            minY = axis.from;
+            maxY = axis.to;
         }
-        
         if (isNaN(minX)) {
             minX = 0;
-            xScale = bbox.width / (store.getCount() - 1);
+            xScale = bbox.width / ((storeCount - 1) || 1);
         }
         else {
-            //In case some person decides to set an axis' minimum and maximum
-            //configuration properties to the same value, then fallback the
-            //denominator to a > 0 value.
-            xScale = bbox.width / ((maxX - minX) || (store.getCount() - 1));
+            xScale = bbox.width / ((maxX - minX) || (storeCount -1) || 1);
         }
 
         if (isNaN(minY)) {
             minY = 0;
-            yScale = bbox.height / (store.getCount() - 1);
-        } 
+            yScale = bbox.height / ((storeCount - 1) || 1);
+        }
         else {
-            //In case some person decides to set an axis' minimum and maximum
-            //configuration properties to the same value, then fallback the
-            //denominator to a > 0 value.
-            yScale = bbox.height / ((maxY - minY) || (store.getCount() - 1));
+            yScale = bbox.height / ((maxY - minY) || (storeCount - 1) || 1);
         }
-        
-        store.each(function(record, i) {
+
+        // Extract all x and y values from the store
+        me.eachRecord(function(record, i) {
             xValue = record.get(me.xField);
+
+            // Ensure a value
+            if (typeof xValue == 'string' || typeof xValue == 'object' && !Ext.isDate(xValue)
+                //set as uniform distribution if the axis is a category axis.
+                || boundXAxis && chartAxes.get(boundXAxis) && chartAxes.get(boundXAxis).type == 'Category') {
+                    if (xValue in xValueMap) {
+                        xValue = xValueMap[xValue];
+                    } else {
+                        xValue = xValueMap[xValue] = i;
+                    }
+            }
+
+            // Filter out values that don't fit within the pan/zoom buffer area
             yValue = record.get(me.yField);
             //skip undefined values
             if (typeof yValue == 'undefined' || (typeof yValue == 'string' && !yValue)) {
@@ -49483,20 +51903,15 @@ Ext.define('Ext.chart.series.Line', {
                 return;
             }
             // Ensure a value
-            if (typeof xValue == 'string' || typeof xValue == 'object'
+            if (typeof yValue == 'string' || typeof yValue == 'object' && !Ext.isDate(yValue)
                 //set as uniform distribution if the axis is a category axis.
-                || (me.axis != 'top' && me.axis != 'bottom' && !numericAxis)) {
-                xValue = i;
-            }
-            if (typeof yValue == 'string' || typeof yValue == 'object'
-                //set as uniform distribution if the axis is a category axis.
-                || (me.axis != 'left' && me.axis != 'right' && !numericAxis)) {
+                || boundYAxis && chartAxes.get(boundYAxis) && chartAxes.get(boundYAxis).type == 'Category') {
                 yValue = i;
             }
             storeIndices.push(i);
             xValues.push(xValue);
             yValues.push(yValue);
-        }, me);
+        });
 
         ln = xValues.length;
         if (ln > bbox.width) {
@@ -49525,11 +51940,12 @@ Ext.define('Ext.chart.series.Line', {
                 if (onbreak) {
                     onbreak = false;
                     path.push('M');
-                } 
+                }
                 path = path.concat([x, y]);
             }
             if ((typeof firstY == 'undefined') && (typeof y != 'undefined')) {
                 firstY = y;
+                firstX = x;
             }
             // If this is the first line, create a dummypath to animate in from.
             if (!me.line || chart.resizing) {
@@ -49564,15 +51980,16 @@ Ext.define('Ext.chart.series.Line', {
                         group: [group, markerGroup],
                         x: 0, y: 0,
                         translate: {
-                            x: prevX || x, 
+                            x: +(prevX || x),
                             y: prevY || (bbox.y + bbox.height / 2)
                         },
-                        value: '"' + xValue + ', ' + yValue + '"'
+                        value: '"' + xValue + ', ' + yValue + '"',
+                        zIndex: 4000
                     }, endMarkerStyle));
                     marker._to = {
                         translate: {
-                            x: x,
-                            y: y
+                            x: +x,
+                            y: +y
                         }
                     };
                 } else {
@@ -49583,12 +52000,12 @@ Ext.define('Ext.chart.series.Line', {
                     }, true);
                     marker._to = {
                         translate: {
-                            x: x, y: y
+                            x: +x, 
+                            y: +y
                         }
                     };
                 }
             }
-
             me.items.push({
                 series: me,
                 value: [xValue, yValue],
@@ -49599,16 +52016,16 @@ Ext.define('Ext.chart.series.Line', {
             prevX = x;
             prevY = y;
         }
-        
+
         if (path.length <= 1) {
             //nothing to be rendered
-            return;    
+            return;
         }
-    
-        if (smooth) {
+
+        if (me.smooth) {
             smoothPath = Ext.draw.Draw.smooth(path, isNumber(smooth) ? smooth : me.defaultSmoothness);
         }
-        
+
         renderPath = smooth ? smoothPath : path;
 
         //Correct path if we're animating timeAxis intervals
@@ -49620,7 +52037,7 @@ Ext.define('Ext.chart.series.Line', {
         } else {
             fromPath = path;
         }
-        
+
         // Only create a line if one doesn't exist.
         if (!me.line) {
             me.line = surface.add(Ext.apply({
@@ -49629,9 +52046,15 @@ Ext.define('Ext.chart.series.Line', {
                 path: dummyPath,
                 stroke: endLineStyle.stroke || endLineStyle.fill
             }, endLineStyle || {}));
+
+            if (enableShadows) {
+                me.line.setAttributes(Ext.apply({}, me.shadowOptions), true);
+            }
+
             //unset fill here (there's always a default fill withing the themes).
             me.line.setAttributes({
-                fill: 'none'
+                fill: 'none',
+                zIndex: 3000
             });
             if (!endLineStyle.stroke && colorArrayLength) {
                 me.line.setAttributes({
@@ -49640,11 +52063,11 @@ Ext.define('Ext.chart.series.Line', {
             }
             if (enableShadows) {
                 //create shadows
-                shadows = me.line.shadows = [];                
+                shadows = me.line.shadows = [];
                 for (shindex = 0; shindex < lnsh; shindex++) {
                     shadowBarAttr = shadowAttributes[shindex];
                     shadowBarAttr = Ext.apply({}, shadowBarAttr, { path: dummyPath });
-                    shadow = chart.surface.add(Ext.apply({}, {
+                    shadow = surface.add(Ext.apply({}, {
                         type: 'path',
                         group: shadowGroups[shindex]
                     }, shadowBarAttr));
@@ -49655,8 +52078,8 @@ Ext.define('Ext.chart.series.Line', {
         if (me.fill) {
             fillPath = renderPath.concat([
                 ["L", x, bbox.y + bbox.height],
-                ["L", bbox.x, bbox.y + bbox.height],
-                ["L", bbox.x, firstY]
+                ["L", firstX, bbox.y + bbox.height],
+                ["L", firstX, firstY]
             ]);
             if (!me.fillPath) {
                 me.fillPath = surface.add({
@@ -49679,6 +52102,7 @@ Ext.define('Ext.chart.series.Line', {
             });
             //fill should not be used here but when drawing the special fill path object
             delete rendererAttributes.fill;
+            line.show(true);
             if (chart.markerIndex && me.previousPath) {
                 me.animation = animation = me.onAnimate(line, {
                     to: rendererAttributes,
@@ -49695,6 +52119,7 @@ Ext.define('Ext.chart.series.Line', {
             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 },
@@ -49709,10 +52134,12 @@ Ext.define('Ext.chart.series.Line', {
             }
             //animate fill path
             if (fill) {
+                me.fillPath.show(true);
                 me.onAnimate(me.fillPath, {
                     to: Ext.apply({}, {
                         path: fillPath,
-                        fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength]
+                        fill: endLineStyle.fill || colorArrayStyle[seriesIdx % colorArrayLength],
+                        'stroke-width': 0
                     }, endLineStyle || {})
                 });
             }
@@ -49727,13 +52154,18 @@ Ext.define('Ext.chart.series.Line', {
                             me.onAnimate(item, {
                                 to: Ext.apply(rendererAttributes, endMarkerStyle || {})
                             });
+                            item.show(true);
                         }
-                    } 
+                    }
                 }
                 for(; count < markerCount; count++) {
                     item = markerGroup.getAt(count);
                     item.hide(true);
                 }
+//                for(i = 0; i < (chart.markerIndex || 0)-1; i++) {
+//                    item = markerGroup.getAt(i);
+//                    item.hide(true);
+//                }
             }
         } else {
             rendererAttributes = me.renderer(me.line, false, { path: renderPath, hidden: false }, i, store);
@@ -49748,13 +52180,15 @@ Ext.define('Ext.chart.series.Line', {
                 shadows = me.line.shadows;
                 for(j = 0; j < lnsh; j++) {
                     shadows[j].setAttributes({
-                        path: renderPath
+                        path: renderPath,
+                        hidden: false
                     }, true);
                 }
             }
             if (me.fill) {
                 me.fillPath.setAttributes({
-                    path: fillPath
+                    path: fillPath,
+                    hidden: false
                 }, true);
             }
             if (showMarkers) {
@@ -49765,8 +52199,9 @@ Ext.define('Ext.chart.series.Line', {
                         if (item) {
                             rendererAttributes = me.renderer(item, store.getAt(i), item._to, i, store);
                             item.setAttributes(Ext.apply(endMarkerStyle || {}, rendererAttributes || {}), true);
+                            item.show(true);
                         }
-                    } 
+                    }
                 }
                 for(; count < markerCount; count++) {
                     item = markerGroup.getAt(count);
@@ -49785,8 +52220,10 @@ Ext.define('Ext.chart.series.Line', {
         }
         me.renderLabels();
         me.renderCallouts();
+
+        me.fireEvent('draw', me);
     },
-    
+
     // @private called when a label is to be created.
     onCreateLabel: function(storeItem, item, i, display) {
         var me = this,
@@ -49803,7 +52240,7 @@ Ext.define('Ext.chart.series.Line', {
             'y': bbox.y + bbox.height / 2
         }, endLabelStyle || {}));
     },
-    
+
     // @private called when a label is to be created.
     onPlaceLabel: function(label, storeItem, item, i, display, animate) {
         var me = this,
@@ -49817,12 +52254,12 @@ Ext.define('Ext.chart.series.Line', {
             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',
@@ -49839,7 +52276,7 @@ Ext.define('Ext.chart.series.Line', {
             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') {
             //TODO(nicolas): find out why width/height values in circle bounding boxes are undefined.
             bb = item.sprite.getBBox();
@@ -49855,7 +52292,7 @@ Ext.define('Ext.chart.series.Line', {
             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, {
@@ -49869,7 +52306,7 @@ Ext.define('Ext.chart.series.Line', {
                 x: x,
                 y: y
             }, true);
-            if (resizing) {
+            if (resizing && me.animation) {
                 me.animation.on('afteranimate', function() {
                     label.show(true);
                 });
@@ -49883,20 +52320,20 @@ Ext.define('Ext.chart.series.Line', {
     highlightItem: function() {
         var me = this;
         me.callParent(arguments);
-        if (this.line && !this.highlighted) {
-            if (!('__strokeWidth' in this.line)) {
-                this.line.__strokeWidth = this.line.attr['stroke-width'] || 0;
+        if (me.line && !me.highlighted) {
+            if (!('__strokeWidth' in me.line)) {
+                me.line.__strokeWidth = me.line.attr['stroke-width'] || 0;
             }
-            if (this.line.__anim) {
-                this.line.__anim.paused = true;
+            if (me.line.__anim) {
+                me.line.__anim.paused = true;
             }
-            this.line.__anim = Ext.create('Ext.fx.Anim', {
-                target: this.line,
+            me.line.__anim = Ext.create('Ext.fx.Anim', {
+                target: me.line,
                 to: {
-                    'stroke-width': this.line.__strokeWidth + 3
+                    'stroke-width': me.line.__strokeWidth + 3
                 }
             });
-            this.highlighted = true;
+            me.highlighted = true;
         }
     },
 
@@ -49904,14 +52341,14 @@ Ext.define('Ext.chart.series.Line', {
     unHighlightItem: function() {
         var me = this;
         me.callParent(arguments);
-        if (this.line && this.highlighted) {
-            this.line.__anim = Ext.create('Ext.fx.Anim', {
-                target: this.line,
+        if (me.line && me.highlighted) {
+            me.line.__anim = Ext.create('Ext.fx.Anim', {
+                target: me.line,
                 to: {
-                    'stroke-width': this.line.__strokeWidth
+                    'stroke-width': me.line.__strokeWidth
                 }
             });
-            this.highlighted = false;
+            me.highlighted = false;
         }
     },
 
@@ -49920,7 +52357,7 @@ Ext.define('Ext.chart.series.Line', {
         if (!display) {
             return;
         }
-        
+
         var me = this,
             chart = me.chart,
             surface = chart.surface,
@@ -49952,11 +52389,11 @@ Ext.define('Ext.chart.series.Line', {
         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]];
-        
+
         //keep the label always on the outer part of the "elbow"
         if (aprev > 0 && anext < 0 && normal[1] < 0
             || aprev < 0 && anext > 0 && normal[1] > 0) {
@@ -49976,7 +52413,7 @@ Ext.define('Ext.chart.series.Line', {
         boxy = y - bbox.height /2 - offsetBox;
         boxw = bbox.width + 2 * offsetBox;
         boxh = bbox.height + 2 * offsetBox;
-        
+
         //now check if we're out of bounds and invert the normal vector correspondingly
         //this may add new overlaps between labels (but labels won't be out of bounds).
         if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
@@ -49989,13 +52426,13 @@ Ext.define('Ext.chart.series.Line', {
         //update positions
         x = cur[0] + normal[0] * offsetFromViz;
         y = cur[1] + normal[1] * offsetFromViz;
-        
+
         //update box position and dimensions
         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) {
             //set the line from the middle of the pie to the box.
             me.onAnimate(callout.lines, {
@@ -50022,7 +52459,7 @@ Ext.define('Ext.chart.series.Line', {
             callout[p].show(true);
         }
     },
-    
+
     isItemInPoint: function(x, y, item, i) {
         var me = this,
             items = me.items,
@@ -50041,10 +52478,10 @@ Ext.define('Ext.chart.series.Line', {
             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];
         }
@@ -50057,22 +52494,22 @@ Ext.define('Ext.chart.series.Line', {
         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;
     },
-    
+
     // @private toggle visibility of all series elements (markers, sprites).
     toggleAll: function(show) {
         var me = this,
             i, ln, shadow, shadows;
         if (!show) {
-            Ext.chart.series.Line.superclass.hideAll.call(me);
+            Ext.chart.series.Cartesian.prototype.hideAll.call(me);
         }
         else {
-            Ext.chart.series.Line.superclass.showAll.call(me);
+            Ext.chart.series.Cartesian.prototype.showAll.call(me);
         }
         if (me.line) {
             me.line.setAttributes({
@@ -50094,43 +52531,43 @@ Ext.define('Ext.chart.series.Line', {
             }, true);
         }
     },
-    
+
     // @private hide all series elements (markers, sprites).
     hideAll: function() {
         this.toggleAll(false);
     },
-    
+
     // @private hide all series elements (markers, sprites).
     showAll: function() {
         this.toggleAll(true);
     }
 });
+
 /**
  * @class Ext.chart.series.Pie
  * @extends Ext.chart.series.Series
- * 
- * Creates a Pie Chart. A Pie Chart is a useful visualization technique to display quantitative information for different 
+ *
+ * Creates a Pie Chart. A Pie Chart is a useful visualization technique to display quantitative information for different
  * categories that also have a meaning as a whole.
- * As with all other series, the Pie Series must be appended in the *series* Chart array configuration. See the Chart 
+ * As with all other series, the Pie Series must be appended in the *series* Chart array configuration. See the Chart
  * documentation for more information. A typical configuration object for the pie series could be:
- * 
- * {@img Ext.chart.series.Pie/Ext.chart.series.Pie.png Ext.chart.series.Pie chart series}
  *
+ *     @example
  *     var store = Ext.create('Ext.data.JsonStore', {
  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
  *         data: [
- *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
+ *             { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
+ *             { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
+ *             { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
+ *             { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
+ *             { 'name': 'metric five',  'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
  *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.chart.Chart', {
  *         renderTo: Ext.getBody(),
  *         width: 500,
- *         height: 300,
+ *         height: 350,
  *         animate: true,
  *         store: store,
  *         theme: 'Base:gradients',
@@ -50139,22 +52576,22 @@ Ext.define('Ext.chart.series.Line', {
  *             field: 'data1',
  *             showInLegend: true,
  *             tips: {
- *               trackMouse: true,
- *               width: 140,
- *               height: 28,
- *               renderer: function(storeItem, item) {
- *                 //calculate and display percentage on hover
- *                 var total = 0;
- *                 store.each(function(rec) {
- *                     total += rec.get('data1');
- *                 });
- *                 this.setTitle(storeItem.get('name') + ': ' + Math.round(storeItem.get('data1') / total * 100) + '%');
- *               }
+ *                 trackMouse: true,
+ *                 width: 140,
+ *                 height: 28,
+ *                 renderer: function(storeItem, item) {
+ *                     // calculate and display percentage on hover
+ *                     var total = 0;
+ *                     store.each(function(rec) {
+ *                         total += rec.get('data1');
+ *                     });
+ *                     this.setTitle(storeItem.get('name') + ': ' + Math.round(storeItem.get('data1') / total * 100) + '%');
+ *                 }
  *             },
  *             highlight: {
- *               segment: {
- *                 margin: 20
- *               }
+ *                 segment: {
+ *                     margin: 20
+ *                 }
  *             },
  *             label: {
  *                 field: 'name',
@@ -50162,16 +52599,18 @@ Ext.define('Ext.chart.series.Line', {
  *                 contrast: true,
  *                 font: '18px Arial'
  *             }
- *         }]    
+ *         }]
  *     });
- * 
- * In this configuration we set `pie` as the type for the series, set an object with specific style properties for highlighting options 
- * (triggered when hovering elements). We also set true to `showInLegend` so all the pie slices can be represented by a legend item. 
- * We set `data1` as the value of the field to determine the angle span for each pie slice. We also set a label configuration object 
- * where we set the field name of the store field to be renderer as text for the label. The labels will also be displayed rotated. 
- * We set `contrast` to `true` to flip the color of the label if it is to similar to the background color. Finally, we set the font family 
- * and size through the `font` parameter. 
- * 
+ *
+ * In this configuration we set `pie` as the type for the series, set an object with specific style properties for highlighting options
+ * (triggered when hovering elements). We also set true to `showInLegend` so all the pie slices can be represented by a legend item.
+ *
+ * We set `data1` as the value of the field to determine the angle span for each pie slice. We also set a label configuration object
+ * where we set the field name of the store field to be renderer as text for the label. The labels will also be displayed rotated.
+ *
+ * We set `contrast` to `true` to flip the color of the label if it is to similar to the background color. Finally, we set the font family
+ * and size through the `font` parameter.
+ *
  * @xtype pie
  */
 Ext.define('Ext.chart.series.Pie', {
@@ -50185,7 +52624,7 @@ Ext.define('Ext.chart.series.Pie', {
     /* End Definitions */
 
     type: "pie",
-    
+
     alias: 'series.pie',
 
     rad: Math.PI / 180,
@@ -50197,10 +52636,9 @@ Ext.define('Ext.chart.series.Pie', {
     highlightDuration: 150,
 
     /**
-     * @cfg {String} angleField
+     * @cfg {String} angleField (required)
      * The store record field name to be used for the pie angles.
      * The values bound to this field name must be positive real numbers.
-     * This parameter is required.
      */
     angleField: false,
 
@@ -50208,12 +52646,11 @@ Ext.define('Ext.chart.series.Pie', {
      * @cfg {String} lengthField
      * The store record field name to be used for the pie slice lengths.
      * The values bound to this field name must be positive real numbers.
-     * This parameter is optional.
      */
     lengthField: false,
 
     /**
-     * @cfg {Boolean|Number} donut
+     * @cfg {Boolean/Number} donut
      * Whether to set the pie chart as donut chart.
      * Default's false. Can be set to a particular percentage to set the radius
      * of the donut chart.
@@ -50230,13 +52667,13 @@ Ext.define('Ext.chart.series.Pie', {
      * @cfg {Array} colorSet
      * An array of color values which will be used, in order, as the pie slice fill colors.
      */
-    
+
     /**
      * @cfg {Object} style
      * An object containing styles for overriding series styles from Theming.
      */
     style: {},
-    
+
     constructor: function(config) {
         this.callParent(arguments);
         var me = this,
@@ -50251,7 +52688,7 @@ Ext.define('Ext.chart.series.Pie', {
                 }
             }
         });
-        Ext.apply(me, config, {            
+        Ext.apply(me, config, {
             shadowAttributes: [{
                 "stroke-width": 6,
                 "stroke-opacity": 1,
@@ -50289,12 +52726,13 @@ Ext.define('Ext.chart.series.Pie', {
         surface.customAttributes.segment = function(opt) {
             return me.getSegment(opt);
         };
+        me.__excludes = me.__excludes || [];
     },
-    
+
     //@private updates some onbefore render parameters.
     initialize: function() {
         var me = this,
-            store = me.chart.substore || me.chart.store;
+            store = me.chart.getChartStore();
         //Add yFields to be used in Legend.js
         me.yField = [];
         if (me.label.field) {
@@ -50310,58 +52748,81 @@ Ext.define('Ext.chart.series.Pie', {
             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,
+            x5 = 0, y5 = 0, x6 = 0, y6 = 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);
+            c1 = cos(a1), s1 = sin(a1),
+            c2 = cos(a2), s2 = sin(a2),
+            cm = cos(midAngle), sm = sin(midAngle),
+            flag = 0, hsqr2 = 0.7071067811865476; // sqrt(0.5)
 
-        x1 = x + opt.startRho * cos(a1);
-        y1 = y + opt.startRho * sin(a1);
+        if (a2 - a1 < delta) {
+            return {path: ""};
+        }
 
-        x2 = x + opt.endRho * cos(a1);
-        y2 = y + opt.endRho * sin(a1);
+        if (margin !== 0) {
+            x += margin * cm;
+            y += margin * sm;
+        }
 
-        x3 = x + opt.startRho * cos(a2);
-        y3 = y + opt.startRho * sin(a2);
+        x2 = x + opt.endRho * c1;
+        y2 = y + opt.endRho * s1;
 
-        x4 = x + opt.endRho * cos(a2);
-        y4 = y + opt.endRho * sin(a2);
+        x4 = x + opt.endRho * c2;
+        y4 = y + opt.endRho * s2;
 
-        if (abs(x1 - x3) <= delta && abs(y1 - y3) <= delta) {
-            singleSlice = true;
+        if (Math.abs(x2 - x4) + Math.abs(y2 - y4) < delta) {
+            cm = hsqr2;
+            sm = -hsqr2;
+            flag = 1;
         }
-        //Solves mysterious clipping bug with IE
-        if (singleSlice) {
+
+        x6 = x + opt.endRho * cm;
+        y6 = y + opt.endRho * sm;
+
+        // TODO(bei): It seems that the canvas engine cannot render half circle command correctly on IE.
+        // Better fix the VML engine for half circles.
+
+        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", x1, y1],
-                ["L", x2, y2],
-                ["A", opt.endRho, opt.endRho, 0, +flag, 1, x4, y4],
-                ["Z"]]
+                    ["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", 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"]]
+                    ["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"]
+                ]
             };
         }
     },
@@ -50376,11 +52837,10 @@ Ext.define('Ext.chart.series.Pie', {
             startAngle = slice.startAngle,
             endAngle = slice.endAngle,
             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);
+            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,
@@ -50393,7 +52853,7 @@ Ext.define('Ext.chart.series.Pie', {
      */
     drawSeries: function() {
         var me = this,
-            store = me.chart.substore || me.chart.store,
+            store = me.chart.getChartStore(),
             group = me.group,
             animate = me.chart.animate,
             field = me.angleField || me.field || me.xField,
@@ -50427,6 +52887,7 @@ Ext.define('Ext.chart.series.Pie', {
             colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
             gutterX = chart.maxGutter[0],
             gutterY = chart.maxGutter[1],
+            abs = Math.abs,
             rendererAttributes,
             shadowGroup,
             shadowAttr,
@@ -50454,7 +52915,7 @@ Ext.define('Ext.chart.series.Pie', {
             path,
             p,
             spriteOptions, bbox;
-        
+
         Ext.apply(seriesStyle, me.style || {});
 
         me.setBBox();
@@ -50465,12 +52926,12 @@ Ext.define('Ext.chart.series.Pie', {
             colorArrayStyle = me.colorSet;
             colorArrayLength = colorArrayStyle.length;
         }
-        
+
         //if not store or store is empty then there's nothing to draw
         if (!store || !store.getCount()) {
             return;
         }
-        
+
         me.unHighlightItem();
         me.cleanHighlights();
 
@@ -50495,25 +52956,26 @@ Ext.define('Ext.chart.series.Pie', {
             }
         }, this);
 
+        totalField = totalField || 1;
         store.each(function(record, i) {
             if (this.__excludes && this.__excludes[i]) {
-                //hidden series
-                return;
-            } 
-            value = record.get(field);
-            middleAngle = angle - 360 * value / totalField / 2;
-            // TODO - Put up an empty circle
-            if (isNaN(middleAngle)) {
-                middleAngle = 360;
-                value = 1;
-                totalField = 1;
+                value = 0;
+            } else {
+                value = record.get(field);
+                if (first == 0) {
+                    first = 1;
+                }
             }
+
             // First slice
-            if (!i || first == 0) {
-                angle = 360 - middleAngle;
-                me.firstAngle = angle;
-                middleAngle = angle - 360 * value / totalField / 2;
+            if (first == 1) {
+                first = 2;
+                me.firstAngle = angle = 360 * value / totalField / 2;
+                for (j = 0; j < i; j++) {
+                    slices[j].startAngle = slices[j].endAngle = me.firstAngle;
+                }
             }
+            
             endAngle = angle - 360 * value / totalField;
             slice = {
                 series: me,
@@ -50529,20 +52991,11 @@ Ext.define('Ext.chart.series.Pie', {
                 slice.rho = me.radius;
             }
             slices[i] = slice;
-            if((slice.startAngle % 360) == (slice.endAngle % 360)) {
-                slice.startAngle -= 0.0001;
-            }
             angle = endAngle;
-            first++;
         }, me);
-        
         //do all shadows first.
         if (enableShadows) {
             for (i = 0, ln = slices.length; i < ln; i++) {
-                if (this.__excludes && this.__excludes[i]) {
-                    //hidden series
-                    continue;
-                }
                 slice = slices[i];
                 slice.shadowAttrs = [];
                 for (j = 0, rhoAcum = 0, shadows = []; j < layers; j++) {
@@ -50557,7 +53010,8 @@ Ext.define('Ext.chart.series.Pie', {
                             rho: slice.rho,
                             startRho: rhoAcum + (deltaRho * donut / 100),
                             endRho: rhoAcum + deltaRho
-                        }
+                        },
+                        hidden: !slice.value && (slice.startAngle % 360) == (slice.endAngle % 360)
                     };
                     //create shadows
                     for (shindex = 0, shadows = []; shindex < lnsh; shindex++) {
@@ -50576,9 +53030,7 @@ Ext.define('Ext.chart.series.Pie', {
                                 to: shadowAttr
                             });
                         } else {
-                            shadowAttr = me.renderer(shadow, store.getAt(i), Ext.apply(shadowAttr, {
-                                hidden: false
-                            }), i, store);
+                            shadowAttr = me.renderer(shadow, store.getAt(i), shadowAttr, i, store);
                             shadow.setAttributes(shadowAttr, true);
                         }
                         shadows.push(shadow);
@@ -50589,10 +53041,6 @@ Ext.define('Ext.chart.series.Pie', {
         }
         //do pie slices after.
         for (i = 0, ln = slices.length; i < ln; i++) {
-            if (this.__excludes && this.__excludes[i]) {
-                //hidden series
-                continue;
-            }
             slice = slices[i];
             for (j = 0, rhoAcum = 0; j < layers; j++) {
                 sprite = group.getAt(i * layers + j);
@@ -50606,7 +53054,8 @@ Ext.define('Ext.chart.series.Pie', {
                         rho: slice.rho,
                         startRho: rhoAcum + (deltaRho * donut / 100),
                         endRho: rhoAcum + deltaRho
-                    } 
+                    },
+                    hidden: (!slice.value && (slice.startAngle % 360) == (slice.endAngle % 360))
                 }, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[(layers > 1? j : i) % colorArrayLength] } || {}));
                 item = Ext.apply({},
                 rendererAttributes.segment, {
@@ -50657,7 +53106,7 @@ Ext.define('Ext.chart.series.Pie', {
                 rhoAcum += deltaRho;
             }
         }
-        
+
         // Hide unused bars
         ln = group.getCount();
         for (i = 0; i < ln; i++) {
@@ -50690,7 +53139,7 @@ Ext.define('Ext.chart.series.Pie', {
             centerY = me.centerY,
             middle = item.middle,
             endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config || {});
-        
+
         return me.chart.surface.add(Ext.apply({
             'type': 'text',
             'text-anchor': 'middle',
@@ -50722,9 +53171,13 @@ Ext.define('Ext.chart.series.Pie', {
             theta = Math.atan2(y, x || 1),
             dg = theta * 180 / Math.PI,
             prevDg;
-        
+        if (this.__excludes && this.__excludes[i]) {
+            opt.hidden = true;
+        }
         function fixAngle(a) {
-            if (a < 0) a += 360;
+            if (a < 0) {
+                a += 360;
+            }
             return a % 360;
         }
 
@@ -50768,7 +53221,7 @@ Ext.define('Ext.chart.series.Pie', {
         }
         //ensure the object has zero translation
         opt.translate = {
-            x: 0, y: 0    
+            x: 0, y: 0
         };
         if (animate && !resizing && (display != 'rotate' || prevDg != null)) {
             me.onAnimate(label, {
@@ -50879,8 +53332,8 @@ Ext.define('Ext.chart.series.Pie', {
             startAngle = item.startAngle,
             endAngle = item.endAngle,
             rho = Math.sqrt(dx * dx + dy * dy),
-            angle = Math.atan2(y - cy, x - cx) / me.rad + 360;
-        
+            angle = Math.atan2(y - cy, x - cx) / me.rad;
+
         // normalize to the same range of angles created by drawSeries
         if (angle > me.firstAngle) {
             angle -= 360;
@@ -50888,7 +53341,7 @@ Ext.define('Ext.chart.series.Pie', {
         return (angle <= startAngle && angle > endAngle
                 && rho >= item.startRho && rho <= item.endRho);
     },
-    
+
     // @private hides all elements in the series.
     hideAll: function() {
         var i, l, shadow, shadows, sh, lsh, sprite;
@@ -50914,7 +53367,7 @@ Ext.define('Ext.chart.series.Pie', {
             this.drawSeries();
         }
     },
-    
+
     // @private shows all elements in the series.
     showAll: function() {
         if (!isNaN(this._index)) {
@@ -50931,13 +53384,13 @@ Ext.define('Ext.chart.series.Pie', {
         var me = this,
             rad = me.rad;
         item = item || this.items[this._index];
-        
+
         //TODO(nico): sometimes in IE itemmouseover is triggered
         //twice without triggering itemmouseout in between. This
         //fixes the highlighting bug. Eventually, events should be
         //changed to trigger one itemmouseout between two itemmouseovers.
         this.unHighlightItem();
-        
+
         if (!item || item.sprite && item.sprite._animating) {
             return;
         }
@@ -50970,7 +53423,7 @@ Ext.define('Ext.chart.series.Pie', {
                 if (Math.abs(y) < 1e-10) {
                     y = 0;
                 }
-                
+
                 if (animate) {
                     label.stopAnimation();
                     label.animate({
@@ -51025,7 +53478,7 @@ Ext.define('Ext.chart.series.Pie', {
     },
 
     /**
-     * un-highlights the specified item. If no item is provided it will un-highlight the entire series.
+     * Un-highlights the specified item. If no item is provided it will un-highlight the entire series.
      * @param item {Object} Info about the item; same format as returned by #getItemForPoint
      */
     unHighlightItem: function() {
@@ -51112,7 +53565,7 @@ Ext.define('Ext.chart.series.Pie', {
         }
         me.callParent(arguments);
     },
-    
+
     /**
      * Returns the color of the series (to be displayed as color for the series legend item).
      * @param item {Object} Info about the item; same format as returned by #getItemForPoint
@@ -51127,25 +53580,25 @@ Ext.define('Ext.chart.series.Pie', {
 /**
  * @class Ext.chart.series.Radar
  * @extends Ext.chart.series.Series
- * 
- * Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for 
+ *
+ * Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for
  * a constrained number of categories.
- * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart 
+ *
+ * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
  * documentation for more information. A typical configuration object for the radar series could be:
- * 
- * {@img Ext.chart.series.Radar/Ext.chart.series.Radar.png Ext.chart.series.Radar chart series}  
  *
+ *     @example
  *     var store = Ext.create('Ext.data.JsonStore', {
  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
  *         data: [
- *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
+ *             { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
+ *             { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
+ *             { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
+ *             { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
+ *             { 'name': 'metric five',  'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
  *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.chart.Chart', {
  *         renderTo: Ext.getBody(),
  *         width: 500,
@@ -51168,7 +53621,7 @@ Ext.define('Ext.chart.series.Pie', {
  *             showMarkers: true,
  *             markerConfig: {
  *                 radius: 5,
- *                 size: 5           
+ *                 size: 5
  *             },
  *             style: {
  *                 'stroke-width': 2,
@@ -51202,13 +53655,15 @@ Ext.define('Ext.chart.series.Pie', {
  *                 'stroke-width': 2,
  *                 fill: 'none'
  *             }
- *         }]    
+ *         }]
  *     });
- * 
- * In this configuration we add three series to the chart. Each of these series is bound to the same categories field, `name` but bound to different properties for each category,
- * `data1`, `data2` and `data3` respectively. All series display markers by having `showMarkers` enabled. The configuration for the markers of each series can be set by adding properties onto 
- * the markerConfig object. Finally we override some theme styling properties by adding properties to the `style` object.
- * 
+ *
+ * In this configuration we add three series to the chart. Each of these series is bound to the same
+ * categories field, `name` but bound to different properties for each category, `data1`, `data2` and
+ * `data3` respectively. All series display markers by having `showMarkers` enabled. The configuration
+ * for the markers of each series can be set by adding properties onto the markerConfig object.
+ * Finally we override some theme styling properties by adding properties to the `style` object.
+ *
  * @xtype radar
  */
 Ext.define('Ext.chart.series.Radar', {
@@ -51224,7 +53679,7 @@ Ext.define('Ext.chart.series.Radar', {
     type: "radar",
     alias: 'series.radar',
 
-    
+
     rad: Math.PI / 180,
 
     showInLegend: false,
@@ -51234,7 +53689,7 @@ Ext.define('Ext.chart.series.Radar', {
      * An object containing styles for overriding series styles from Theming.
      */
     style: {},
-    
+
     constructor: function(config) {
         this.callParent(arguments);
         var me = this,
@@ -51250,7 +53705,7 @@ Ext.define('Ext.chart.series.Radar', {
      */
     drawSeries: function() {
         var me = this,
-            store = me.chart.substore || me.chart.store,
+            store = me.chart.getChartStore(),
             group = me.group,
             sprite,
             chart = me.chart,
@@ -51276,18 +53731,18 @@ Ext.define('Ext.chart.series.Radar', {
             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 the store is empty then there's nothing to draw
         if (!store || !store.getCount()) {
             return;
         }
-        
+
         me.unHighlightItem();
         me.cleanHighlights();
 
@@ -51363,7 +53818,7 @@ Ext.define('Ext.chart.series.Radar', {
         me.renderLabels();
         me.renderCallouts();
     },
-    
+
     // @private draws the markers for the lines (if any).
     drawMarkers: function() {
         var me = this,
@@ -51371,15 +53826,15 @@ Ext.define('Ext.chart.series.Radar', {
             surface = chart.surface,
             markerStyle = Ext.apply({}, me.markerStyle || {}),
             endMarkerStyle = Ext.apply(markerStyle, me.markerConfig),
-            items = me.items, 
+            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);
@@ -51424,7 +53879,7 @@ Ext.define('Ext.chart.series.Radar', {
             }
         }
     },
-    
+
     isItemInPoint: function(x, y, item) {
         var point,
             tolerance = 10,
@@ -51443,7 +53898,7 @@ Ext.define('Ext.chart.series.Radar', {
             centerY = me.centerY,
             point = item.point,
             endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);
-        
+
         return me.chart.surface.add(Ext.apply({
             'type': 'text',
             'text-anchor': 'middle',
@@ -51475,14 +53930,14 @@ Ext.define('Ext.chart.series.Radar', {
             hidden: true
         },
         true);
-        
+
         if (resizing) {
             label.setAttributes({
                 x: centerX,
                 y: centerY
             }, true);
         }
-        
+
         if (animate) {
             label.show(true);
             me.onAnimate(label, {
@@ -51494,7 +53949,7 @@ Ext.define('Ext.chart.series.Radar', {
         }
     },
 
-    // @private for toggling (show/hide) series. 
+    // @private for toggling (show/hide) series.
     toggleAll: function(show) {
         var me = this,
             i, ln, shadow, shadows;
@@ -51519,18 +53974,18 @@ Ext.define('Ext.chart.series.Radar', {
             }
         }
     },
-    
+
     // @private hide all elements in the series.
     hideAll: function() {
         this.toggleAll(false);
         this.hideMarkers(0);
     },
-    
+
     // @private show all elements in the series.
     showAll: function() {
         this.toggleAll(true);
     },
-    
+
     // @private hide all markers that belong to `markerGroup`
     hideMarkers: function(index) {
         var me = this,
@@ -51546,25 +54001,24 @@ Ext.define('Ext.chart.series.Radar', {
 /**
  * @class Ext.chart.series.Scatter
  * @extends Ext.chart.series.Cartesian
- * 
- * Creates a Scatter Chart. The scatter plot is useful when trying to display more than two variables in the same visualization. 
+ *
+ * Creates a Scatter Chart. The scatter plot is useful when trying to display more than two variables in the same visualization.
  * These variables can be mapped into x, y coordinates and also to an element's radius/size, color, etc.
- * As with all other series, the Scatter Series must be appended in the *series* Chart array configuration. See the Chart 
+ * As with all other series, the Scatter Series must be appended in the *series* Chart array configuration. See the Chart
  * documentation for more information on creating charts. A typical configuration object for the scatter could be:
  *
- * {@img Ext.chart.series.Scatter/Ext.chart.series.Scatter.png Ext.chart.series.Scatter chart series}  
- *
+ *     @example
  *     var store = Ext.create('Ext.data.JsonStore', {
  *         fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
  *         data: [
- *             {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
- *             {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
- *             {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
- *             {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
- *             {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}                                                
+ *             { 'name': 'metric one',   'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8,  'data5': 13 },
+ *             { 'name': 'metric two',   'data1': 7,  'data2': 8,  'data3': 16, 'data4': 10, 'data5': 3  },
+ *             { 'name': 'metric three', 'data1': 5,  'data2': 2,  'data3': 14, 'data4': 12, 'data5': 7  },
+ *             { 'name': 'metric four',  'data1': 2,  'data2': 14, 'data3': 6,  'data4': 1,  'data5': 23 },
+ *             { 'name': 'metric five',  'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
  *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.chart.Chart', {
  *         renderTo: Ext.getBody(),
  *         width: 500,
@@ -51574,14 +54028,14 @@ Ext.define('Ext.chart.series.Radar', {
  *         store: store,
  *         axes: [{
  *             type: 'Numeric',
- *             position: 'bottom',
- *             fields: ['data1', 'data2', 'data3'],
+ *             position: 'left',
+ *             fields: ['data2', 'data3'],
  *             title: 'Sample Values',
  *             grid: true,
  *             minimum: 0
  *         }, {
  *             type: 'Category',
- *             position: 'left',
+ *             position: 'bottom',
  *             fields: ['name'],
  *             title: 'Sample Metrics'
  *         }],
@@ -51603,14 +54057,14 @@ Ext.define('Ext.chart.series.Radar', {
  *             axis: 'left',
  *             xField: 'name',
  *             yField: 'data3'
- *         }]   
+ *         }]
  *     });
- * 
- * In this configuration we add three different categories of scatter series. Each of them is bound to a different field of the same data store, 
- * `data1`, `data2` and `data3` respectively. All x-fields for the series must be the same field, in this case `name`. 
- * Each scatter series has a different styling configuration for markers, specified by the `markerConfig` object. Finally we set the left axis as 
+ *
+ * In this configuration we add three different categories of scatter series. Each of them is bound to a different field of the same data store,
+ * `data1`, `data2` and `data3` respectively. All x-fields for the series must be the same field, in this case `name`.
+ * Each scatter series has a different styling configuration for markers, specified by the `markerConfig` object. Finally we set the left axis as
  * axis to show the current values of the elements.
- * 
+ *
  * @xtype scatter
  */
 Ext.define('Ext.chart.series.Scatter', {
@@ -51630,11 +54084,18 @@ Ext.define('Ext.chart.series.Scatter', {
      * @cfg {Object} markerConfig
      * The display style for the scatter series markers.
      */
-    
+
     /**
-     * @cfg {Object} style 
+     * @cfg {Object} style
      * Append styling properties to this object for it to override theme properties.
      */
+    
+    /**
+     * @cfg {String/Array} axis
+     * The position of the axis to bind the values to. Possible values are 'left', 'bottom', 'top' and 'right'.
+     * You must explicitly set this value to bind the values of the line series to the ones in the axis, otherwise a
+     * relative scale will be used. If multiple axes are being used, they should both be specified in in the configuration.
+     */
 
     constructor: function(config) {
         this.callParent(arguments);
@@ -51670,14 +54131,14 @@ Ext.define('Ext.chart.series.Scatter', {
     getBounds: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             axes = [].concat(me.axis),
             bbox, xScale, yScale, ln, minX, minY, maxX, maxY, i, axis, ends;
 
         me.setBBox();
         bbox = me.bbox;
 
-        for (i = 0, ln = axes.length; i < ln; i++) { 
+        for (i = 0, ln = axes.length; i < ln; i++) {
             axis = chart.axes.get(axes[i]);
             if (axis) {
                 ends = axis.calcEnds();
@@ -51722,7 +54183,7 @@ Ext.define('Ext.chart.series.Scatter', {
             minY = 0;
             maxY = store.getCount() - 1;
             yScale = bbox.height / (store.getCount() - 1);
-        } 
+        }
         else {
             yScale = bbox.height / (maxY - minY);
         }
@@ -51741,7 +54202,7 @@ Ext.define('Ext.chart.series.Scatter', {
         var me = this,
             chart = me.chart,
             enableShadows = chart.shadow,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             group = me.group,
             bounds = me.bounds = me.getBounds(),
             bbox = me.bbox,
@@ -51769,10 +54230,10 @@ Ext.define('Ext.chart.series.Scatter', {
                 return;
             }
             // Ensure a value
-            if (typeof xValue == 'string' || typeof xValue == 'object') {
+            if (typeof xValue == 'string' || typeof xValue == 'object' && !Ext.isDate(xValue)) {
                 xValue = i;
             }
-            if (typeof yValue == 'string' || typeof yValue == 'object') {
+            if (typeof yValue == 'string' || typeof yValue == 'object' && !Ext.isDate(yValue)) {
                 yValue = i;
             }
             x = boxX + (xValue - minX) * xScale;
@@ -51898,7 +54359,7 @@ Ext.define('Ext.chart.series.Scatter', {
     drawSeries: function() {
         var me = this,
             chart = me.chart,
-            store = chart.substore || chart.store,
+            store = chart.getChartStore(),
             group = me.group,
             enableShadows = chart.shadow,
             shadowGroups = me.shadowGroups,
@@ -51945,23 +54406,28 @@ Ext.define('Ext.chart.series.Scatter', {
                 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), Ext.apply({ translate: attr }, { hidden: false }), i, store);
+                rendererAttributes = me.renderer(sprite, store.getAt(i), { translate: attr }, i, store);
+                sprite._to = rendererAttributes;
                 sprite.setAttributes(rendererAttributes, true);
-                //update shadows
+                //animate shadows
                 for (shindex = 0; shindex < lnsh; shindex++) {
-                    shadowAttribute = shadowAttributes[shindex];
-                    rendererAttributes = me.renderer(shadows[shindex], store.getAt(i), Ext.apply({ 
-                        x: attr.x,
-                        y: attr.y
+                    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);
                 }
@@ -51977,7 +54443,7 @@ Ext.define('Ext.chart.series.Scatter', {
         me.renderLabels();
         me.renderCallouts();
     },
-    
+
     // @private callback for when creating a label sprite.
     onCreateLabel: function(storeItem, item, i, display) {
         var me = this,
@@ -51985,7 +54451,7 @@ Ext.define('Ext.chart.series.Scatter', {
             config = me.label,
             endLabelStyle = Ext.apply({}, config, me.seriesLabelStyle),
             bbox = me.bbox;
-        
+
         return me.chart.surface.add(Ext.apply({
             type: 'text',
             group: group,
@@ -51993,7 +54459,7 @@ Ext.define('Ext.chart.series.Scatter', {
             y: bbox.y + bbox.height / 2
         }, endLabelStyle));
     },
-    
+
     // @private callback for when placing a label sprite.
     onPlaceLabel: function(label, storeItem, item, i, display, animate) {
         var me = this,
@@ -52007,12 +54473,12 @@ Ext.define('Ext.chart.series.Scatter', {
             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',
@@ -52029,7 +54495,7 @@ Ext.define('Ext.chart.series.Scatter', {
             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') {
             //TODO(nicolas): find out why width/height values in circle bounding boxes are undefined.
             bb = item.sprite.getBBox();
@@ -52063,7 +54529,7 @@ Ext.define('Ext.chart.series.Scatter', {
                             y: y
                         }, true);
                         label.show(true);
-                    });   
+                    });
                 }
                 else {
                     label.show(true);
@@ -52079,8 +54545,8 @@ Ext.define('Ext.chart.series.Scatter', {
             }
         }
     },
-    
-    // @private callback for when placing a callout sprite.    
+
+    // @private callback for when placing a callout sprite.
     onPlaceCallout: function(callout, storeItem, item, i, display, animate, index) {
         var me = this,
             chart = me.chart,
@@ -52097,18 +54563,18 @@ Ext.define('Ext.chart.series.Scatter', {
             boxx, boxy, boxw, boxh,
             p, clipRect = me.bbox,
             x, y;
-    
+
         //position
         normal = [Math.cos(Math.PI /4), -Math.sin(Math.PI /4)];
         x = cur[0] + normal[0] * offsetFromViz;
         y = cur[1] + normal[1] * offsetFromViz;
-        
+
         //box position and dimensions
         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;
-        
+
         //now check if we're out of bounds and invert the normal vector correspondingly
         //this may add new overlaps between labels (but labels won't be out of bounds).
         if (boxx < clipRect[0] || (boxx + boxw) > (clipRect[0] + clipRect[2])) {
@@ -52117,17 +54583,17 @@ Ext.define('Ext.chart.series.Scatter', {
         if (boxy < clipRect[1] || (boxy + boxh) > (clipRect[1] + clipRect[3])) {
             normal[1] *= -1;
         }
-    
+
         //update positions
         x = cur[0] + normal[0] * offsetFromViz;
         y = cur[1] + normal[1] * offsetFromViz;
-        
+
         //update box position and dimensions
         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) {
             //set the line from the middle of the pie to the box.
             me.onAnimate(callout.lines, {
@@ -52388,8 +54854,7 @@ Ext.define('Ext.chart.theme.Base', {
  *
  * An object literal of this form could also be used as the {@link #data} config option.
  *
- * **Note:** Although not listed here, this class accepts all of the configuration options of
- * **{@link Ext.data.reader.Array ArrayReader}**.
+ * **Note:** This class accepts all of the configuration options of {@link Ext.data.reader.Array ArrayReader}.
  */
 Ext.define('Ext.data.ArrayStore', {
     extend: 'Ext.data.Store',
@@ -52433,75 +54898,68 @@ Ext.define('Ext.data.ArrayStore', {
 /**
  * @author Ed Spencer
  * @class Ext.data.Batch
- * 
+ *
  * <p>Provides a mechanism to run one or more {@link Ext.data.Operation operations} in a given order. Fires the 'operationcomplete' event
  * after the completion of each Operation, and the 'complete' event when all Operations have been successfully executed. Fires an 'exception'
  * event if any of the Operations encounter an exception.</p>
- * 
+ *
  * <p>Usually these are only used internally by {@link Ext.data.proxy.Proxy} classes</p>
- * 
+ *
  */
 Ext.define('Ext.data.Batch', {
     mixins: {
         observable: 'Ext.util.Observable'
     },
-    
+
     /**
-     * True to immediately start processing the batch as soon as it is constructed (defaults to false)
-     * @property autoStart
-     * @type Boolean
+     * @property {Boolean} autoStart
+     * True to immediately start processing the batch as soon as it is constructed.
      */
     autoStart: false,
-    
+
     /**
+     * @property {Number} current
      * The index of the current operation being executed
-     * @property current
-     * @type Number
      */
     current: -1,
-    
+
     /**
+     * @property {Number} total
      * The total number of operations in this batch. Read only
-     * @property total
-     * @type Number
      */
     total: 0,
-    
+
     /**
+     * @property {Boolean} isRunning
      * True if the batch is currently running
-     * @property isRunning
-     * @type Boolean
      */
     isRunning: false,
-    
+
     /**
+     * @property {Boolean} isComplete
      * True if this batch has been executed completely
-     * @property isComplete
-     * @type Boolean
      */
     isComplete: false,
-    
+
     /**
+     * @property {Boolean} hasException
      * True if this batch has encountered an exception. This is cleared at the start of each operation
-     * @property hasException
-     * @type Boolean
      */
     hasException: false,
-    
+
     /**
-     * True to automatically pause the execution of the batch if any operation encounters an exception (defaults to true)
-     * @property pauseOnException
-     * @type Boolean
+     * @property {Boolean} pauseOnException
+     * True to automatically pause the execution of the batch if any operation encounters an exception
      */
     pauseOnException: true,
-    
+
     /**
      * Creates new Batch object.
-     * @param {Object} config (optional) Config object
+     * @param {Object} [config] Config object
      */
-    constructor: function(config) {   
+    constructor: function(config) {
         var me = this;
-                     
+
         me.addEvents(
           /**
            * @event complete
@@ -52510,7 +54968,7 @@ Ext.define('Ext.data.Batch', {
            * @param {Object} operation The last operation that was executed
            */
           'complete',
-          
+
           /**
            * @event exception
            * Fired when a operation encountered an exception
@@ -52518,7 +54976,7 @@ Ext.define('Ext.data.Batch', {
            * @param {Object} operation The operation that encountered the exception
            */
           'exception',
-          
+
           /**
            * @event operationcomplete
            * Fired when each operation of the batch completes
@@ -52527,29 +54985,28 @@ Ext.define('Ext.data.Batch', {
            */
           'operationcomplete'
         );
-        
+
         me.mixins.observable.constructor.call(me, config);
-        
+
         /**
          * Ordered array of operations that will be executed by this batch
-         * @property operations
-         * @type Array
+         * @property {Ext.data.Operation[]} operations
          */
         me.operations = [];
     },
-    
+
     /**
      * Adds a new operation to this batch
      * @param {Object} operation The {@link Ext.data.Operation Operation} object
      */
     add: function(operation) {
         this.total++;
-        
+
         operation.setBatch(this);
-        
+
         this.operations.push(operation);
     },
-    
+
     /**
      * Kicks off the execution of the batch, continuing from the next operation if the previous
      * operation encountered an exception, or if execution was paused
@@ -52557,10 +55014,10 @@ Ext.define('Ext.data.Batch', {
     start: function() {
         this.hasException = false;
         this.isRunning = true;
-        
+
         this.runNextOperation();
     },
-    
+
     /**
      * @private
      * Runs the next operation, relative to this.current.
@@ -52568,14 +55025,14 @@ Ext.define('Ext.data.Batch', {
     runNextOperation: function() {
         this.runOperation(this.current + 1);
     },
-    
+
     /**
      * Pauses execution of the batch, but does not cancel the current operation
      */
     pause: function() {
         this.isRunning = false;
     },
-    
+
     /**
      * Executes a operation by its numeric index
      * @param {Number} index The operation index to run
@@ -52585,17 +55042,17 @@ Ext.define('Ext.data.Batch', {
             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.fireEvent('exception', me, operation);
@@ -52610,9 +55067,9 @@ Ext.define('Ext.data.Batch', {
                     me.runNextOperation();
                 }
             };
-            
+
             operation.setStarted();
-            
+
             me.proxy[operation.action](operation, onProxyReturn, me);
         }
     }
@@ -52622,117 +55079,110 @@ Ext.define('Ext.data.Batch', {
  * @class Ext.data.BelongsToAssociation
  * @extends Ext.data.Association
  *
- * <p>Represents a many to one association with another model. The owner model is expected to have
- * a foreign key which references the primary key of the associated model:</p>
+ * Represents a many to one association with another model. The owner model is expected to have
+ * a foreign key which references the primary key of the associated model:
  *
-<pre><code>
-Ext.define('Category', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'id',   type: 'int'},
-        {name: 'name', type: 'string'}
-    ]
-});
-
-Ext.define('Product', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'id',          type: 'int'},
-        {name: 'category_id', type: 'int'},
-        {name: 'name',        type: 'string'}
-    ],
-    // we can use the belongsTo shortcut on the model to create a belongsTo association
-    belongsTo: {type: 'belongsTo', model: 'Category'}
-});
-</code></pre>
- * <p>In the example above we have created models for Products and Categories, and linked them together
+ *     Ext.define('Category', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             { name: 'id',   type: 'int' },
+ *             { name: 'name', type: 'string' }
+ *         ]
+ *     });
+ *
+ *     Ext.define('Product', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             { name: 'id',          type: 'int' },
+ *             { name: 'category_id', type: 'int' },
+ *             { name: 'name',        type: 'string' }
+ *         ],
+ *         // we can use the belongsTo shortcut on the model to create a belongsTo association
+ *         associations: [
+ *             { type: 'belongsTo', model: 'Category' }
+ *         ]
+ *     });
+ *
+ * In the example above we have created models for Products and Categories, and linked them together
  * by saying that each Product belongs to a Category. This automatically links each Product to a Category
- * based on the Product's category_id, and provides new functions on the Product model:</p>
+ * based on the Product's category_id, and provides new functions on the Product model:
  *
- * <p><u>Generated getter function</u></p>
+ * ## Generated getter function
  *
- * <p>The first function that is added to the owner model is a getter function:</p>
+ * The first function that is added to the owner model is a getter function:
  *
-<pre><code>
-var product = new Product({
-    id: 100,
-    category_id: 20,
-    name: 'Sneakers'
-});
-
-product.getCategory(function(category, operation) {
-    //do something with the category object
-    alert(category.get('id')); //alerts 20
-}, this);
-</code></pre>
-*
- * <p>The getCategory function was created on the Product model when we defined the association. This uses the
+ *     var product = new Product({
+ *         id: 100,
+ *         category_id: 20,
+ *         name: 'Sneakers'
+ *     });
+ *
+ *     product.getCategory(function(category, operation) {
+ *         // do something with the category object
+ *         alert(category.get('id')); // alerts 20
+ *     }, this);
+ *
+ * The getCategory function was created on the Product model when we defined the association. This uses the
  * Category's configured {@link Ext.data.proxy.Proxy proxy} to load the Category asynchronously, calling the provided
- * callback when it has loaded.</p>
+ * callback when it has loaded.
  *
- * <p>The new getCategory function will also accept an object containing success, failure and callback properties
+ * The new getCategory function will also accept an object containing success, failure and callback properties
  * - callback will always be called, success will only be called if the associated model was loaded successfully
- * and failure will only be called if the associatied model could not be loaded:</p>
+ * and failure will only be called if the associatied model could not be loaded:
  *
-<pre><code>
-product.getCategory({
-    callback: function(category, operation) {}, //a function that will always be called
-    success : function(category, operation) {}, //a function that will only be called if the load succeeded
-    failure : function(category, operation) {}, //a function that will only be called if the load did not succeed
-    scope   : this //optionally pass in a scope object to execute the callbacks in
-});
-</code></pre>
+ *     product.getCategory({
+ *         callback: function(category, operation) {}, // a function that will always be called
+ *         success : function(category, operation) {}, // a function that will only be called if the load succeeded
+ *         failure : function(category, operation) {}, // a function that will only be called if the load did not succeed
+ *         scope   : this // optionally pass in a scope object to execute the callbacks in
+ *     });
  *
- * <p>In each case above the callbacks are called with two arguments - the associated model instance and the
+ * In each case above the callbacks are called with two arguments - the associated model instance and the
  * {@link Ext.data.Operation operation} object that was executed to load that instance. The Operation object is
- * useful when the instance could not be loaded.</p>
+ * useful when the instance could not be loaded.
  *
- * <p><u>Generated setter function</u></p>
+ * ## Generated setter function
  *
- * <p>The second generated function sets the associated model instance - if only a single argument is passed to
- * the setter then the following two calls are identical:</p>
+ * The second generated function sets the associated model instance - if only a single argument is passed to
+ * the setter then the following two calls are identical:
  *
-<pre><code>
-//this call
-product.setCategory(10);
-
-//is equivalent to this call:
-product.set('category_id', 10);
-</code></pre>
- * <p>If we pass in a second argument, the model will be automatically saved and the second argument passed to
- * the owner model's {@link Ext.data.Model#save save} method:</p>
-<pre><code>
-product.setCategory(10, function(product, operation) {
-    //the product has been saved
-    alert(product.get('category_id')); //now alerts 10
-});
-
-//alternative syntax:
-product.setCategory(10, {
-    callback: function(product, operation), //a function that will always be called
-    success : function(product, operation), //a function that will only be called if the load succeeded
-    failure : function(product, operation), //a function that will only be called if the load did not succeed
-    scope   : this //optionally pass in a scope object to execute the callbacks in
-})
-</code></pre>
-*
- * <p><u>Customisation</u></p>
+ *     // this call...
+ *     product.setCategory(10);
  *
- * <p>Associations reflect on the models they are linking to automatically set up properties such as the
- * {@link #primaryKey} and {@link #foreignKey}. These can alternatively be specified:</p>
+ *     // is equivalent to this call:
+ *     product.set('category_id', 10);
  *
-<pre><code>
-Ext.define('Product', {
-    fields: [...],
-
-    associations: [
-        {type: 'belongsTo', model: 'Category', primaryKey: 'unique_id', foreignKey: 'cat_id'}
-    ]
-});
- </code></pre>
+ * If we pass in a second argument, the model will be automatically saved and the second argument passed to
+ * the owner model's {@link Ext.data.Model#save save} method:
+ *
+ *     product.setCategory(10, function(product, operation) {
+ *         // the product has been saved
+ *         alert(product.get('category_id')); //now alerts 10
+ *     });
  *
- * <p>Here we replaced the default primary key (defaults to 'id') and foreign key (calculated as 'category_id')
- * with our own settings. Usually this will not be needed.</p>
+ *     //alternative syntax:
+ *     product.setCategory(10, {
+ *         callback: function(product, operation), // a function that will always be called
+ *         success : function(product, operation), // a function that will only be called if the load succeeded
+ *         failure : function(product, operation), // a function that will only be called if the load did not succeed
+ *         scope   : this //optionally pass in a scope object to execute the callbacks in
+ *     })
+ *
+ * ## Customisation
+ *
+ * Associations reflect on the models they are linking to automatically set up properties such as the
+ * {@link #primaryKey} and {@link #foreignKey}. These can alternatively be specified:
+ *
+ *     Ext.define('Product', {
+ *         fields: [...],
+ *
+ *         associations: [
+ *             { type: 'belongsTo', model: 'Category', primaryKey: 'unique_id', foreignKey: 'cat_id' }
+ *         ]
+ *     });
+ *
+ * Here we replaced the default primary key (defaults to 'id') and foreign key (calculated as 'category_id')
+ * with our own settings. Usually this will not be needed.
  */
 Ext.define('Ext.data.BelongsToAssociation', {
     extend: 'Ext.data.Association',
@@ -52743,26 +55193,25 @@ Ext.define('Ext.data.BelongsToAssociation', {
      * @cfg {String} foreignKey The name of the foreign key on the owner model that links it to the associated
      * model. Defaults to the lowercased name of the associated model plus "_id", e.g. an association with a
      * model called Product would set up a product_id foreign key.
-     * <pre><code>
-Ext.define('Order', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'date'],
-    hasMany: 'Product'
-});
-
-Ext.define('Product', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'name', 'order_id'], // refers to the id of the order that this product belongs to
-    belongsTo: 'Group'
-});
-var product = new Product({
-    id: 1,
-    name: 'Product 1',
-    order_id: 22
-}, 1);
-product.getOrder(); // Will make a call to the server asking for order_id 22
-
-     * </code></pre>
+     *
+     *     Ext.define('Order', {
+     *         extend: 'Ext.data.Model',
+     *         fields: ['id', 'date'],
+     *         hasMany: 'Product'
+     *     });
+     *
+     *     Ext.define('Product', {
+     *         extend: 'Ext.data.Model',
+     *         fields: ['id', 'name', 'order_id'], // refers to the id of the order that this product belongs to
+     *         belongsTo: 'Group'
+     *     });
+     *     var product = new Product({
+     *         id: 1,
+     *         name: 'Product 1',
+     *         order_id: 22
+     *     }, 1);
+     *     product.getOrder(); // Will make a call to the server asking for order_id 22
+     *
      */
 
     /**
@@ -52774,18 +55223,16 @@ product.getOrder(); // Will make a call to the server asking for order_id 22
      * @cfg {String} setterName The name of the setter function that will be added to the local model's prototype.
      * Defaults to 'set' + the name of the foreign model, e.g. setCategory
      */
-    
+
     /**
      * @cfg {String} type The type configuration can be used when creating associations using a configuration object.
      * Use 'belongsTo' to create a HasManyAssocation
-     * <pre><code>
-associations: [{
-    type: 'belongsTo',
-    model: 'User'
-}]
-     * </code></pre>
+     *
+     *     associations: [{
+     *         type: 'belongsTo',
+     *         model: 'User'
+     *     }]
      */
-
     constructor: function(config) {
         this.callParent(arguments);
 
@@ -52877,7 +55324,7 @@ associations: [{
                 instance = model[instanceName];
                 args = [instance];
                 scope = scope || model;
-                
+
                 //TODO: We're duplicating the callback invokation code that the instance.load() call above
                 //makes here - ought to be able to normalize this - perhaps by caching at the Model.load layer
                 //instead of the association layer.
@@ -52919,73 +55366,62 @@ Ext.define('Ext.data.BufferStore', {
     }
 });
 /**
- * @class Ext.direct.Manager
- * <p><b><u>Overview</u></b></p>
+ * Ext.Direct aims to streamline communication between the client and server by providing a single interface that
+ * reduces the amount of common code typically required to validate data and handle returned data packets (reading data,
+ * error conditions, etc).
  *
- * <p>Ext.Direct aims to streamline communication between the client and server
- * by providing a single interface that reduces the amount of common code
- * typically required to validate data and handle returned data packets
- * (reading data, error conditions, etc).</p>
+ * The Ext.direct namespace includes several classes for a closer integration with the server-side. The Ext.data
+ * namespace also includes classes for working with Ext.data.Stores which are backed by data from an Ext.Direct method.
  *
- * <p>The Ext.direct namespace includes several classes for a closer integration
- * with the server-side. The Ext.data namespace also includes classes for working
- * with Ext.data.Stores which are backed by data from an Ext.Direct method.</p>
+ * # Specification
  *
- * <p><b><u>Specification</u></b></p>
+ * For additional information consult the [Ext.Direct Specification][1].
  *
- * <p>For additional information consult the
- * <a href="http://sencha.com/products/extjs/extdirect">Ext.Direct Specification</a>.</p>
+ * # Providers
  *
- * <p><b><u>Providers</u></b></p>
+ * Ext.Direct uses a provider architecture, where one or more providers are used to transport data to and from the
+ * server. There are several providers that exist in the core at the moment:
  *
- * <p>Ext.Direct uses a provider architecture, where one or more providers are
- * used to transport data to and from the server. There are several providers
- * that exist in the core at the moment:</p><div class="mdetail-params"><ul>
+ * - {@link Ext.direct.JsonProvider JsonProvider} for simple JSON operations
+ * - {@link Ext.direct.PollingProvider PollingProvider} for repeated requests
+ * - {@link Ext.direct.RemotingProvider RemotingProvider} exposes server side on the client.
  *
- * <li>{@link Ext.direct.JsonProvider JsonProvider} for simple JSON operations</li>
- * <li>{@link Ext.direct.PollingProvider PollingProvider} for repeated requests</li>
- * <li>{@link Ext.direct.RemotingProvider RemotingProvider} exposes server side
- * on the client.</li>
- * </ul></div>
+ * A provider does not need to be invoked directly, providers are added via {@link Ext.direct.Manager}.{@link #addProvider}.
  *
- * <p>A provider does not need to be invoked directly, providers are added via
- * {@link Ext.direct.Manager}.{@link Ext.direct.Manager#addProvider addProvider}.</p>
+ * # Router
  *
- * <p><b><u>Router</u></b></p>
+ * Ext.Direct utilizes a "router" on the server to direct requests from the client to the appropriate server-side
+ * method. Because the Ext.Direct API is completely platform-agnostic, you could completely swap out a Java based server
+ * solution and replace it with one that uses C# without changing the client side JavaScript at all.
  *
- * <p>Ext.Direct utilizes a "router" on the server to direct requests from the client
- * to the appropriate server-side method. Because the Ext.Direct API is completely
- * platform-agnostic, you could completely swap out a Java based server solution
- * and replace it with one that uses C# without changing the client side JavaScript
- * at all.</p>
+ * # Server side events
  *
- * <p><b><u>Server side events</u></b></p>
+ * Custom events from the server may be handled by the client by adding listeners, for example:
+ *
+ *     {"type":"event","name":"message","data":"Successfully polled at: 11:19:30 am"}
+ *
+ *     // add a handler for a 'message' event sent by the server
+ *     Ext.direct.Manager.on('message', function(e){
+ *         out.append(String.format('<p><i>{0}</i></p>', e.data));
+ *         out.el.scrollTo('t', 100000, true);
+ *     });
+ *
+ *    [1]: http://sencha.com/products/extjs/extdirect
  *
- * <p>Custom events from the server may be handled by the client by adding
- * listeners, for example:</p>
- * <pre><code>
-{"type":"event","name":"message","data":"Successfully polled at: 11:19:30 am"}
-
-// add a handler for a 'message' event sent by the server
-Ext.direct.Manager.on('message', function(e){
-    out.append(String.format('&lt;p>&lt;i>{0}&lt;/i>&lt;/p>', e.data));
-            out.el.scrollTo('t', 100000, true);
-});
- * </code></pre>
  * @singleton
+ * @alternateClassName Ext.Direct
  */
-
 Ext.define('Ext.direct.Manager', {
-    
+
     /* Begin Definitions */
     singleton: true,
-   
+
     mixins: {
         observable: 'Ext.util.Observable'
     },
-    
+
     requires: ['Ext.util.MixedCollection'],
-    
+
     statics: {
         exceptions: {
             TRANSPORT: 'xhr',
@@ -52994,74 +55430,75 @@ Ext.define('Ext.direct.Manager', {
             SERVER: 'exception'
         }
     },
-    
+
     /* End Definitions */
-   
+
     constructor: function(){
         var me = this;
-       
+
         me.addEvents(
             /**
              * @event event
              * Fires after an event.
-             * @param {event} e The Ext.direct.Event type that occurred.
+             * @param {Ext.direct.Event} e The Ext.direct.Event type that occurred.
              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
              */
             'event',
             /**
              * @event exception
              * Fires after an event exception.
-             * @param {event} e The Ext.direct.Event type that occurred.
+             * @param {Ext.direct.Event} e The event type that occurred.
              */
             'exception'
         );
         me.transactions = Ext.create('Ext.util.MixedCollection');
         me.providers = Ext.create('Ext.util.MixedCollection');
-        
+
         me.mixins.observable.constructor.call(me);
     },
-    
-    /**
-     * Adds an Ext.Direct Provider and creates the proxy or stub methods to execute server-side methods.
-     * If the provider is not already connected, it will auto-connect.
-     * <pre><code>
-var pollProv = new Ext.direct.PollingProvider({
-    url: 'php/poll2.php'
-});
 
-Ext.direct.Manager.addProvider({
-    "type":"remoting",       // create a {@link Ext.direct.RemotingProvider}
-    "url":"php\/router.php", // url to connect to the Ext.Direct server-side router.
-    "actions":{              // each property within the actions object represents a Class
-        "TestAction":[       // array of methods within each server side Class
-        {
-            "name":"doEcho", // name of method
-            "len":1
-        },{
-            "name":"multiply",
-            "len":1
-        },{
-            "name":"doForm",
-            "formHandler":true, // handle form on server with Ext.Direct.Transaction
-            "len":1
-        }]
-    },
-    "namespace":"myApplication",// namespace to create the Remoting Provider in
-},{
-    type: 'polling', // create a {@link Ext.direct.PollingProvider}
-    url:  'php/poll.php'
-}, pollProv); // reference to previously created instance
-     * </code></pre>
-     * @param {Object/Array} provider Accepts either an Array of Provider descriptions (an instance
-     * or config object for a Provider) or any number of Provider descriptions as arguments.  Each
-     * Provider description instructs Ext.Direct how to create client-side stub methods.
+    /**
+     * Adds an Ext.Direct Provider and creates the proxy or stub methods to execute server-side methods. If the provider
+     * is not already connected, it will auto-connect.
+     *
+     *     var pollProv = new Ext.direct.PollingProvider({
+     *         url: 'php/poll2.php'
+     *     });
+     *
+     *     Ext.direct.Manager.addProvider({
+     *         "type":"remoting",       // create a {@link Ext.direct.RemotingProvider}
+     *         "url":"php\/router.php", // url to connect to the Ext.Direct server-side router.
+     *         "actions":{              // each property within the actions object represents a Class
+     *             "TestAction":[       // array of methods within each server side Class
+     *             {
+     *                 "name":"doEcho", // name of method
+     *                 "len":1
+     *             },{
+     *                 "name":"multiply",
+     *                 "len":1
+     *             },{
+     *                 "name":"doForm",
+     *                 "formHandler":true, // handle form on server with Ext.Direct.Transaction
+     *                 "len":1
+     *             }]
+     *         },
+     *         "namespace":"myApplication",// namespace to create the Remoting Provider in
+     *     },{
+     *         type: 'polling', // create a {@link Ext.direct.PollingProvider}
+     *         url:  'php/poll.php'
+     *     }, pollProv); // reference to previously created instance
+     *
+     * @param {Ext.direct.Provider/Object...} provider
+     * Accepts any number of Provider descriptions (an instance or config object for
+     * a Provider). Each Provider description instructs Ext.Directhow to create
+     * client-side stub methods.
      */
     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]);
@@ -53083,17 +55520,16 @@ Ext.direct.Manager.addProvider({
 
         return provider;
     },
-    
+
     /**
-     * Retrieve a {@link Ext.direct.Provider provider} by the
-     * <b><tt>{@link Ext.direct.Provider#id id}</tt></b> specified when the provider is
-     * {@link #addProvider added}.
-     * @param {String/Ext.data.Provider} id The id of the provider, or the provider instance.
+     * Retrieves a {@link Ext.direct.Provider provider} by the **{@link Ext.direct.Provider#id id}** specified when the
+     * provider is {@link #addProvider added}.
+     * @param {String/Ext.direct.Provider} id The id of the provider, or the provider instance.
      */
     getProvider : function(id){
         return id.isProvider ? id : this.providers.get(id);
     },
-    
+
     /**
      * Removes the provider.
      * @param {String/Ext.direct.Provider} provider The provider instance or the id of the provider.
@@ -53101,9 +55537,10 @@ Ext.direct.Manager.addProvider({
      */
     removeProvider : function(provider){
         var me = this,
-            providers = me.providers,
-            provider = provider.isProvider ? provider : providers.get(provider);
-            
+            providers = me.providers;
+
+        provider = provider.isProvider ? provider : providers.get(provider);
+
         if (provider) {
             provider.un('data', me.onProviderData, me);
             providers.remove(provider);
@@ -53111,9 +55548,9 @@ Ext.direct.Manager.addProvider({
         }
         return null;
     },
-    
+
     /**
-     * Add a transaction to the manager.
+     * Adds a transaction to the manager.
      * @private
      * @param {Ext.direct.Transaction} transaction The transaction to add
      * @return {Ext.direct.Transaction} transaction
@@ -53124,7 +55561,7 @@ Ext.direct.Manager.addProvider({
     },
 
     /**
-     * Remove a transaction from the manager.
+     * Removes a transaction from the manager.
      * @private
      * @param {String/Ext.direct.Transaction} transaction The transaction/id of transaction to remove
      * @return {Ext.direct.Transaction} transaction
@@ -53144,12 +55581,12 @@ Ext.direct.Manager.addProvider({
     getTransaction: function(transaction){
         return transaction.isTransaction ? 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]);
@@ -53158,7 +55595,7 @@ Ext.direct.Manager.addProvider({
         }
         if (event.name && event.name != 'event' && event.name != 'exception') {
             me.fireEvent(event.name, event);
-        } else if (event.type == 'exception') {
+        } else if (event.status === false) {
             me.fireEvent('exception', event);
         }
         me.fireEvent('event', event, provider);
@@ -53169,27 +55606,26 @@ Ext.direct.Manager.addProvider({
 });
 
 /**
- * @class Ext.data.proxy.Direct
- * @extends Ext.data.proxy.Server
- * 
- * This class is used to send requests to the server using {@link Ext.direct}. When a request is made,
- * the transport mechanism is handed off to the appropriate {@link Ext.direct.RemotingProvider Provider}
- * to complete the call.
- * 
- * ## Specifying the function
+ * This class is used to send requests to the server using {@link Ext.direct.Manager Ext.Direct}. When a
+ * request is made, the transport mechanism is handed off to the appropriate
+ * {@link Ext.direct.RemotingProvider Provider} to complete the call.
+ *
+ * # Specifying the function
+ *
  * This proxy expects a Direct remoting method to be passed in order to be able to complete requests.
  * This can be done by specifying the {@link #directFn} configuration. This will use the same direct
  * method for all requests. Alternatively, you can provide an {@link #api} configuration. This
  * allows you to specify a different remoting method for each CRUD action.
- * 
- * ## Parameters
+ *
+ * # Parameters
+ *
  * This proxy provides options to help configure which parameters will be sent to the server.
  * By specifying the {@link #paramsAsHash} option, it will send an object literal containing each
  * of the passed parameters. The {@link #paramOrder} option can be used to specify the order in which
  * the remoting method parameters are passed.
- * 
- * ## Example Usage
- * 
+ *
+ * # Example Usage
+ *
  *     Ext.define('User', {
  *         extend: 'Ext.data.Model',
  *         fields: ['firstName', 'lastName'],
@@ -53203,34 +55639,34 @@ Ext.direct.Manager.addProvider({
  */
 Ext.define('Ext.data.proxy.Direct', {
     /* Begin Definitions */
-    
+
     extend: 'Ext.data.proxy.Server',
     alternateClassName: 'Ext.data.DirectProxy',
-    
+
     alias: 'proxy.direct',
-    
+
     requires: ['Ext.direct.Manager'],
-    
+
     /* End Definitions */
-   
-   /**
-     * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. A list of params to be executed
-     * server side.  Specify the params in the order in which they must be executed on the server-side
-     * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
-     * comma, or pipe. For example,
-     * any of the following would be acceptable:<pre><code>
-paramOrder: ['param1','param2','param3']
-paramOrder: 'param1 param2 param3'
-paramOrder: 'param1,param2,param3'
-paramOrder: 'param1|param2|param'
-     </code></pre>
+
+    /**
+     * @cfg {String/String[]} paramOrder
+     * Defaults to undefined. A list of params to be executed server side.  Specify the params in the order in
+     * which they must be executed on the server-side as either (1) an Array of String values, or (2) a String
+     * of params delimited by either whitespace, comma, or pipe. For example, any of the following would be
+     * acceptable:
+     *
+     *     paramOrder: ['param1','param2','param3']
+     *     paramOrder: 'param1 param2 param3'
+     *     paramOrder: 'param1,param2,param3'
+     *     paramOrder: 'param1|param2|param'
      */
     paramOrder: undefined,
 
     /**
      * @cfg {Boolean} paramsAsHash
-     * Send parameters as a collection of named arguments (defaults to <tt>true</tt>). Providing a
-     * <tt>{@link #paramOrder}</tt> nullifies this configuration.
+     * Send parameters as a collection of named arguments.
+     * Providing a {@link #paramOrder} nullifies this configuration.
      */
     paramsAsHash: true,
 
@@ -53240,30 +55676,32 @@ paramOrder: 'param1|param2|param'
      * for Store's which will not implement a full CRUD api.
      */
     directFn : undefined,
-    
+
     /**
-     * @cfg {Object} api The same as {@link Ext.data.proxy.Server#api}, however instead of providing urls, you should provide a direct
+     * @cfg {Object} api
+     * The same as {@link Ext.data.proxy.Server#api}, however instead of providing urls, you should provide a direct
      * function call.
      */
-    
+
     /**
-     * @cfg {Object} extraParams Extra parameters that will be included on every read request. Individual requests with params
+     * @cfg {Object} extraParams
+     * Extra parameters that will be included on every read request. Individual requests with params
      * of the same name will override these params when they are in conflict.
      */
-    
+
     // private
     paramOrderRe: /[\s,|]/,
-    
+
     constructor: function(config){
         var me = this;
-        
+
         Ext.apply(me, config);
         if (Ext.isString(me.paramOrder)) {
             me.paramOrder = me.paramOrder.split(me.paramOrderRe);
         }
         me.callParent(arguments);
     },
-    
+
     doRequest: function(operation, callback, scope) {
         var me = this,
             writer = me.getWriter(),
@@ -53275,21 +55713,21 @@ paramOrder: 'param1|param2|param'
             method,
             i = 0,
             len;
-            
+
         //<debug>
         if (!fn) {
             Ext.Error.raise('No direct function specified for this proxy');
         }
         //</debug>
-            
+
         if (operation.allowWrite()) {
             request = writer.write(request);
         }
-        
+
         if (operation.action == 'read') {
             // We need to pass params
             method = fn.directCfg.method;
-            
+
             if (method.ordered) {
                 if (method.len > 0) {
                     if (paramOrder) {
@@ -53306,7 +55744,7 @@ paramOrder: 'param1|param2|param'
         } else {
             args.push(request.jsonData);
         }
-        
+
         Ext.apply(request, {
             args: args,
             directFn: fn
@@ -53314,7 +55752,7 @@ paramOrder: 'param1|param2|param'
         args.push(me.createRequestCallback(request, operation, callback, scope), me);
         fn.apply(window, args);
     },
-    
+
     /*
      * Inherit docs. We don't apply any encoding here because
      * all of the direct requests go out as jsonData
@@ -53322,25 +55760,25 @@ paramOrder: 'param1|param2|param'
     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);
         };
     },
-    
+
     // inherit docs
     extractResponseData: function(response){
         return Ext.isDefined(response.result) ? response.result : response.data;
     },
-    
+
     // inherit docs
     setException: function(operation, response) {
         operation.setException(response.message);
     },
-    
+
     // inherit docs
     buildUrl: function(){
         return '';
@@ -53348,36 +55786,28 @@ paramOrder: 'param1|param2|param'
 });
 
 /**
- * @class Ext.data.DirectStore
- * @extends Ext.data.Store
- * <p>Small helper class to create an {@link Ext.data.Store} configured with an
- * {@link Ext.data.proxy.Direct} and {@link Ext.data.reader.Json} to make interacting
- * with an {@link Ext.Direct} Server-side {@link Ext.direct.Provider Provider} easier.
- * To create a different proxy/reader combination create a basic {@link Ext.data.Store}
- * configured as needed.</p>
+ * Small helper class to create an {@link Ext.data.Store} configured with an {@link Ext.data.proxy.Direct}
+ * and {@link Ext.data.reader.Json} to make interacting with an {@link Ext.direct.Manager} server-side
+ * {@link Ext.direct.Provider Provider} easier. To create a different proxy/reader combination create a basic
+ * {@link Ext.data.Store} configured as needed.
  *
- * <p><b>*Note:</b> Although they are not listed, this class inherits all of the config options of:</p>
- * <div><ul class="mdetail-params">
- * <li><b>{@link Ext.data.Store Store}</b></li>
- * <div class="sub-desc"><ul class="mdetail-params">
+ * **Note:** Although they are not listed, this class inherits all of the config options of:
  *
- * </ul></div>
- * <li><b>{@link Ext.data.reader.Json JsonReader}</b></li>
- * <div class="sub-desc"><ul class="mdetail-params">
- * <li><tt><b>{@link Ext.data.reader.Json#root root}</b></tt></li>
- * <li><tt><b>{@link Ext.data.reader.Json#idProperty idProperty}</b></tt></li>
- * <li><tt><b>{@link Ext.data.reader.Json#totalProperty totalProperty}</b></tt></li>
- * </ul></div>
+ * - **{@link Ext.data.Store Store}**
+ *
+ * - **{@link Ext.data.reader.Json JsonReader}**
+ *
+ *   - **{@link Ext.data.reader.Json#root root}**
+ *   - **{@link Ext.data.reader.Json#idProperty idProperty}**
+ *   - **{@link Ext.data.reader.Json#totalProperty totalProperty}**
+ *
+ * - **{@link Ext.data.proxy.Direct DirectProxy}**
+ *
+ *   - **{@link Ext.data.proxy.Direct#directFn directFn}**
+ *   - **{@link Ext.data.proxy.Direct#paramOrder paramOrder}**
+ *   - **{@link Ext.data.proxy.Direct#paramsAsHash paramsAsHash}**
  *
- * <li><b>{@link Ext.data.proxy.Direct DirectProxy}</b></li>
- * <div class="sub-desc"><ul class="mdetail-params">
- * <li><tt><b>{@link Ext.data.proxy.Direct#directFn directFn}</b></tt></li>
- * <li><tt><b>{@link Ext.data.proxy.Direct#paramOrder paramOrder}</b></tt></li>
- * <li><tt><b>{@link Ext.data.proxy.Direct#paramsAsHash paramsAsHash}</b></tt></li>
- * </ul></div>
- * </ul></div>
  */
-
 Ext.define('Ext.data.DirectStore', {
     /* Begin Definitions */
     
@@ -53389,9 +55819,6 @@ Ext.define('Ext.data.DirectStore', {
    
     /* End Definitions */
 
-    /**
-     * @param {Object} config (optional) Config object.
-     */
     constructor : function(config){
         config = Ext.apply({}, config);
         if (!config.proxy) {
@@ -53410,51 +55837,40 @@ Ext.define('Ext.data.DirectStore', {
 });
 
 /**
- * @class Ext.util.Inflector
- * @extends Object
- * <p>General purpose inflector class that {@link #pluralize pluralizes}, {@link #singularize singularizes} and 
- * {@link #ordinalize ordinalizes} words. Sample usage:</p>
- * 
-<pre><code>
-//turning singular words into plurals
-Ext.util.Inflector.pluralize('word'); //'words'
-Ext.util.Inflector.pluralize('person'); //'people'
-Ext.util.Inflector.pluralize('sheep'); //'sheep'
-
-//turning plurals into singulars
-Ext.util.Inflector.singularize('words'); //'word'
-Ext.util.Inflector.singularize('people'); //'person'
-Ext.util.Inflector.singularize('sheep'); //'sheep'
-
-//ordinalizing numbers
-Ext.util.Inflector.ordinalize(11); //"11th"
-Ext.util.Inflector.ordinalize(21); //"21th"
-Ext.util.Inflector.ordinalize(1043); //"1043rd"
-</code></pre>
- * 
- * <p><u>Customization</u></p>
- * 
- * <p>The Inflector comes with a default set of US English pluralization rules. These can be augmented with additional
+ * General purpose inflector class that {@link #pluralize pluralizes}, {@link #singularize singularizes} and
+ * {@link #ordinalize ordinalizes} words. Sample usage:
+ *
+ *     //turning singular words into plurals
+ *     Ext.util.Inflector.pluralize('word'); //'words'
+ *     Ext.util.Inflector.pluralize('person'); //'people'
+ *     Ext.util.Inflector.pluralize('sheep'); //'sheep'
+ *
+ *     //turning plurals into singulars
+ *     Ext.util.Inflector.singularize('words'); //'word'
+ *     Ext.util.Inflector.singularize('people'); //'person'
+ *     Ext.util.Inflector.singularize('sheep'); //'sheep'
+ *
+ *     //ordinalizing numbers
+ *     Ext.util.Inflector.ordinalize(11); //"11th"
+ *     Ext.util.Inflector.ordinalize(21); //"21th"
+ *     Ext.util.Inflector.ordinalize(1043); //"1043rd"
+ *
+ * # Customization
+ *
+ * The Inflector comes with a default set of US English pluralization rules. These can be augmented with additional
  * rules if the default rules do not meet your application's requirements, or swapped out entirely for other languages.
- * Here is how we might add a rule that pluralizes "ox" to "oxen":</p>
- * 
-<pre><code>
-Ext.util.Inflector.plural(/^(ox)$/i, "$1en");
-</code></pre>
- * 
- * <p>Each rule consists of two items - a regular expression that matches one or more rules, and a replacement string.
- * In this case, the regular expression will only match the string "ox", and will replace that match with "oxen". 
- * Here's how we could add the inverse rule:</p>
- * 
-<pre><code>
-Ext.util.Inflector.singular(/^(ox)en$/i, "$1");
-</code></pre>
- * 
- * <p>Note that the ox/oxen rules are present by default.</p>
- * 
- * @singleton
+ * Here is how we might add a rule that pluralizes "ox" to "oxen":
+ *
+ *     Ext.util.Inflector.plural(/^(ox)$/i, "$1en");
+ *
+ * Each rule consists of two items - a regular expression that matches one or more rules, and a replacement string. In
+ * this case, the regular expression will only match the string "ox", and will replace that match with "oxen". Here's
+ * how we could add the inverse rule:
+ *
+ *     Ext.util.Inflector.singular(/^(ox)en$/i, "$1");
+ *
+ * Note that the ox/oxen rules are present by default.
  */
-
 Ext.define('Ext.util.Inflector', {
 
     /* Begin Definitions */
@@ -53468,8 +55884,7 @@ Ext.define('Ext.util.Inflector', {
      * The registered plural tuples. Each item in the array should contain two items - the first must be a regular
      * expression that matchers the singular form of a word, the second must be a String that replaces the matched
      * part of the regular expression. This is managed by the {@link #plural} method.
-     * @property plurals
-     * @type Array
+     * @property {Array} plurals
      */
     plurals: [
         [(/(quiz)$/i),                "$1zes"  ],
@@ -53493,14 +55908,13 @@ Ext.define('Ext.util.Inflector', {
         [(/s$/i),                     "s"      ],
         [(/$/),                       "s"      ]
     ],
-    
+
     /**
      * @private
-     * The set of registered singular matchers. Each item in the array should contain two items - the first must be a 
-     * regular expression that matches the plural form of a word, the second must be a String that replaces the 
+     * The set of registered singular matchers. Each item in the array should contain two items - the first must be a
+     * regular expression that matches the plural form of a word, the second must be a String that replaces the
      * matched part of the regular expression. This is managed by the {@link #singular} method.
-     * @property singulars
-     * @type Array
+     * @property {Array} singulars
      */
     singulars: [
       [(/(quiz)zes$/i),                                                    "$1"     ],
@@ -53529,12 +55943,11 @@ Ext.define('Ext.util.Inflector', {
       [(/people$/i),                                                       "person" ],
       [(/s$/i),                                                            ""       ]
     ],
-    
+
     /**
      * @private
      * The registered uncountable words
-     * @property uncountable
-     * @type Array
+     * @property {String[]} uncountable
      */
      uncountable: [
         "sheep",
@@ -53551,7 +55964,7 @@ Ext.define('Ext.util.Inflector', {
         "deer",
         "means"
     ],
-    
+
     /**
      * Adds a new singularization rule to the Inflector. See the intro docs for more information
      * @param {RegExp} matcher The matcher regex
@@ -53560,7 +55973,7 @@ Ext.define('Ext.util.Inflector', {
     singular: function(matcher, replacer) {
         this.singulars.unshift([matcher, replacer]);
     },
-    
+
     /**
      * Adds a new pluralization rule to the Inflector. See the intro docs for more information
      * @param {RegExp} matcher The matcher regex
@@ -53569,21 +55982,21 @@ Ext.define('Ext.util.Inflector', {
     plural: function(matcher, replacer) {
         this.plurals.unshift([matcher, replacer]);
     },
-    
+
     /**
      * Removes all registered singularization rules
      */
     clearSingulars: function() {
         this.singulars = [];
     },
-    
+
     /**
      * Removes all registered pluralization rules
      */
     clearPlurals: function() {
         this.plurals = [];
     },
-    
+
     /**
      * Returns true if the given word is transnumeral (the word is its own singular and plural form - e.g. sheep, fish)
      * @param {String} word The word to test
@@ -53606,19 +56019,19 @@ Ext.define('Ext.util.Inflector', {
         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;
     },
-    
+
     /**
      * Returns the singularized form of a word (e.g. Ext.util.Inflector.singularize('words') returns 'word')
      * @param {String} word The word to singularize
@@ -53632,21 +56045,21 @@ Ext.define('Ext.util.Inflector', {
         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;
     },
-    
+
     /**
-     * Returns the correct {@link Ext.data.Model Model} name for a given string. Mostly used internally by the data 
+     * Returns the correct {@link Ext.data.Model Model} name for a given string. Mostly used internally by the data
      * package
      * @param {String} word The word to classify
      * @return {String} The classified version of the word
@@ -53654,9 +56067,9 @@ Ext.define('Ext.util.Inflector', {
     classify: function(word) {
         return Ext.String.capitalize(this.singularize(word));
     },
-    
+
     /**
-     * Ordinalizes a given number by adding a prefix such as 'st', 'nd', 'rd' or 'th' based on the last digit of the 
+     * Ordinalizes a given number by adding a prefix such as 'st', 'nd', 'rd' or 'th' based on the last digit of the
      * number. 21 -> 21st, 22 -> 22nd, 23 -> 23rd, 24 -> 24th etc
      * @param {Number} number The number to ordinalize
      * @return {String} The ordinalized number
@@ -53665,7 +56078,7 @@ Ext.define('Ext.util.Inflector', {
         var parsed = parseInt(number, 10),
             mod10  = parsed % 10,
             mod100 = parsed % 100;
-        
+
         //11 through 13 are a special case
         if (11 <= mod100 && mod100 <= 13) {
             return number + "th";
@@ -53714,7 +56127,7 @@ Ext.define('Ext.util.Inflector', {
             vita: 'vitae'
         },
         singular;
-    
+
     for (singular in irregulars) {
         this.plural(singular, irregulars[singular]);
         this.singular(irregulars[singular], singular);
@@ -53757,7 +56170,7 @@ Ext.define('User', {
  * 
 <pre><code>
 //first, we load up a User with id of 1
-var user = Ext.ModelManager.create({id: 1, name: 'Ed'}, 'User');
+var user = Ext.create('User', {id: 1, name: 'Ed'});
 
 //the user.products function was created automatically by the association and returns a {@link Ext.data.Store Store}
 //the created store is automatically scoped to the set of Products for the User with id of 1
@@ -53813,7 +56226,7 @@ var store = new Search({query: 'Sencha Touch'}).tweets();
  * equivalent to this:</p>
  * 
 <pre><code>
-var store = new Ext.data.Store({
+var store = Ext.create('Ext.data.Store', {
     model: 'Tweet',
     filters: [
         {
@@ -54009,22 +56422,21 @@ associations: [{
  * @class Ext.data.JsonP
  * @singleton
  * This class is used to create JSONP requests. JSONP is a mechanism that allows for making
- * requests for data cross domain. More information is available here:
- * http://en.wikipedia.org/wiki/JSONP
+ * requests for data cross domain. More information is available <a href="http://en.wikipedia.org/wiki/JSONP">here</a>.
  */
 Ext.define('Ext.data.JsonP', {
-    
+
     /* Begin Definitions */
-    
+
     singleton: true,
-    
+
     statics: {
         requestCount: 0,
         requests: {}
     },
-    
+
     /* End Definitions */
-    
+
     /**
      * @property timeout
      * @type Number
@@ -54032,21 +56444,21 @@ Ext.define('Ext.data.JsonP', {
      * failure callback will be fired. The timeout is in ms. Defaults to <tt>30000</tt>.
      */
     timeout: 30000,
-    
+
     /**
      * @property disableCaching
      * @type Boolean
      * True to add a unique cache-buster param to requests. Defaults to <tt>true</tt>.
      */
     disableCaching: true,
-   
+
     /**
-     * @property disableCachingParam 
+     * @property disableCachingParam
      * @type String
      * Change the parameter which is sent went disabling caching through a cache buster. Defaults to <tt>'_dc'</tt>.
      */
     disableCachingParam: '_dc',
-   
+
     /**
      * @property callbackKey
      * @type String
@@ -54055,7 +56467,7 @@ Ext.define('Ext.data.JsonP', {
      * url?callback=Ext.data.JsonP.callback1
      */
     callbackKey: 'callback',
-   
+
     /**
      * Makes a JSONP request.
      * @param {Object} options An object which may contain the following properties. Note that options will
@@ -54075,7 +56487,7 @@ Ext.define('Ext.data.JsonP', {
      * <li><b>disableCachingParam</b> : String (Optional) <div class="sub-desc">See {@link #disableCachingParam}</div></li>
      * <li><b>success</b> : Function (Optional) <div class="sub-desc">A function to execute if the request succeeds.</div></li>
      * <li><b>failure</b> : Function (Optional) <div class="sub-desc">A function to execute if the request fails.</div></li>
-     * <li><b>callback</b> : Function (Optional) <div class="sub-desc">A function to execute when the request 
+     * <li><b>callback</b> : Function (Optional) <div class="sub-desc">A function to execute when the request
      * completes, whether it is a success or failure.</div></li>
      * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
      * which to execute the callbacks: The "this" object for the callback function. Defaults to the browser window.</div></li>
@@ -54084,32 +56496,33 @@ Ext.define('Ext.data.JsonP', {
      */
     request: function(options){
         options = Ext.apply({}, options);
-       
+
         //<debug>
         if (!options.url) {
             Ext.Error.raise('A url must be specified for a JSONP request.');
         }
         //</debug>
-        
-        var me = this, 
-            disableCaching = Ext.isDefined(options.disableCaching) ? options.disableCaching : me.disableCaching, 
-            cacheParam = options.disableCachingParam || me.disableCachingParam, 
-            id = ++me.statics().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), 
+
+        var me = this,
+            disableCaching = Ext.isDefined(options.disableCaching) ? options.disableCaching : me.disableCaching,
+            cacheParam = options.disableCachingParam || me.disableCachingParam,
+            id = ++me.statics().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,
-            request, 
+            name = Ext.isSandboxed ? Ext.getUniqueGlobalNamespace() : 'Ext',
+            request,
             script;
-            
-        params[callbackKey] = 'Ext.data.JsonP.' + callbackName;
+
+        params[callbackKey] = name + '.data.JsonP.' + callbackName;
         if (disableCaching) {
             params[cacheParam] = new Date().getTime();
         }
-        
+
         script = me.createScript(url, params);
-        
+
         me.statics().requests[id] = request = {
             url: url,
             params: params,
@@ -54121,17 +56534,17 @@ Ext.define('Ext.data.JsonP', {
             callback: options.callback,
             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);
         Ext.getHead().appendChild(script);
         return request;
     },
-    
+
     /**
      * Abort a request. If the request parameter is not specified all open requests will
      * be aborted.
@@ -54140,7 +56553,7 @@ Ext.define('Ext.data.JsonP', {
     abort: function(request){
         var requests = this.statics().requests,
             key;
-            
+
         if (request) {
             if (!request.id) {
                 request = requests[request];
@@ -54154,7 +56567,7 @@ Ext.define('Ext.data.JsonP', {
             }
         }
     },
-    
+
     /**
      * Sets up error handling for the script
      * @private
@@ -54163,7 +56576,7 @@ Ext.define('Ext.data.JsonP', {
     setupErrorHandling: function(request){
         request.script.onerror = Ext.bind(this.handleError, this, [request]);
     },
-    
+
     /**
      * Handles any aborts when loading the script
      * @private
@@ -54173,7 +56586,7 @@ Ext.define('Ext.data.JsonP', {
         request.errorType = 'abort';
         this.handleResponse(null, request);
     },
-    
+
     /**
      * Handles any script errors when loading the script
      * @private
@@ -54183,7 +56596,7 @@ Ext.define('Ext.data.JsonP', {
         request.errorType = 'error';
         this.handleResponse(null, request);
     },
+
     /**
      * Cleans up anu script handling errors
      * @private
@@ -54192,7 +56605,7 @@ Ext.define('Ext.data.JsonP', {
     cleanupErrorHandling: function(request){
         request.script.onerror = null;
     },
+
     /**
      * Handle any script timeouts
      * @private
@@ -54202,7 +56615,7 @@ Ext.define('Ext.data.JsonP', {
         request.errorType = 'timeout';
         this.handleResponse(null, request);
     },
+
     /**
      * Handle a successful response
      * @private
@@ -54210,9 +56623,9 @@ Ext.define('Ext.data.JsonP', {
      * @param {Object} request The request
      */
     handleResponse: function(result, request){
+
         var success = true;
+
         if (request.timeout) {
             clearTimeout(request.timeout);
         }
@@ -54220,7 +56633,7 @@ Ext.define('Ext.data.JsonP', {
         delete this.statics()[request.id];
         this.cleanupErrorHandling(request);
         Ext.fly(request.script).remove();
+
         if (request.errorType) {
             success = false;
             Ext.callback(request.failure, request.scope, [request.errorType]);
@@ -54229,7 +56642,7 @@ Ext.define('Ext.data.JsonP', {
         }
         Ext.callback(request.callback, request.scope, [success, result, request.errorType]);
     },
-    
+
     /**
      * Create the script tag
      * @private
@@ -54248,9 +56661,7 @@ Ext.define('Ext.data.JsonP', {
 /**
  * @class Ext.data.JsonPStore
  * @extends Ext.data.Store
- * @ignore
  * @private
- * <p><b>NOTE:</b> This class is in need of migration to the new API.</p>
  * <p>Small helper class to make creating {@link Ext.data.Store}s from different domain JSON data easier.
  * A JsonPStore will be automatically configured with a {@link Ext.data.reader.Json} and a {@link Ext.data.proxy.JsonP JsonPProxy}.</p>
  * <p>A store configuration would be something like:<pre><code>
@@ -54299,21 +56710,170 @@ Ext.define('Ext.data.JsonPStore', {
 });
 
 /**
- * @class Ext.data.NodeInterface
- * This class is meant to be used as a set of methods that are applied to the prototype of a
- * Record to decorate it with a Node API. This means that models used in conjunction with a tree
+ * This class is used as a set of methods that are applied to the prototype of a
+ * Model to decorate it with a Node API. This means that models used in conjunction with a tree
  * will have all of the tree related methods available on the model. In general this class will
- * not be used directly by the developer.
+ * not be used directly by the developer. This class also creates extra fields on the model if
+ * they do not exist, to help maintain the tree state and UI. These fields are documented as
+ * config options.
  */
 Ext.define('Ext.data.NodeInterface', {
     requires: ['Ext.data.Field'],
-    
+
+    /**
+     * @cfg {String} parentId
+     * ID of parent node.
+     */
+
+    /**
+     * @cfg {Number} index
+     * The position of the node inside its parent. When parent has 4 children and the node is third amongst them,
+     * index will be 2.
+     */
+
+    /**
+     * @cfg {Number} depth
+     * The number of parents this node has. A root node has depth 0, a child of it depth 1, and so on...
+     */
+
+    /**
+     * @cfg {Boolean} [expanded=false]
+     * True if the node is expanded.
+     */
+
+    /**
+     * @cfg {Boolean} [expandable=false]
+     * Set to true to allow for expanding/collapsing of this node.
+     */
+
+    /**
+     * @cfg {Boolean} [checked=null]
+     * Set to true or false to show a checkbox alongside this node.
+     */
+
+    /**
+     * @cfg {Boolean} [leaf=false]
+     * Set to true to indicate that this child can have no children. The expand icon/arrow will then not be
+     * rendered for this node.
+     */
+
+    /**
+     * @cfg {String} cls
+     * CSS class to apply for this node.
+     */
+
+    /**
+     * @cfg {String} iconCls
+     * CSS class to apply for this node's icon.
+     */
+
+    /**
+     * @cfg {String} icon
+     * URL for this node's icon.
+     */
+
+    /**
+     * @cfg {Boolean} root
+     * True if this is the root node.
+     */
+
+    /**
+     * @cfg {Boolean} isLast
+     * True if this is the last node.
+     */
+
+    /**
+     * @cfg {Boolean} isFirst
+     * True if this is the first node.
+     */
+
+    /**
+     * @cfg {Boolean} [allowDrop=true]
+     * Set to false to deny dropping on this node.
+     */
+
+    /**
+     * @cfg {Boolean} [allowDrag=true]
+     * Set to false to deny dragging of this node.
+     */
+
+    /**
+     * @cfg {Boolean} [loaded=false]
+     * True if the node has finished loading.
+     */
+
+    /**
+     * @cfg {Boolean} [loading=false]
+     * True if the node is currently loading.
+     */
+
+    /**
+     * @cfg {String} href
+     * An URL for a link that's created when this config is specified.
+     */
+
+    /**
+     * @cfg {String} hrefTarget
+     * Target for link. Only applicable when {@link #href} also specified.
+     */
+
+    /**
+     * @cfg {String} qtip
+     * Tooltip text to show on this node.
+     */
+
+    /**
+     * @cfg {String} qtitle
+     * Tooltip title.
+     */
+
+    /**
+     * @cfg {String} text
+     * The text for to show on node label.
+     */
+
+    /**
+     * @cfg {Ext.data.NodeInterface[]} children
+     * Array of child nodes.
+     */
+
+
+    /**
+     * @property nextSibling
+     * A reference to this node's next sibling node. `null` if this node does not have a next sibling.
+     */
+
+    /**
+     * @property previousSibling
+     * A reference to this node's previous sibling node. `null` if this node does not have a previous sibling.
+     */
+
+    /**
+     * @property parentNode
+     * A reference to this node's parent node. `null` if this node is the root node.
+     */
+
+    /**
+     * @property lastChild
+     * A reference to this node's last child node. `null` if this node has no children.
+     */
+
+    /**
+     * @property firstChild
+     * A reference to this node's first child node. `null` if this node has no children.
+     */
+
+    /**
+     * @property childNodes
+     * An array of this nodes children.  Array will be empty if this node has no chidren.
+     */
+
     statics: {
         /**
          * This method allows you to decorate a Record's prototype to implement the NodeInterface.
          * This adds a set of methods, new events, new properties and new fields on every Record
          * with the same Model as the passed Record.
-         * @param {Ext.data.Record} record The Record you want to decorate the prototype of.
+         * @param {Ext.data.Model} record The Record you want to decorate the prototype of.
          * @static
          */
         decorate: function(record) {
@@ -54333,13 +56893,14 @@ Ext.define('Ext.data.NodeInterface', {
                     {name: idName,       type: 'string',  defaultValue: null},
                     {name: 'parentId',   type: 'string',  defaultValue: null},
                     {name: 'index',      type: 'int',     defaultValue: null},
-                    {name: 'depth',      type: 'int',     defaultValue: 0}, 
+                    {name: 'depth',      type: 'int',     defaultValue: 0},
                     {name: 'expanded',   type: 'bool',    defaultValue: false, persist: false},
                     {name: 'expandable', type: 'bool',    defaultValue: true, persist: false},
                     {name: 'checked',    type: 'auto',    defaultValue: null},
                     {name: 'leaf',       type: 'bool',    defaultValue: false, persist: 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},
@@ -54362,7 +56923,7 @@ Ext.define('Ext.data.NodeInterface', {
                     }
                 }
             }
-            
+
             Ext.applyIf(record, {
                 firstChild: null,
                 lastChild: null,
@@ -54373,13 +56934,13 @@ Ext.define('Ext.data.NodeInterface', {
             });
             // Commit any fields so the record doesn't show as dirty initially
             record.commit(true);
-            
+
             record.enableBubble([
                 /**
                  * @event append
                  * Fires when a new child node is appended
-                 * @param {Node} this This node
-                 * @param {Node} node The newly appended node
+                 * @param {Ext.data.NodeInterface} this This node
+                 * @param {Ext.data.NodeInterface} node The newly appended node
                  * @param {Number} index The index of the newly appended node
                  */
                 "append",
@@ -54387,17 +56948,17 @@ Ext.define('Ext.data.NodeInterface', {
                 /**
                  * @event remove
                  * Fires when a child node is removed
-                 * @param {Node} this This node
-                 * @param {Node} node The removed node
+                 * @param {Ext.data.NodeInterface} this This node
+                 * @param {Ext.data.NodeInterface} node The removed node
                  */
                 "remove",
 
                 /**
                  * @event move
                  * Fires when this node is moved to a new location in the tree
-                 * @param {Node} this This node
-                 * @param {Node} oldParent The old parent of this node
-                 * @param {Node} newParent The new parent of this node
+                 * @param {Ext.data.NodeInterface} this This node
+                 * @param {Ext.data.NodeInterface} oldParent The old parent of this node
+                 * @param {Ext.data.NodeInterface} newParent The new parent of this node
                  * @param {Number} index The index it was moved to
                  */
                 "move",
@@ -54405,34 +56966,34 @@ Ext.define('Ext.data.NodeInterface', {
                 /**
                  * @event insert
                  * Fires when a new child node is inserted.
-                 * @param {Node} this This node
-                 * @param {Node} node The child node inserted
-                 * @param {Node} refNode The child node the node was inserted before
+                 * @param {Ext.data.NodeInterface} this This node
+                 * @param {Ext.data.NodeInterface} node The child node inserted
+                 * @param {Ext.data.NodeInterface} refNode The child node the node was inserted before
                  */
                 "insert",
 
                 /**
                  * @event beforeappend
                  * Fires before a new child is appended, return false to cancel the append.
-                 * @param {Node} this This node
-                 * @param {Node} node The child node to be appended
+                 * @param {Ext.data.NodeInterface} this This node
+                 * @param {Ext.data.NodeInterface} node The child node to be appended
                  */
                 "beforeappend",
 
                 /**
                  * @event beforeremove
                  * Fires before a child is removed, return false to cancel the remove.
-                 * @param {Node} this This node
-                 * @param {Node} node The child node to be removed
+                 * @param {Ext.data.NodeInterface} this This node
+                 * @param {Ext.data.NodeInterface} node The child node to be removed
                  */
                 "beforeremove",
 
                 /**
                  * @event beforemove
                  * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
-                 * @param {Node} this This node
-                 * @param {Node} oldParent The parent of this node
-                 * @param {Node} newParent The new parent this node is moving to
+                 * @param {Ext.data.NodeInterface} this This node
+                 * @param {Ext.data.NodeInterface} oldParent The parent of this node
+                 * @param {Ext.data.NodeInterface} newParent The new parent this node is moving to
                  * @param {Number} index The index it is being moved to
                  */
                 "beforemove",
@@ -54440,52 +57001,52 @@ Ext.define('Ext.data.NodeInterface', {
                  /**
                   * @event beforeinsert
                   * Fires before a new child is inserted, return false to cancel the insert.
-                  * @param {Node} this This node
-                  * @param {Node} node The child node to be inserted
-                  * @param {Node} refNode The child node the node is being inserted before
+                  * @param {Ext.data.NodeInterface} this This node
+                  * @param {Ext.data.NodeInterface} node The child node to be inserted
+                  * @param {Ext.data.NodeInterface} refNode The child node the node is being inserted before
                   */
                 "beforeinsert",
-                
+
                 /**
                  * @event expand
                  * Fires when this node is expanded.
-                 * @param {Node} this The expanding node
+                 * @param {Ext.data.NodeInterface} this The expanding node
                  */
                 "expand",
-                
+
                 /**
                  * @event collapse
                  * Fires when this node is collapsed.
-                 * @param {Node} this The collapsing node
+                 * @param {Ext.data.NodeInterface} this The collapsing node
                  */
                 "collapse",
-                
+
                 /**
                  * @event beforeexpand
                  * Fires before this node is expanded.
-                 * @param {Node} this The expanding node
+                 * @param {Ext.data.NodeInterface} this The expanding node
                  */
                 "beforeexpand",
-                
+
                 /**
                  * @event beforecollapse
                  * Fires before this node is collapsed.
-                 * @param {Node} this The collapsing node
+                 * @param {Ext.data.NodeInterface} this The collapsing node
                  */
                 "beforecollapse",
-                
+
                 /**
                  * @event sort
                  * Fires when this node's childNodes are sorted.
-                 * @param {Node} this This node.
-                 * @param {Array} The childNodes of this node.
+                 * @param {Ext.data.NodeInterface} this This node.
+                 * @param {Ext.data.NodeInterface[]} childNodes The childNodes of this node.
                  */
                 "sort"
             ]);
-            
+
             return record;
         },
-        
+
         applyFields: function(modelClass, addFields) {
             var modelPrototype = modelClass.prototype,
                 fields = modelPrototype.fields,
@@ -54493,20 +57054,20 @@ Ext.define('Ext.data.NodeInterface', {
                 ln = addFields.length,
                 addField, i, name,
                 newFields = [];
-                
+
             for (i = 0; i < ln; i++) {
                 addField = addFields[i];
                 if (!Ext.Array.contains(keys, addField.name)) {
                     addField = Ext.create('data.field', addField);
-                    
+
                     newFields.push(addField);
                     fields.add(addField);
                 }
             }
-            
+
             return newFields;
         },
-        
+
         getPrototypeBody: function() {
             return {
                 isNode: true,
@@ -54522,7 +57083,7 @@ Ext.define('Ext.data.NodeInterface', {
                     // Make sure the node implements the node interface
                     return Ext.data.NodeInterface.decorate(node);
                 },
-                
+
                 /**
                  * Returns true if this node is a leaf
                  * @return {Boolean}
@@ -54571,8 +57132,8 @@ Ext.define('Ext.data.NodeInterface', {
                     while (parent.parentNode) {
                         ++depth;
                         parent = parent.parentNode;
-                    }                                            
-                    
+                    }
+
                     me.beginEdit();
                     me.set({
                         isFirst: isFirst,
@@ -54585,7 +57146,7 @@ Ext.define('Ext.data.NodeInterface', {
                     if (silent) {
                         me.commit();
                     }
-                    
+
                     for (i = 0; i < len; i++) {
                         children[i].updateInfo(silent);
                     }
@@ -54617,12 +57178,12 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Returns true if this node has one or more child nodes, or if the <tt>expandable</tt>
-                 * node attribute is explicitly specified as true (see {@link #attributes}), otherwise returns false.
+                 * node attribute is explicitly specified as true, otherwise returns false.
                  * @return {Boolean}
                  */
                 isExpandable : function() {
                     var me = this;
-                    
+
                     if (me.get('expandable')) {
                         return !(me.isLeaf() || (me.isLoaded() && !me.hasChildNodes()));
                     }
@@ -54630,10 +57191,12 @@ Ext.define('Ext.data.NodeInterface', {
                 },
 
                 /**
-                 * <p>Insert node(s) as the last child node of this node.</p>
-                 * <p>If the node was previously a child node of another parent node, it will be removed from that node first.</p>
-                 * @param {Node/Array} node The node or Array of nodes to append
-                 * @return {Node} The appended node if single append, or null if an array was passed
+                 * Inserts node(s) as the last child node of this node.
+                 *
+                 * If the node was previously a child node of another parent node, it will be removed from that node first.
+                 *
+                 * @param {Ext.data.NodeInterface/Ext.data.NodeInterface[]} node The node or Array of nodes to append
+                 * @return {Ext.data.NodeInterface} The appended node if single append, or null if an array was passed
                  */
                 appendChild : function(node, suppressEvents, suppressNodeUpdate) {
                     var me = this,
@@ -54650,9 +57213,9 @@ Ext.define('Ext.data.NodeInterface', {
                     } else {
                         // Make sure it is a record
                         node = me.createNode(node);
-                        
+
                         if (suppressEvents !== true && me.fireEvent("beforeappend", me, node) === false) {
-                            return false;                         
+                            return false;
                         }
 
                         index = me.childNodes.length;
@@ -54676,7 +57239,7 @@ Ext.define('Ext.data.NodeInterface', {
                         node.nextSibling = null;
 
                         me.setLastChild(node);
-                                                
+
                         ps = me.childNodes[index - 1];
                         if (ps) {
                             node.previousSibling = ps;
@@ -54687,28 +57250,28 @@ Ext.define('Ext.data.NodeInterface', {
                         }
 
                         node.updateInfo(suppressNodeUpdate);
-                        
+
                         // As soon as we append a child to this node, we are loaded
                         if (!me.isLoaded()) {
-                            me.set('loaded', true);                            
+                            me.set('loaded', true);
                         }
                         // If this node didnt have any childnodes before, update myself
                         else if (me.childNodes.length === 1) {
                             me.set('loaded', me.isLoaded());
                         }
-                        
+
                         if (suppressEvents !== true) {
                             me.fireEvent("append", me, node, index);
 
                             if (oldParent) {
                                 node.fireEvent("move", node, oldParent, me, index);
-                            }                            
+                            }
                         }
 
                         return node;
                     }
                 },
-                
+
                 /**
                  * Returns the bubble target for this node
                  * @private
@@ -54720,14 +57283,14 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Removes a child node from this node.
-                 * @param {Node} node The node to remove
-                 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
-                 * @return {Node} The removed node
+                 * @param {Ext.data.NodeInterface} node The node to remove
+                 * @param {Boolean} [destroy=false] True to destroy the node upon removal.
+                 * @return {Ext.data.NodeInterface} The removed node
                  */
                 removeChild : function(node, destroy, suppressEvents, suppressNodeUpdate) {
                     var me = this,
                         index = me.indexOf(node);
-                    
+
                     if (index == -1 || (suppressEvents !== true && me.fireEvent("beforeremove", me, node) === false)) {
                         return false;
                     }
@@ -54742,7 +57305,7 @@ Ext.define('Ext.data.NodeInterface', {
                     if (me.lastChild == node) {
                         me.setLastChild(node.previousSibling);
                     }
-                    
+
                     // update siblings
                     if (node.previousSibling) {
                         node.previousSibling.nextSibling = node.nextSibling;
@@ -54756,13 +57319,13 @@ Ext.define('Ext.data.NodeInterface', {
                     if (suppressEvents !== true) {
                         me.fireEvent("remove", me, node);
                     }
-                    
-                    
+
+
                     // If this node suddenly doesnt have childnodes anymore, update myself
                     if (!me.childNodes.length) {
                         me.set('loaded', me.isLoaded());
                     }
-                    
+
                     if (destroy) {
                         node.destroy(true);
                     } else {
@@ -54774,10 +57337,10 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Creates a copy (clone) of this Node.
-                 * @param {String} id (optional) A new id, defaults to this Node's id. See <code>{@link #id}</code>.
-                 * @param {Boolean} deep (optional) <p>If passed as <code>true</code>, all child Nodes are recursively copied into the new Node.</p>
-                 * <p>If omitted or false, the copy will have no child Nodes.</p>
-                 * @return {Node} A copy of this Node.
+                 * @param {String} [id] A new id, defaults to this Node's id.
+                 * @param {Boolean} [deep=false] True to recursively copy all child Nodes into the new Node.
+                 * False to copy without child Nodes.
+                 * @return {Ext.data.NodeInterface} A copy of this Node.
                  */
                 copy: function(newId, deep) {
                     var me = this,
@@ -54795,13 +57358,13 @@ Ext.define('Ext.data.NodeInterface', {
                 },
 
                 /**
-                 * Clear the node.
+                 * Clears the node.
                  * @private
-                 * @param {Boolean} destroy True to destroy the node.
+                 * @param {Boolean} [destroy=false] True to destroy the node.
                  */
                 clear : function(destroy) {
                     var me = this;
-                    
+
                     // clear any references from the node
                     me.parentNode = me.previousSibling = me.nextSibling = null;
                     if (destroy) {
@@ -54821,7 +57384,7 @@ Ext.define('Ext.data.NodeInterface', {
                      */
                     var me = this,
                         options = me.destroyOptions;
-                    
+
                     if (silent === true) {
                         me.clear(true);
                         Ext.each(me.childNodes, function(n) {
@@ -54839,9 +57402,9 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Inserts the first node before the second node in this nodes childNodes collection.
-                 * @param {Node} node The node to insert
-                 * @param {Node} refNode The node to insert before (if null the node is appended)
-                 * @return {Node} The inserted node
+                 * @param {Ext.data.NodeInterface} node The node to insert
+                 * @param {Ext.data.NodeInterface} refNode The node to insert before (if null the node is appended)
+                 * @return {Ext.data.NodeInterface} The inserted node
                  */
                 insertBefore : function(node, refNode, suppressEvents) {
                     var me = this,
@@ -54849,11 +57412,11 @@ Ext.define('Ext.data.NodeInterface', {
                         oldParent = node.parentNode,
                         refIndex  = index,
                         ps;
-                    
+
                     if (!refNode) { // like standard Dom, refNode can be null for append
                         return me.appendChild(node);
                     }
-                    
+
                     // nothing to do
                     if (node == refNode) {
                         return false;
@@ -54861,11 +57424,11 @@ Ext.define('Ext.data.NodeInterface', {
 
                     // Make sure it is a record with the NodeInterface
                     node = me.createNode(node);
-                    
+
                     if (suppressEvents !== true && me.fireEvent("beforeinsert", me, node, refNode) === false) {
                         return false;
                     }
-                    
+
                     // when moving internally, indexes will change after remove
                     if (oldParent == me && me.indexOf(node) < index) {
                         refIndex--;
@@ -54885,10 +57448,10 @@ Ext.define('Ext.data.NodeInterface', {
 
                     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;
@@ -54897,12 +57460,12 @@ Ext.define('Ext.data.NodeInterface', {
                     } else {
                         node.previousSibling = null;
                     }
-                    
+
                     node.updateInfo();
-                    
+
                     if (!me.isLoaded()) {
-                        me.set('loaded', true);                            
-                    }    
+                        me.set('loaded', true);
+                    }
                     // If this node didnt have any childnodes before, update myself
                     else if (me.childNodes.length === 1) {
                         me.set('loaded', me.isLoaded());
@@ -54913,18 +57476,18 @@ Ext.define('Ext.data.NodeInterface', {
 
                         if (oldParent) {
                             node.fireEvent("move", node, oldParent, me, refIndex, refNode);
-                        }                        
+                        }
                     }
 
                     return node;
                 },
-                
+
                 /**
                  * Insert a node into this node
                  * @param {Number} index The zero-based index to insert the node at
                  * @param {Ext.data.Model} node The node to insert
-                 * @return {Ext.data.Record} The record you just inserted
-                 */    
+                 * @return {Ext.data.Model} The record you just inserted
+                 */
                 insertChild: function(index, node) {
                     var sibling = this.childNodes[index];
                     if (sibling) {
@@ -54937,8 +57500,8 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Removes this node from its parent
-                 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
-                 * @return {Node} this
+                 * @param {Boolean} [destroy=false] True to destroy the node upon removal.
+                 * @return {Ext.data.NodeInterface} this
                  */
                 remove : function(destroy, suppressEvents) {
                     var parentNode = this.parentNode;
@@ -54951,8 +57514,8 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Removes all child nodes from this node.
-                 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
-                 * @return {Node} this
+                 * @param {Boolean} [destroy=false] <True to destroy the node upon removal.
+                 * @return {Ext.data.NodeInterface} this
                  */
                 removeAll : function(destroy, suppressEvents) {
                     var cn = this.childNodes,
@@ -54967,7 +57530,7 @@ Ext.define('Ext.data.NodeInterface', {
                 /**
                  * Returns the child node at the specified index.
                  * @param {Number} index
-                 * @return {Node}
+                 * @return {Ext.data.NodeInterface}
                  */
                 getChildAt : function(index) {
                     return this.childNodes[index];
@@ -54975,13 +57538,13 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Replaces one child node in this node with another.
-                 * @param {Node} newChild The replacement node
-                 * @param {Node} oldChild The node to replace
-                 * @return {Node} The replaced node
+                 * @param {Ext.data.NodeInterface} newChild The replacement node
+                 * @param {Ext.data.NodeInterface} oldChild The node to replace
+                 * @return {Ext.data.NodeInterface} The replaced node
                  */
                 replaceChild : function(newChild, oldChild, suppressEvents) {
                     var s = oldChild ? oldChild.nextSibling : null;
-                    
+
                     this.removeChild(oldChild, suppressEvents);
                     this.insertBefore(newChild, s, suppressEvents);
                     return oldChild;
@@ -54989,13 +57552,33 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Returns the index of a child node
-                 * @param {Node} node
+                 * @param {Ext.data.NodeInterface} node
                  * @return {Number} The index of the node or -1 if it was not found
                  */
                 indexOf : function(child) {
                     return Ext.Array.indexOf(this.childNodes, child);
                 },
 
+                /**
+                 * Gets the hierarchical path from the root of the current node.
+                 * @param {String} [field] The field to construct the path from. Defaults to the model idProperty.
+                 * @param {String} [separator="/"] A separator to use.
+                 * @return {String} The node path
+                 */
+                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);
+                },
+
                 /**
                  * Returns depth of this node (the root node has a depth of 0)
                  * @return {Number}
@@ -55009,8 +57592,8 @@ Ext.define('Ext.data.NodeInterface', {
                  * will be the args provided or the current node. If the function returns false at any point,
                  * the bubble is stopped.
                  * @param {Function} fn The function to call
-                 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.
-                 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
+                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the current Node.
+                 * @param {Array} [args] The args to call the function with. Defaults to passing the current Node.
                  */
                 bubble : function(fn, scope, args) {
                     var p = this;
@@ -55036,8 +57619,8 @@ Ext.define('Ext.data.NodeInterface', {
                  * will be the args provided or the current node. If the function returns false at any point,
                  * the cascade is stopped on that branch.
                  * @param {Function} fn The function to call
-                 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.
-                 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
+                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the current Node.
+                 * @param {Array} [args] The args to call the function with. Defaults to passing the current Node.
                  */
                 cascadeBy : function(fn, scope, args) {
                     if (fn.apply(scope || this, args || [this]) !== false) {
@@ -55056,8 +57639,8 @@ Ext.define('Ext.data.NodeInterface', {
                  * will be the args provided or the current node. If the function returns false at any point,
                  * the iteration stops.
                  * @param {Function} fn The function to call
-                 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node in the iteration.
-                 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
+                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the current Node in iteration.
+                 * @param {Array} [args] The args to call the function with. Defaults to passing the current Node.
                  */
                 eachChild : function(fn, scope, args) {
                     var childNodes = this.childNodes,
@@ -55074,9 +57657,9 @@ Ext.define('Ext.data.NodeInterface', {
                 /**
                  * Finds the first child that has the attribute with the specified value.
                  * @param {String} attribute The attribute name
-                 * @param {Mixed} value The value to search for
-                 * @param {Boolean} deep (Optional) True to search through nodes deeper than the immediate children
-                 * @return {Node} The found child or null if none was found
+                 * @param {Object} value The value to search for
+                 * @param {Boolean} [deep=false] True to search through nodes deeper than the immediate children
+                 * @return {Ext.data.NodeInterface} The found child or null if none was found
                  */
                 findChild : function(attribute, value, deep) {
                     return this.findChildBy(function() {
@@ -55085,11 +57668,11 @@ Ext.define('Ext.data.NodeInterface', {
                 },
 
                 /**
-                 * Finds the first child by a custom function. The child matches if the function passed returns <code>true</code>.
-                 * @param {Function} fn A function which must return <code>true</code> if the passed Node is the required Node.
-                 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Node being tested.
-                 * @param {Boolean} deep (Optional) True to search through nodes deeper than the immediate children
-                 * @return {Node} The found child or null if none was found
+                 * Finds the first child by a custom function. The child matches if the function passed returns true.
+                 * @param {Function} fn A function which must return true if the passed Node is the required Node.
+                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the Node being tested.
+                 * @param {Boolean} [deep=false] True to search through nodes deeper than the immediate children
+                 * @return {Ext.data.NodeInterface} The found child or null if none was found
                  */
                 findChildBy : function(fn, scope, deep) {
                     var cs = this.childNodes,
@@ -55114,7 +57697,7 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Returns true if this node is an ancestor (at any point) of the passed node.
-                 * @param {Node} node
+                 * @param {Ext.data.NodeInterface} node
                  * @return {Boolean}
                  */
                 contains : function(node) {
@@ -55123,7 +57706,7 @@ Ext.define('Ext.data.NodeInterface', {
 
                 /**
                  * Returns true if the passed node is an ancestor (at any point) of this node.
-                 * @param {Node} node
+                 * @param {Ext.data.NodeInterface} node
                  * @return {Boolean}
                  */
                 isAncestor : function(node) {
@@ -55140,21 +57723,21 @@ Ext.define('Ext.data.NodeInterface', {
                 /**
                  * Sorts this nodes children using the supplied sort function.
                  * @param {Function} fn A function which, when passed two Nodes, returns -1, 0 or 1 depending upon required sort order.
-                 * @param {Boolean} recursive Whether or not to apply this sort recursively
-                 * @param {Boolean} suppressEvent Set to true to not fire a sort event.
+                 * @param {Boolean} [recursive=false] True to apply this sort recursively
+                 * @param {Boolean} [suppressEvent=false] True to not fire a sort event.
                  */
                 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);
                                 n.updateInfo();
@@ -55167,25 +57750,25 @@ Ext.define('Ext.data.NodeInterface', {
                                 n.sort(sortFn, true, true);
                             }
                         }
-                        
+
                         if (suppressEvent !== true) {
                             this.fireEvent('sort', this, cs);
                         }
                     }
                 },
-                        
+
                 /**
                  * Returns true if this node is expaned
                  * @return {Boolean}
-                 */        
+                 */
                 isExpanded: function() {
                     return this.get('expanded');
                 },
-                
+
                 /**
                  * Returns true if this node is loaded
                  * @return {Boolean}
-                 */ 
+                 */
                 isLoaded: function() {
                     return this.get('loaded');
                 },
@@ -55193,23 +57776,23 @@ Ext.define('Ext.data.NodeInterface', {
                 /**
                  * Returns true if this node is loading
                  * @return {Boolean}
-                 */ 
+                 */
                 isLoading: function() {
                     return this.get('loading');
                 },
-                                
+
                 /**
                  * Returns true if this node is the root node
                  * @return {Boolean}
-                 */ 
+                 */
                 isRoot: function() {
                     return !this.parentNode;
                 },
-                
+
                 /**
                  * Returns true if this node is visible
                  * @return {Boolean}
-                 */ 
+                 */
                 isVisible: function() {
                     var parent = this.parentNode;
                     while (parent) {
@@ -55220,12 +57803,12 @@ Ext.define('Ext.data.NodeInterface', {
                     }
                     return true;
                 },
-                
+
                 /**
                  * Expand this node.
-                 * @param {Function} recursive (Optional) True to recursively expand all the children
-                 * @param {Function} callback (Optional) The function to execute once the expand completes
-                 * @param {Object} scope (Optional) The scope to run the callback in
+                 * @param {Boolean} [recursive=false] True to recursively expand all the children
+                 * @param {Function} [callback] The function to execute once the expand completes
+                 * @param {Object} [scope] The scope to run the callback in
                  */
                 expand: function(recursive, callback, scope) {
                     var me = this;
@@ -55235,48 +57818,47 @@ Ext.define('Ext.data.NodeInterface', {
 
                     // First we start by checking if this node is a parent
                     if (!me.isLeaf()) {
-                        // Now we check if this record is already expanding or expanded
-                        if (!me.isLoading() && !me.isExpanded()) {
-                            // The TreeStore actually listens for the beforeexpand method and checks
-                            // whether we have to asynchronously load the children from the server
-                            // first. Thats why we pass a callback function to the event that the
-                            // store can call once it has loaded and parsed all the children.
-                            me.fireEvent('beforeexpand', me, function() {
-                                me.set('expanded', true); 
-                                me.fireEvent('expand', me, me.childNodes, false);
-                                
-                                // Call the expandChildren method if recursive was set to true 
-                                if (recursive) {
-                                    me.expandChildren(true, callback, scope);
-                                }
-                                else {
-                                    Ext.callback(callback, scope || me, [me.childNodes]);                                
-                                }
-                            }, me);                            
-                        }
-                        // If it is is already expanded but we want to recursively expand then call expandChildren
-                        else if (recursive) {
-                            me.expandChildren(true, callback, scope);
-                        }
-                        else {
-                            Ext.callback(callback, scope || me, [me.childNodes]);
+                        // If it's loaded, wait until it loads before proceeding
+                        if (me.isLoading()) {
+                            me.on('expand', function(){
+                                me.expand(recursive, callback, scope);
+                            }, me, {single: true});
+                        } else {
+                            // Now we check if this record is already expanding or expanded
+                            if (!me.isExpanded()) {
+                                // The TreeStore actually listens for the beforeexpand method and checks
+                                // whether we have to asynchronously load the children from the server
+                                // first. Thats why we pass a callback function to the event that the
+                                // store can call once it has loaded and parsed all the children.
+                                me.fireEvent('beforeexpand', me, function(){
+                                    me.set('expanded', true);
+                                    me.fireEvent('expand', me, me.childNodes, false);
+
+                                    // Call the expandChildren method if recursive was set to true
+                                    if (recursive) {
+                                        me.expandChildren(true, callback, scope);
+                                    } else {
+                                        Ext.callback(callback, scope || me, [me.childNodes]);
+                                    }
+                                }, me);
+                            } else if (recursive) {
+                                // If it is is already expanded but we want to recursively expand then call expandChildren
+                                me.expandChildren(true, callback, scope);
+                            } else {
+                                Ext.callback(callback, scope || me, [me.childNodes]);
+                            }
                         }
-
-                        // TODO - if the node isLoading, we probably need to defer the
-                        // callback until it is loaded (e.g., selectPath would need us
-                        // to not make the callback until the childNodes exist).
-                    }
-                    // If it's not then we fire the callback right away
-                    else {
+                    } else {
+                        // If it's not then we fire the callback right away
                         Ext.callback(callback, scope || me); // leaf = no childNodes
                     }
                 },
-                
+
                 /**
                  * Expand all the children of this node.
-                 * @param {Function} recursive (Optional) True to recursively expand all the children
-                 * @param {Function} callback (Optional) The function to execute once all the children are expanded
-                 * @param {Object} scope (Optional) The scope to run the callback in
+                 * @param {Boolean} [recursive=false] True to recursively expand all the children
+                 * @param {Function} [callback] The function to execute once all the children are expanded
+                 * @param {Object} [scope] The scope to run the callback in
                  */
                 expandChildren: function(recursive, callback, scope) {
                     var me = this,
@@ -55293,21 +57875,21 @@ Ext.define('Ext.data.NodeInterface', {
                             nodes[i].expand(recursive, function () {
                                 expanding--;
                                 if (callback && !expanding) {
-                                    Ext.callback(callback, scope || me, [me.childNodes]); 
+                                    Ext.callback(callback, scope || me, [me.childNodes]);
                                 }
-                            });                            
+                            });
                         }
                     }
-                    
+
                     if (!expanding && callback) {
                         Ext.callback(callback, scope || me, [me.childNodes]);                    }
                 },
 
                 /**
                  * Collapse this node.
-                 * @param {Function} recursive (Optional) True to recursively collapse all the children
-                 * @param {Function} callback (Optional) The function to execute once the collapse completes
-                 * @param {Object} scope (Optional) The scope to run the callback in
+                 * @param {Boolean} [recursive=false] True to recursively collapse all the children
+                 * @param {Function} [callback] The function to execute once the collapse completes
+                 * @param {Object} [scope] The scope to run the callback in
                  */
                 collapse: function(recursive, callback, scope) {
                     var me = this;
@@ -55317,17 +57899,17 @@ Ext.define('Ext.data.NodeInterface', {
                         // Now we check if this record is already collapsing or collapsed
                         if (!me.collapsing && me.isExpanded()) {
                             me.fireEvent('beforecollapse', me, function() {
-                                me.set('expanded', false); 
+                                me.set('expanded', false);
                                 me.fireEvent('collapse', me, me.childNodes, false);
-                                
-                                // Call the collapseChildren method if recursive was set to true 
+
+                                // Call the collapseChildren method if recursive was set to true
                                 if (recursive) {
                                     me.collapseChildren(true, callback, scope);
                                 }
                                 else {
-                                    Ext.callback(callback, scope || me, [me.childNodes]);                                
+                                    Ext.callback(callback, scope || me, [me.childNodes]);
                                 }
-                            }, me);                            
+                            }, me);
                         }
                         // If it is is already collapsed but we want to recursively collapse then call collapseChildren
                         else if (recursive) {
@@ -55336,15 +57918,15 @@ Ext.define('Ext.data.NodeInterface', {
                     }
                     // If it's not then we fire the callback right away
                     else {
-                        Ext.callback(callback, scope || me, [me.childNodes]); 
+                        Ext.callback(callback, scope || me, [me.childNodes]);
                     }
                 },
-                
+
                 /**
                  * Collapse all the children of this node.
-                 * @param {Function} recursive (Optional) True to recursively collapse all the children
-                 * @param {Function} callback (Optional) The function to execute once all the children are collapsed
-                 * @param {Object} scope (Optional) The scope to run the callback in
+                 * @param {Function} [recursive=false] True to recursively collapse all the children
+                 * @param {Function} [callback] The function to execute once all the children are collapsed
+                 * @param {Object} [scope] The scope to run the callback in
                  */
                 collapseChildren: function(recursive, callback, scope) {
                     var me = this,
@@ -55361,12 +57943,12 @@ Ext.define('Ext.data.NodeInterface', {
                             nodes[i].collapse(recursive, function () {
                                 collapsing--;
                                 if (callback && !collapsing) {
-                                    Ext.callback(callback, scope || me, [me.childNodes]); 
+                                    Ext.callback(callback, scope || me, [me.childNodes]);
                                 }
-                            });                            
+                            });
                         }
                     }
-                    
+
                     if (!collapsing && callback) {
                         Ext.callback(callback, scope || me, [me.childNodes]);
                     }
@@ -55387,14 +57969,16 @@ Ext.define('Ext.data.NodeStore', {
     requires: ['Ext.data.NodeInterface'],
     
     /**
-     * @cfg {Ext.data.Record} node The Record you want to bind this Store to. Note that
+     * @cfg {Ext.data.Model} node
+     * The Record you want to bind this Store to. Note that
      * this record will be decorated with the Ext.data.NodeInterface if this is not the
      * case yet.
      */
     node: null,
     
     /**
-     * @cfg {Boolean} recursive Set this to true if you want this NodeStore to represent
+     * @cfg {Boolean} recursive
+     * Set this to true if you want this NodeStore to represent
      * all the descendents of the node in its flat data collection. This is useful for
      * rendering a tree structure to a DataView and is being used internally by
      * the TreeView. Any records that are moved, removed, inserted or appended to the
@@ -55404,7 +57988,8 @@ Ext.define('Ext.data.NodeStore', {
     recursive: false,
     
     /** 
-     * @cfg {Boolean} rootVisible <tt>false</tt> to not include the root node in this Stores collection (defaults to <tt>true</tt>)
+     * @cfg {Boolean} rootVisible
+     * False to not include the root node in this Stores collection.
      */    
     rootVisible: false,
     
@@ -55624,79 +58209,142 @@ Ext.define('Ext.data.NodeStore', {
 });
 /**
  * @author Ed Spencer
- * @class Ext.data.Request
- * @extends Object
  * 
- * <p>Simple class that represents a Request that will be made by any {@link Ext.data.proxy.Server} subclass.
+ * Simple class that represents a Request that will be made by any {@link Ext.data.proxy.Server} subclass.
  * All this class does is standardize the representation of a Request as used by any ServerProxy subclass,
- * it does not contain any actual logic or perform the request itself.</p>
- * 
+ * it does not contain any actual logic or perform the request itself.
  */
 Ext.define('Ext.data.Request', {
     /**
-     * @cfg {String} action The name of the action this Request represents. Usually one of 'create', 'read', 'update' or 'destroy'
+     * @cfg {String} action
+     * The name of the action this Request represents. Usually one of 'create', 'read', 'update' or 'destroy'.
      */
     action: undefined,
     
     /**
-     * @cfg {Object} params HTTP request params. The Proxy and its Writer have access to and can modify this object.
+     * @cfg {Object} params
+     * HTTP request params. The Proxy and its Writer have access to and can modify this object.
      */
     params: undefined,
     
     /**
-     * @cfg {String} method The HTTP method to use on this Request (defaults to 'GET'). Should be one of 'GET', 'POST', 'PUT' or 'DELETE'
+     * @cfg {String} method
+     * The HTTP method to use on this Request. Should be one of 'GET', 'POST', 'PUT' or 'DELETE'.
      */
     method: 'GET',
     
     /**
-     * @cfg {String} url The url to access on this Request
+     * @cfg {String} url
+     * The url to access on this Request
      */
     url: undefined,
 
     /**
      * Creates the Request object.
-     * @param {Object} config (optional) Config object.
+     * @param {Object} [config] Config object.
      */
     constructor: function(config) {
         Ext.apply(this, config);
     }
 });
+/**
+ * @author Don Griffin
+ *
+ * This class is a sequential id generator. A simple use of this class would be like so:
+ *
+ *     Ext.define('MyApp.data.MyModel', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'sequential'
+ *     });
+ *     // assign id's of 1, 2, 3, etc.
+ *
+ * An example of a configured generator would be:
+ *
+ *     Ext.define('MyApp.data.MyModel', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: {
+ *             type: 'sequential',
+ *             prefix: 'ID_',
+ *             seed: 1000
+ *         }
+ *     });
+ *     // assign id's of ID_1000, ID_1001, ID_1002, etc.
+ *
+ */
+Ext.define('Ext.data.SequentialIdGenerator', {
+    extend: 'Ext.data.IdGenerator',
+    alias: 'idgen.sequential',
+
+    constructor: function() {
+        var me = this;
+
+        me.callParent(arguments);
+
+        me.parts = [ me.prefix, ''];
+    },
+
+    /**
+     * @cfg {String} prefix
+     * The string to place in front of the sequential number for each generated id. The
+     * default is blank.
+     */
+    prefix: '',
+
+    /**
+     * @cfg {Number} seed
+     * The number at which to start generating sequential id's. The default is 1.
+     */
+    seed: 1,
+
+    /**
+     * Generates and returns the next id.
+     * @return {String} The next id.
+     */
+    generate: function () {
+        var me = this,
+            parts = me.parts;
+
+        parts[1] = me.seed++;
+        return parts.join('');
+    }
+});
+
 /**
  * @class Ext.data.Tree
- * 
+ *
  * This class is used as a container for a series of nodes. The nodes themselves maintain
  * the relationship between parent/child. The tree itself acts as a manager. It gives functionality
- * to retrieve a node by its identifier: {@link #getNodeById}. 
+ * to retrieve a node by its identifier: {@link #getNodeById}.
  *
- * The tree also relays events from any of it's child nodes, allowing them to be handled in a 
- * centralized fashion. In general this class is not used directly, rather used internally 
+ * The tree also relays events from any of it's child nodes, allowing them to be handled in a
+ * centralized fashion. In general this class is not used directly, rather used internally
  * by other parts of the framework.
  *
  */
 Ext.define('Ext.data.Tree', {
     alias: 'data.tree',
-    
+
     mixins: {
         observable: "Ext.util.Observable"
     },
 
     /**
+     * @property {Ext.data.NodeInterface}
      * The root node for this tree
-     * @type Node
      */
     root: null,
 
     /**
      * Creates new Tree object.
-     * @param {Node} root (optional) The root node
+     * @param {Ext.data.NodeInterface} root (optional) The root node
      */
     constructor: function(root) {
         var me = this;
+
         
-        me.nodeHash = {};
 
         me.mixins.observable.constructor.call(me);
-                        
+
         if (root) {
             me.setRootNode(root);
         }
@@ -55717,119 +58365,84 @@ Ext.define('Ext.data.Tree', {
      */
     setRootNode : function(node) {
         var me = this;
-        
+
         me.root = node;
         Ext.data.NodeInterface.decorate(node);
-        
+
         if (me.fireEvent('beforeappend', null, node) !== false) {
             node.set('root', true);
             node.updateInfo();
-            
+
             me.relayEvents(node, [
                 /**
                  * @event append
-                 * Fires when a new child node is appended to a node in this tree.
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} parent The parent node
-                 * @param {Node} node The newly appended node
-                 * @param {Number} index The index of the newly appended node
+                 * @alias Ext.data.NodeInterface#append
                  */
                 "append",
 
                 /**
                  * @event remove
-                 * Fires when a child node is removed from a node in this tree.
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} parent The parent node
-                 * @param {Node} node The child node removed
+                 * @alias Ext.data.NodeInterface#remove
                  */
                 "remove",
 
                 /**
                  * @event move
-                 * Fires when a node is moved to a new location in the tree
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} node The node moved
-                 * @param {Node} oldParent The old parent of this node
-                 * @param {Node} newParent The new parent of this node
-                 * @param {Number} index The index it was moved to
+                 * @alias Ext.data.NodeInterface#move
                  */
                 "move",
 
                 /**
                  * @event insert
-                 * Fires when a new child node is inserted in a node in this tree.
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} parent The parent node
-                 * @param {Node} node The child node inserted
-                 * @param {Node} refNode The child node the node was inserted before
+                 * @alias Ext.data.NodeInterface#insert
                  */
                 "insert",
 
                 /**
                  * @event beforeappend
-                 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} parent The parent node
-                 * @param {Node} node The child node to be appended
+                 * @alias Ext.data.NodeInterface#beforeappend
                  */
                 "beforeappend",
 
                 /**
                  * @event beforeremove
-                 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} parent The parent node
-                 * @param {Node} node The child node to be removed
+                 * @alias Ext.data.NodeInterface#beforeremove
                  */
                 "beforeremove",
 
                 /**
                  * @event beforemove
-                 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} node The node being moved
-                 * @param {Node} oldParent The parent of the node
-                 * @param {Node} newParent The new parent the node is moving to
-                 * @param {Number} index The index it is being moved to
+                 * @alias Ext.data.NodeInterface#beforemove
                  */
                 "beforemove",
 
                 /**
                  * @event beforeinsert
-                 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
-                 * @param {Tree} tree The owner tree
-                 * @param {Node} parent The parent node
-                 * @param {Node} node The child node to be inserted
-                 * @param {Node} refNode The child node the node is being inserted before
+                 * @alias Ext.data.NodeInterface#beforeinsert
                  */
                 "beforeinsert",
 
                  /**
                   * @event expand
-                  * Fires when this node is expanded.
-                  * @param {Node} this The expanding node
+                  * @alias Ext.data.NodeInterface#expand
                   */
                  "expand",
 
                  /**
                   * @event collapse
-                  * Fires when this node is collapsed.
-                  * @param {Node} this The collapsing node
+                  * @alias Ext.data.NodeInterface#collapse
                   */
                  "collapse",
 
                  /**
                   * @event beforeexpand
-                  * Fires before this node is expanded.
-                  * @param {Node} this The expanding node
+                  * @alias Ext.data.NodeInterface#beforeexpand
                   */
                  "beforeexpand",
 
                  /**
                   * @event beforecollapse
-                  * Fires before this node is collapsed.
-                  * @param {Node} this The collapsing node
+                  * @alias Ext.data.NodeInterface#beforecollapse
                   */
                  "beforecollapse" ,
 
@@ -55840,7 +58453,7 @@ Ext.define('Ext.data.Tree', {
                   */
                  "rootchange"
             ]);
-            
+
             node.on({
                 scope: me,
                 insert: me.onNodeInsert,
@@ -55848,24 +58461,25 @@ Ext.define('Ext.data.Tree', {
                 remove: me.onNodeRemove
             });
 
-            me.registerNode(node);        
+            me.nodeHash = {};
+            me.registerNode(node);
             me.fireEvent('append', null, node);
             me.fireEvent('rootchange', node);
         }
-            
+
         return node;
     },
-    
+
     /**
      * Flattens all the nodes in the tree into an array.
      * @private
-     * @return {Array} The flattened nodes.
+     * @return {Ext.data.NodeInterface[]} The flattened nodes.
      */
     flatten: function(){
         var nodes = [],
             hash = this.nodeHash,
             key;
-            
+
         for (key in hash) {
             if (hash.hasOwnProperty(key)) {
                 nodes.push(hash[key]);
@@ -55873,7 +58487,7 @@ Ext.define('Ext.data.Tree', {
         }
         return nodes;
     },
-    
+
     /**
      * Fired when a node is inserted into the root or one of it's children
      * @private
@@ -55881,9 +58495,9 @@ Ext.define('Ext.data.Tree', {
      * @param {Ext.data.NodeInterface} node The inserted node
      */
     onNodeInsert: function(parent, node) {
-        this.registerNode(node);
+        this.registerNode(node, true);
     },
-    
+
     /**
      * Fired when a node is appended into the root or one of it's children
      * @private
@@ -55891,9 +58505,9 @@ Ext.define('Ext.data.Tree', {
      * @param {Ext.data.NodeInterface} node The appended node
      */
     onNodeAppend: function(parent, node) {
-        this.registerNode(node);
+        this.registerNode(node, true);
     },
-    
+
     /**
      * Fired when a node is removed from the root or one of it's children
      * @private
@@ -55901,7 +58515,7 @@ Ext.define('Ext.data.Tree', {
      * @param {Ext.data.NodeInterface} node The removed node
      */
     onNodeRemove: function(parent, node) {
-        this.unregisterNode(node);
+        this.unregisterNode(node, true);
     },
 
     /**
@@ -55917,20 +58531,32 @@ Ext.define('Ext.data.Tree', {
      * Registers a node with the tree
      * @private
      * @param {Ext.data.NodeInterface} The node to register
+     * @param {Boolean} [includeChildren] True to unregister any child nodes
      */
-    registerNode : function(node) {
+    registerNode : function(node, includeChildren) {
         this.nodeHash[node.getId() || node.internalId] = node;
+        if (includeChildren === true) {
+            node.eachChild(function(child){
+                this.registerNode(child, true);
+            }, this);
+        }
     },
 
     /**
      * Unregisters a node with the tree
      * @private
      * @param {Ext.data.NodeInterface} The node to unregister
+     * @param {Boolean} [includeChildren] True to unregister any child nodes
      */
-    unregisterNode : function(node) {
+    unregisterNode : function(node, includeChildren) {
         delete this.nodeHash[node.getId() || node.internalId];
+        if (includeChildren === true) {
+            node.eachChild(function(child){
+                this.unregisterNode(child, true);
+            }, this);
+        }
     },
-    
+
     /**
      * Sorts this tree
      * @private
@@ -55940,7 +58566,7 @@ Ext.define('Ext.data.Tree', {
     sort: function(sorterFn, recursive) {
         this.getRootNode().sort(sorterFn, recursive);
     },
-    
+
      /**
      * Filters this tree
      * @private
@@ -55957,14 +58583,15 @@ Ext.define('Ext.data.Tree', {
  * the hierarchical tree structure combined with a store. This class is generally used
  * in conjunction with {@link Ext.tree.Panel}. This class also relays many events from
  * the Tree for convenience.
- * 
+ *
  * # Using Models
- * 
+ *
  * If no Model is specified, an implicit model will be created that implements {@link Ext.data.NodeInterface}.
- * The standard Tree fields will also be copied onto the Model for maintaining their state.
- * 
+ * The standard Tree fields will also be copied onto the Model for maintaining their state. These fields are listed
+ * in the {@link Ext.data.NodeInterface} documentation.
+ *
  * # Reading Nested Data
- * 
+ *
  * For the tree to read nested data, the {@link Ext.data.reader.Reader} must be configured with a root property,
  * so the reader can find nested data for each node. If a root is not specified, it will default to
  * 'children'.
@@ -55977,9 +58604,9 @@ Ext.define('Ext.data.TreeStore', {
     /**
      * @cfg {Ext.data.Model/Ext.data.NodeInterface/Object} root
      * The root node for this store. For example:
-     * 
+     *
      *     root: {
-     *         expanded: true, 
+     *         expanded: true,
      *         text: "My Root",
      *         children: [
      *             { text: "Child 1", leaf: true },
@@ -55988,7 +58615,7 @@ Ext.define('Ext.data.TreeStore', {
      *             ] }
      *         ]
      *     }
-     * 
+     *
      * Setting the `root` config option is the same as calling {@link #setRootNode}.
      */
 
@@ -56010,7 +58637,7 @@ Ext.define('Ext.data.TreeStore', {
      * The default root id. Defaults to 'root'
      */
     defaultRootId: 'root',
-    
+
     /**
      * @cfg {String} defaultRootProperty
      * The root property to specify on the reader if one is not explicitly defined.
@@ -56022,14 +58649,14 @@ Ext.define('Ext.data.TreeStore', {
      * Set to true to automatically prepend a leaf sorter. Defaults to `undefined`.
      */
     folderSort: false,
-    
+
     constructor: function(config) {
-        var me = this, 
+        var me = this,
             root,
             fields;
-        
+
         config = Ext.apply({}, config);
-        
+
         /**
          * If we have no fields declare for the store, add some defaults.
          * These will be ignored if a model is explicitly specified.
@@ -56040,129 +58667,86 @@ Ext.define('Ext.data.TreeStore', {
         }
 
         me.callParent([config]);
-        
+
         // We create our data tree.
         me.tree = Ext.create('Ext.data.Tree');
 
         me.relayEvents(me.tree, [
             /**
              * @event append
-             * Fires when a new child node is appended to a node in this store's tree.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The newly appended node
-             * @param {Number} index The index of the newly appended node
+             * @alias Ext.data.Tree#append
              */
             "append",
-            
+
             /**
              * @event remove
-             * Fires when a child node is removed from a node in this store's tree.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node removed
+             * @alias Ext.data.Tree#remove
              */
             "remove",
-            
+
             /**
              * @event move
-             * Fires when a node is moved to a new location in the store's tree
-             * @param {Tree} tree The owner tree
-             * @param {Node} node The node moved
-             * @param {Node} oldParent The old parent of this node
-             * @param {Node} newParent The new parent of this node
-             * @param {Number} index The index it was moved to
+             * @alias Ext.data.Tree#move
              */
             "move",
-            
+
             /**
              * @event insert
-             * Fires when a new child node is inserted in a node in this store's tree.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node inserted
-             * @param {Node} refNode The child node the node was inserted before
+             * @alias Ext.data.Tree#insert
              */
             "insert",
-            
+
             /**
              * @event beforeappend
-             * Fires before a new child is appended to a node in this store's tree, return false to cancel the append.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node to be appended
+             * @alias Ext.data.Tree#beforeappend
              */
             "beforeappend",
-            
+
             /**
              * @event beforeremove
-             * Fires before a child is removed from a node in this store's tree, return false to cancel the remove.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node to be removed
+             * @alias Ext.data.Tree#beforeremove
              */
             "beforeremove",
-            
+
             /**
              * @event beforemove
-             * Fires before a node is moved to a new location in the store's tree. Return false to cancel the move.
-             * @param {Tree} tree The owner tree
-             * @param {Node} node The node being moved
-             * @param {Node} oldParent The parent of the node
-             * @param {Node} newParent The new parent the node is moving to
-             * @param {Number} index The index it is being moved to
+             * @alias Ext.data.Tree#beforemove
              */
             "beforemove",
-            
+
             /**
              * @event beforeinsert
-             * Fires before a new child is inserted in a node in this store's tree, return false to cancel the insert.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node to be inserted
-             * @param {Node} refNode The child node the node is being inserted before
+             * @alias Ext.data.Tree#beforeinsert
              */
             "beforeinsert",
-             
+
              /**
               * @event expand
-              * Fires when this node is expanded.
-              * @param {Node} this The expanding node
+              * @alias Ext.data.Tree#expand
               */
              "expand",
-             
+
              /**
               * @event collapse
-              * Fires when this node is collapsed.
-              * @param {Node} this The collapsing node
+              * @alias Ext.data.Tree#collapse
               */
              "collapse",
-             
+
              /**
               * @event beforeexpand
-              * Fires before this node is expanded.
-              * @param {Node} this The expanding node
+              * @alias Ext.data.Tree#beforeexpand
               */
              "beforeexpand",
-             
+
              /**
               * @event beforecollapse
-              * Fires before this node is collapsed.
-              * @param {Node} this The collapsing node
+              * @alias Ext.data.Tree#beforecollapse
               */
              "beforecollapse",
 
-             /**
-              * @event sort
-              * Fires when this TreeStore is sorted.
-              * @param {Node} node The node that is sorted.
-              */             
-             "sort",
-             
              /**
               * @event rootchange
-              * Fires whenever the root node is changed in the tree.
-              * @param {Ext.data.Model} root The new root
+              * @alias Ext.data.Tree#rootchange
               */
              "rootchange"
         ]);
@@ -56185,17 +58769,16 @@ Ext.define('Ext.data.TreeStore', {
             delete me.root;
             me.setRootNode(root);
         }
-        
+
         me.addEvents(
             /**
-             * @event rootchange
-             * Fires when the root node on this TreeStore is changed.
-             * @param {Ext.data.TreeStore} store This TreeStore
-             * @param {Node} The new root node.
+             * @event sort
+             * Fires when this TreeStore is sorted.
+             * @param {Ext.data.NodeInterface} node The node that is sorted.
              */
-            'rootchange'
+            'sort'
         );
-        
+
         //<deprecated since=0.99>
         if (Ext.isDefined(me.nodeParameter)) {
             if (Ext.isDefined(Ext.global.console)) {
@@ -56206,12 +58789,12 @@ Ext.define('Ext.data.TreeStore', {
         }
         //</deprecated>
     },
-    
+
     // inherit docs
     setProxy: function(proxy) {
         var reader,
             needsRoot;
-        
+
         if (proxy instanceof Ext.data.proxy.Proxy) {
             // proxy instance, check if a root was set
             needsRoot = Ext.isEmpty(proxy.getReader().root);
@@ -56231,17 +58814,17 @@ Ext.define('Ext.data.TreeStore', {
             reader.buildExtractors(true);
         }
     },
-    
+
     // inherit docs
     onBeforeSort: function() {
         if (this.folderSort) {
             this.sort({
                 property: 'leaf',
                 direction: 'ASC'
-            }, 'prepend', false);    
+            }, 'prepend', false);
         }
     },
-    
+
     /**
      * Called before a node is expanded.
      * @private
@@ -56264,10 +58847,10 @@ Ext.define('Ext.data.TreeStore', {
                 callback: function() {
                     Ext.callback(callback, scope || node, [node.childNodes]);
                 }
-            });            
+            });
         }
     },
-    
+
     //inherit docs
     getNewRecords: function() {
         return Ext.Array.filter(this.tree.flatten(), this.filterNew);
@@ -56277,7 +58860,7 @@ Ext.define('Ext.data.TreeStore', {
     getUpdatedRecords: function() {
         return Ext.Array.filter(this.tree.flatten(), this.filterUpdated);
     },
-    
+
     /**
      * Called before a node is collapsed.
      * @private
@@ -56288,23 +58871,23 @@ Ext.define('Ext.data.TreeStore', {
     onBeforeNodeCollapse: function(node, callback, scope) {
         callback.call(scope || node, node.childNodes);
     },
-    
+
     onNodeRemove: function(parent, node) {
         var removed = this.removed;
-        
+
         if (!node.isReplace && Ext.Array.indexOf(removed, node) == -1) {
             removed.push(node);
         }
     },
-    
+
     onNodeAdded: function(parent, node) {
         var proxy = this.getProxy(),
             reader = proxy.getReader(),
             data = node.raw || node.data,
             dataRoot, children;
-            
-        Ext.Array.remove(this.removed, node); 
-        
+
+        Ext.Array.remove(this.removed, node);
+
         if (!node.isLeaf() && !node.isLoaded()) {
             dataRoot = reader.getRoot(data);
             if (dataRoot) {
@@ -56313,7 +58896,7 @@ Ext.define('Ext.data.TreeStore', {
             }
         }
     },
-        
+
     /**
      * Sets the root node for this store.  See also the {@link #root} config option.
      * @param {Ext.data.Model/Ext.data.NodeInterface/Object} root
@@ -56322,9 +58905,9 @@ Ext.define('Ext.data.TreeStore', {
     setRootNode: function(root) {
         var me = this;
 
-        root = root || {};        
+        root = root || {};
         if (!root.isNode) {
-            // create a default rootNode and create internal data struct.        
+            // create a default rootNode and create internal data struct.
             Ext.applyIf(root, {
                 id: me.defaultRootId,
                 text: 'Root',
@@ -56337,20 +58920,20 @@ Ext.define('Ext.data.TreeStore', {
         // Because we have decorated the model with new fields,
         // we need to build new extactor functions on the reader.
         me.getProxy().getReader().buildExtractors(true);
-        
+
         // When we add the root to the tree, it will automaticaly get the NodeInterface
         me.tree.setRootNode(root);
-        
+
         // If the user has set expanded: true on the root, we want to call the expand function
-        if (!root.isLoaded() && root.isExpanded()) {
+        if (!root.isLoaded() && (me.autoLoad === true || root.isExpanded())) {
             me.load({
                 node: root
             });
         }
-        
+
         return root;
     },
-        
+
     /**
      * Returns the root node for this tree.
      * @return {Ext.data.NodeInterface}
@@ -56369,7 +58952,7 @@ Ext.define('Ext.data.TreeStore', {
 
     /**
      * Loads the Store using its configured {@link #proxy}.
-     * @param {Object} options Optional config object. This is passed into the {@link Ext.data.Operation Operation}
+     * @param {Object} options (Optional) config object. This is passed into the {@link Ext.data.Operation Operation}
      * object that is created and then sent to the proxy's {@link Ext.data.proxy.Proxy#read} function.
      * The options can also contain a node, which indicates which node is to be loaded. If not specified, it will
      * default to the root node.
@@ -56377,11 +58960,11 @@ Ext.define('Ext.data.TreeStore', {
     load: function(options) {
         options = options || {};
         options.params = options.params || {};
-        
+
         var me = this,
             node = options.node || me.tree.getRootNode(),
             root;
-            
+
         // If there is not a node it means the user hasnt defined a rootnode yet. In this case lets just
         // create one for them.
         if (!node) {
@@ -56389,29 +58972,29 @@ Ext.define('Ext.data.TreeStore', {
                 expanded: true
             });
         }
-        
+
         if (me.clearOnLoad) {
-            node.removeAll();
+            node.removeAll(true);
         }
-        
+
         Ext.applyIf(options, {
             node: node
         });
         options.params[me.nodeParam] = node ? node.getId() : 'root';
-        
+
         if (node) {
             node.set('loading', true);
         }
-        
+
         return me.callParent([options]);
     },
-        
+
 
     /**
      * Fills a node with a series of child records.
      * @private
      * @param {Ext.data.NodeInterface} node The node to fill
-     * @param {Array} records The records to add
+     * @param {Ext.data.Model[]} records The records to add
      */
     fillNode: function(node, records) {
         var me = this,
@@ -56424,12 +59007,12 @@ Ext.define('Ext.data.TreeStore', {
             sortCollection.sort(me.sorters.items);
             records = sortCollection.items;
         }
-        
+
         node.set('loaded', true);
         for (; i < ln; i++) {
             node.appendChild(records[i], undefined, true);
         }
-        
+
         return records;
     },
 
@@ -56440,21 +59023,32 @@ Ext.define('Ext.data.TreeStore', {
             records = operation.getRecords(),
             node = operation.node;
 
+        me.loading = false;
         node.set('loading', false);
         if (successful) {
             records = me.fillNode(node, records);
         }
+        // The load event has an extra node parameter
+        // (differing from the load event described in AbstractStore)
+        /**
+         * @event load
+         * Fires whenever the store reads data from a remote data source.
+         * @param {Ext.data.TreeStore} this
+         * @param {Ext.data.NodeInterface} node The node that was loaded.
+         * @param {Ext.data.Model[]} records An array of records.
+         * @param {Boolean} successful True if the operation was successful.
+         */
         // deprecate read?
         me.fireEvent('read', me, operation.node, records, successful);
         me.fireEvent('load', me, operation.node, records, successful);
         //this is a callback that would have been passed to the 'read' function and is optional
         Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
     },
-    
+
     /**
      * Creates any new records when a write is returned from the server.
      * @private
-     * @param {Array} records The array of new records
+     * @param {Ext.data.Model[]} records The array of new records
      * @param {Ext.data.Operation} operation The operation that just completed
      * @param {Boolean} success True if the operation was successful
      */
@@ -56493,7 +59087,7 @@ Ext.define('Ext.data.TreeStore', {
     /**
      * Updates any records when a write is returned from the server.
      * @private
-     * @param {Array} records The array of updated records
+     * @param {Ext.data.Model[]} records The array of updated records
      * @param {Ext.data.Operation} operation The operation that just completed
      * @param {Boolean} success True if the operation was successful
      */
@@ -56524,7 +59118,7 @@ Ext.define('Ext.data.TreeStore', {
     /**
      * Removes any records when a write is returned from the server.
      * @private
-     * @param {Array} records The array of removed records
+     * @param {Ext.data.Model[]} records The array of removed records
      * @param {Ext.data.Operation} operation The operation that just completed
      * @param {Boolean} success True if the operation was successful
      */
@@ -56549,10 +59143,227 @@ Ext.define('Ext.data.TreeStore', {
         } else {
             me.tree.sort(sorterFn, true);
             me.fireEvent('datachanged', me);
-        }   
+        }
         me.fireEvent('sort', me);
     }
 });
+
+/**
+ * @extend Ext.data.IdGenerator
+ * @author Don Griffin
+ *
+ * This class generates UUID's according to RFC 4122. This class has a default id property.
+ * This means that a single instance is shared unless the id property is overridden. Thus,
+ * two {@link Ext.data.Model} instances configured like the following share one generator:
+ *
+ *     Ext.define('MyApp.data.MyModelX', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'uuid'
+ *     });
+ *
+ *     Ext.define('MyApp.data.MyModelY', {
+ *         extend: 'Ext.data.Model',
+ *         idgen: 'uuid'
+ *     });
+ *
+ * This allows all models using this class to share a commonly configured instance.
+ *
+ * # Using Version 1 ("Sequential") UUID's
+ *
+ * If a server can provide a proper timestamp and a "cryptographic quality random number"
+ * (as described in RFC 4122), the shared instance can be configured as follows:
+ *
+ *     Ext.data.IdGenerator.get('uuid').reconfigure({
+ *         version: 1,
+ *         clockSeq: clock, // 14 random bits
+ *         salt: salt,      // 48 secure random bits (the Node field)
+ *         timestamp: ts    // timestamp per Section 4.1.4
+ *     });
+ *
+ *     // or these values can be split into 32-bit chunks:
+ *
+ *     Ext.data.IdGenerator.get('uuid').reconfigure({
+ *         version: 1,
+ *         clockSeq: clock,
+ *         salt: { lo: saltLow32, hi: saltHigh32 },
+ *         timestamp: { lo: timestampLow32, hi: timestamptHigh32 }
+ *     });
+ *
+ * This approach improves the generator's uniqueness by providing a valid timestamp and
+ * higher quality random data. Version 1 UUID's should not be used unless this information
+ * can be provided by a server and care should be taken to avoid caching of this data.
+ *
+ * See http://www.ietf.org/rfc/rfc4122.txt for details.
+ */
+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); // right-most digits
+        } 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', // shared by default
+
+        /**
+         * @property {Number/Object} salt
+         * When created, this value is a 48-bit number. For computation, this value is split
+         * into 32-bit parts and stored in an object with `hi` and `lo` properties.
+         */
+
+        /**
+         * @property {Number/Object} timestamp
+         * When created, this value is a 60-bit number. For computation, this value is split
+         * into 32-bit parts and stored in an object with `hi` and `lo` properties.
+         */
+
+        /**
+         * @cfg {Number} version
+         * The Version of UUID. Supported values are:
+         *
+         *  * 1 : Time-based, "sequential" UUID.
+         *  * 4 : Pseudo-random UUID.
+         *
+         * The default is 4.
+         */
+        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;
+
+            /*
+               The magic decoder ring (derived from RFC 4122 Section 4.2.2):
+
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+               |                          time_low                             |
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+               |           time_mid            |  ver  |        time_hi        |
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+               |res|  clock_hi |   clock_low   |    salt 0   |M|     salt 1    |
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+               |                         salt (2-5)                            |
+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+                         time_mid      clock_hi (low 6 bits)
+                time_low     | time_hi |clock_lo
+                    |        |     |   || salt[0]
+                    |        |     |   ||   | salt[1..5]
+                    v        v     v   vv   v v
+                    0badf00d-aced-1def-b123-dfad0badbeef
+                                  ^    ^     ^
+                            version    |     multicast (low bit)
+                                       |
+                                    reserved (upper 2 bits)
+            */
+            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(); // just regenerate all the random values...
+            } else {
+                // sequentially increment the timestamp...
+                ++ts.lo;
+                if (ts.lo >= twoPow32) { // if (overflow)
+                    ts.lo = 0;
+                    ++ts.hi;
+                }
+            }
+
+            return parts.join('-').toLowerCase();
+        },
+
+        getRecId: function (rec) {
+            return rec.getId();
+        },
+
+        /**
+         * @private
+         */
+        init: function () {
+            var me = this,
+                salt, time;
+
+            if (me.version == 4) {
+                // See RFC 4122 (Secion 4.4)
+                //   o  If the state was unavailable (e.g., non-existent or corrupted),
+                //      or the saved node ID is different than the current node ID,
+                //      generate a random clock sequence value.
+                me.clockSeq = rand(0, twoPow14-1);
+
+                // we run this on every id generation...
+                salt = me.salt || (me.salt = {});
+                time = me.timestamp || (me.timestamp = {});
+
+                // See RFC 4122 (Secion 4.4)
+                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 {
+                // this is run only once per-instance
+                me.salt = split(me.salt);
+                me.timestamp = split(me.timestamp);
+
+                // Set multicast bit: "the least significant bit of the first octet of the
+                // node ID" (nodeId = salt for this implementation):
+                me.salt.hi |= 0x100;
+            }
+        },
+
+        /**
+         * Reconfigures this generator given new config properties.
+         */
+        reconfigure: function (config) {
+            Ext.apply(this, config);
+            this.init();
+        }
+    };
+}());
+
 /**
  * @author Ed Spencer
  * @class Ext.data.XmlStore
@@ -56608,7 +59419,7 @@ var store = new Ext.data.XmlStore({
 &#60/ItemSearchResponse>
  * </code></pre>
  * An object literal of this form could also be used as the {@link #data} config option.</p>
- * <p><b>Note:</b> Although not listed here, this class accepts all of the configuration options of
+ * <p><b>Note:</b> This class accepts all of the configuration options of
  * <b>{@link Ext.data.reader.Xml XmlReader}</b>.</p>
  * @xtype xmlstore
  */
@@ -56638,16 +59449,15 @@ Ext.define('Ext.data.XmlStore', {
 
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.Client
- * @extends Ext.data.proxy.Proxy
- * 
- * <p>Base class for any client-side storage. Used as a superclass for {@link Ext.data.proxy.Memory Memory} and 
- * {@link Ext.data.proxy.WebStorage Web Storage} proxies. Do not use directly, use one of the subclasses instead.</p>
+ *
+ * Base class for any client-side storage. Used as a superclass for {@link Ext.data.proxy.Memory Memory} and
+ * {@link Ext.data.proxy.WebStorage Web Storage} proxies. Do not use directly, use one of the subclasses instead.
+ * @private
  */
 Ext.define('Ext.data.proxy.Client', {
     extend: 'Ext.data.proxy.Proxy',
     alternateClassName: 'Ext.data.ClientProxy',
-    
+
     /**
      * Abstract function that must be implemented by each ClientProxy subclass. This should purge all record data
      * from the client side storage, as well as removing any supporting data (such as lists of record IDs)
@@ -56660,154 +59470,130 @@ Ext.define('Ext.data.proxy.Client', {
 });
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.JsonP
- * @extends Ext.data.proxy.Server
  *
- * <p>JsonPProxy is useful when you need to load data from a domain other than the one your application is running
- * on. If your application is running on http://domainA.com it cannot use {@link Ext.data.proxy.Ajax Ajax} to load its
- * data from http://domainB.com because cross-domain ajax requests are prohibited by the browser.</p>
+ * The JsonP proxy is useful when you need to load data from a domain other than the one your application is running on. If
+ * your application is running on http://domainA.com it cannot use {@link Ext.data.proxy.Ajax Ajax} to load its data
+ * from http://domainB.com because cross-domain ajax requests are prohibited by the browser.
  *
- * <p>We can get around this using a JsonPProxy. JsonPProxy injects a &lt;script&gt; tag into the DOM whenever
- * an AJAX request would usually be made. Let's say we want to load data from http://domainB.com/users - the script tag
- * that would be injected might look like this:</p>
+ * We can get around this using a JsonP proxy. JsonP proxy injects a `<script>` tag into the DOM whenever an AJAX request
+ * would usually be made. Let's say we want to load data from http://domainB.com/users - the script tag that would be
+ * injected might look like this:
  *
-<pre><code>
-&lt;script src="http://domainB.com/users?callback=someCallback"&gt;&lt;/script&gt;
-</code></pre>
+ *     <script src="http://domainB.com/users?callback=someCallback"></script>
  *
- * <p>When we inject the tag above, the browser makes a request to that url and includes the response as if it was any
- * other type of JavaScript include. By passing a callback in the url above, we're telling domainB's server that we
- * want to be notified when the result comes in and that it should call our callback function with the data it sends
- * back. So long as the server formats the response to look like this, everything will work:</p>
+ * When we inject the tag above, the browser makes a request to that url and includes the response as if it was any
+ * other type of JavaScript include. By passing a callback in the url above, we're telling domainB's server that we want
+ * to be notified when the result comes in and that it should call our callback function with the data it sends back. So
+ * long as the server formats the response to look like this, everything will work:
  *
-<pre><code>
-someCallback({
-    users: [
-        {
-            id: 1,
-            name: "Ed Spencer",
-            email: "ed@sencha.com"
-        }
-    ]
-});
-</code></pre>
+ *     someCallback({
+ *         users: [
+ *             {
+ *                 id: 1,
+ *                 name: "Ed Spencer",
+ *                 email: "ed@sencha.com"
+ *             }
+ *         ]
+ *     });
  *
- * <p>As soon as the script finishes loading, the 'someCallback' function that we passed in the url is called with the
- * JSON object that the server returned.</p>
+ * As soon as the script finishes loading, the 'someCallback' function that we passed in the url is called with the JSON
+ * object that the server returned.
  *
- * <p>JsonPProxy takes care of all of this automatically. It formats the url you pass, adding the callback
- * parameter automatically. It even creates a temporary callback function, waits for it to be called and then puts
- * the data into the Proxy making it look just like you loaded it through a normal {@link Ext.data.proxy.Ajax AjaxProxy}.
- * Here's how we might set that up:</p>
+ * JsonP proxy takes care of all of this automatically. It formats the url you pass, adding the callback parameter
+ * automatically. It even creates a temporary callback function, waits for it to be called and then puts the data into
+ * the Proxy making it look just like you loaded it through a normal {@link Ext.data.proxy.Ajax AjaxProxy}. Here's how
+ * we might set that up:
  *
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'name', 'email']
-});
-
-var store = new Ext.data.Store({
-    model: 'User',
-    proxy: {
-        type: 'jsonp',
-        url : 'http://domainB.com/users'
-    }
-});
-
-store.load();
-</code></pre>
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'name', 'email']
+ *     });
  *
- * <p>That's all we need to do - JsonPProxy takes care of the rest. In this case the Proxy will have injected a
- * script tag like this:
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: 'User',
+ *         proxy: {
+ *             type: 'jsonp',
+ *             url : 'http://domainB.com/users'
+ *         }
+ *     });
  *
-<pre><code>
-&lt;script src="http://domainB.com/users?callback=stcCallback001" id="stcScript001"&gt;&lt;/script&gt;
-</code></pre>
+ *     store.load();
  *
- * <p><u>Customization</u></p>
+ * That's all we need to do - JsonP proxy takes care of the rest. In this case the Proxy will have injected a script tag
+ * like this:
  *
- * <p>Most parts of this script tag can be customized using the {@link #callbackParam}, {@link #callbackPrefix} and
- * {@link #scriptIdPrefix} configurations. For example:
+ *     <script src="http://domainB.com/users?callback=callback1"></script>
  *
-<pre><code>
-var store = new Ext.data.Store({
-    model: 'User',
-    proxy: {
-        type: 'jsonp',
-        url : 'http://domainB.com/users',
-        callbackParam: 'theCallbackFunction',
-        callbackPrefix: 'ABC',
-        scriptIdPrefix: 'injectedScript'
-    }
-});
-
-store.load();
-</code></pre>
+ * # Customization
  *
- * <p>Would inject a script tag like this:</p>
+ * This script tag can be customized using the {@link #callbackKey} configuration. For example:
  *
-<pre><code>
-&lt;script src="http://domainB.com/users?theCallbackFunction=ABC001" id="injectedScript001"&gt;&lt;/script&gt;
-</code></pre>
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: 'User',
+ *         proxy: {
+ *             type: 'jsonp',
+ *             url : 'http://domainB.com/users',
+ *             callbackKey: 'theCallbackFunction'
+ *         }
+ *     });
  *
- * <p><u>Implementing on the server side</u></p>
+ *     store.load();
  *
- * <p>The remote server side needs to be configured to return data in this format. Here are suggestions for how you
- * might achieve this using Java, PHP and ASP.net:</p>
+ * Would inject a script tag like this:
  *
- * <p>Java:</p>
+ *     <script src="http://domainB.com/users?theCallbackFunction=callback1"></script>
  *
-<pre><code>
-boolean jsonP = false;
-String cb = request.getParameter("callback");
-if (cb != null) {
-    jsonP = true;
-    response.setContentType("text/javascript");
-} else {
-    response.setContentType("application/x-json");
-}
-Writer out = response.getWriter();
-if (jsonP) {
-    out.write(cb + "(");
-}
-out.print(dataBlock.toJsonString());
-if (jsonP) {
-    out.write(");");
-}
-</code></pre>
+ * # Implementing on the server side
  *
- * <p>PHP:</p>
+ * The remote server side needs to be configured to return data in this format. Here are suggestions for how you might
+ * achieve this using Java, PHP and ASP.net:
  *
-<pre><code>
-$callback = $_REQUEST['callback'];
-
-// Create the output object.
-$output = array('a' => 'Apple', 'b' => 'Banana');
-
-//start output
-if ($callback) {
-    header('Content-Type: text/javascript');
-    echo $callback . '(' . json_encode($output) . ');';
-} else {
-    header('Content-Type: application/x-json');
-    echo json_encode($output);
-}
-</code></pre>
+ * Java:
  *
- * <p>ASP.net:</p>
+ *     boolean jsonP = false;
+ *     String cb = request.getParameter("callback");
+ *     if (cb != null) {
+ *         jsonP = true;
+ *         response.setContentType("text/javascript");
+ *     } else {
+ *         response.setContentType("application/x-json");
+ *     }
+ *     Writer out = response.getWriter();
+ *     if (jsonP) {
+ *         out.write(cb + "(");
+ *     }
+ *     out.print(dataBlock.toJsonString());
+ *     if (jsonP) {
+ *         out.write(");");
+ *     }
  *
-<pre><code>
-String jsonString = "{success: true}";
-String cb = Request.Params.Get("callback");
-String responseString = "";
-if (!String.IsNullOrEmpty(cb)) {
-    responseString = cb + "(" + jsonString + ")";
-} else {
-    responseString = jsonString;
-}
-Response.Write(responseString);
-</code></pre>
+ * PHP:
  *
+ *     $callback = $_REQUEST['callback'];
+ *
+ *     // Create the output object.
+ *     $output = array('a' => 'Apple', 'b' => 'Banana');
+ *
+ *     //start output
+ *     if ($callback) {
+ *         header('Content-Type: text/javascript');
+ *         echo $callback . '(' . json_encode($output) . ');';
+ *     } else {
+ *         header('Content-Type: application/x-json');
+ *         echo json_encode($output);
+ *     }
+ *
+ * ASP.net:
+ *
+ *     String jsonString = "{success: true}";
+ *     String cb = Request.Params.Get("callback");
+ *     String responseString = "";
+ *     if (!String.IsNullOrEmpty(cb)) {
+ *         responseString = cb + "(" + jsonString + ")";
+ *     } else {
+ *         responseString = jsonString;
+ *     }
+ *     Response.Write(responseString);
  */
 Ext.define('Ext.data.proxy.JsonP', {
     extend: 'Ext.data.proxy.Server',
@@ -56818,26 +59604,28 @@ Ext.define('Ext.data.proxy.JsonP', {
     defaultWriterType: 'base',
 
     /**
-     * @cfg {String} callbackKey (Optional) See {@link Ext.data.JsonP#callbackKey}.
+     * @cfg {String} callbackKey
+     * See {@link Ext.data.JsonP#callbackKey}.
      */
     callbackKey : 'callback',
 
     /**
      * @cfg {String} recordParam
-     * The param name to use when passing records to the server (e.g. 'records=someEncodedRecordString').
-     * Defaults to 'records'
+     * The param name to use when passing records to the server (e.g. 'records=someEncodedRecordString'). Defaults to
+     * 'records'
      */
     recordParam: 'records',
 
     /**
-     * @cfg {Boolean} autoAppendParams True to automatically append the request's params to the generated url. Defaults to true
+     * @cfg {Boolean} autoAppendParams
+     * True to automatically append the request's params to the generated url. Defaults to true
      */
     autoAppendParams: true,
 
     constructor: function(){
         this.addEvents(
             /**
-             * @event exception
+             * @event
              * Fires when the server returns an exception
              * @param {Ext.data.proxy.Proxy} this
              * @param {Ext.data.Request} request The request that was sent
@@ -56850,7 +59638,7 @@ Ext.define('Ext.data.proxy.JsonP', {
 
     /**
      * @private
-     * Performs the read request to the remote domain. JsonPProxy does not actually create an Ajax request,
+     * Performs the read request to the remote domain. JsonP proxy does not actually create an Ajax request,
      * instead we write out a <script> tag based on the configuration of the internal Ext.data.Request object
      * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute
      * @param {Function} callback A callback function to execute when the Operation has been completed
@@ -56867,7 +59655,7 @@ Ext.define('Ext.data.proxy.JsonP', {
             request = writer.write(request);
         }
 
-        //apply JsonPProxy-specific attributes to the Request
+        // apply JsonP proxy-specific attributes to the Request
         Ext.apply(request, {
             callbackKey: me.callbackKey,
             timeout: me.timeout,
@@ -56875,12 +59663,12 @@ Ext.define('Ext.data.proxy.JsonP', {
             disableCaching: false, // handled by the proxy
             callback: me.createRequestCallback(request, operation, callback, scope)
         });
-        
+
         // prevent doubling up
         if (me.autoAppendParams) {
             request.params = {};
         }
-        
+
         request.jsonp = Ext.data.JsonP.request(request);
         // restore on the request
         request.params = params;
@@ -56913,7 +59701,7 @@ Ext.define('Ext.data.proxy.JsonP', {
             me.processResponse(success, operation, request, response, callback, scope);
         };
     },
-    
+
     // inherit docs
     setException: function(operation, response) {
         operation.setException(operation.request.jsonp.errorType);
@@ -56934,7 +59722,7 @@ Ext.define('Ext.data.proxy.JsonP', {
             filter, i;
 
         delete params.filters;
+
         if (me.autoAppendParams) {
             url = Ext.urlAppend(url, Ext.Object.toQueryString(params));
         }
@@ -56976,9 +59764,9 @@ Ext.define('Ext.data.proxy.JsonP', {
     },
 
     /**
-     * Encodes an array of records into a string suitable to be appended to the script src url. This is broken
-     * out into its own function so that it can be easily overridden.
-     * @param {Array} records The records array
+     * Encodes an array of records into a string suitable to be appended to the script src url. This is broken out into
+     * its own function so that it can be easily overridden.
+     * @param {Ext.data.Model[]} records The records array
      * @return {String} The encoded records string
      */
     encodeRecords: function(records) {
@@ -56996,33 +59784,32 @@ Ext.define('Ext.data.proxy.JsonP', {
 
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.WebStorage
- * @extends Ext.data.proxy.Client
- * 
- * <p>WebStorageProxy is simply a superclass for the {@link Ext.data.proxy.LocalStorage localStorage} and 
- * {@link Ext.data.proxy.SessionStorage sessionStorage} proxies. It uses the new HTML5 key/value client-side storage 
- * objects to save {@link Ext.data.Model model instances} for offline use.</p>
+ *
+ * WebStorageProxy is simply a superclass for the {@link Ext.data.proxy.LocalStorage LocalStorage} and {@link
+ * Ext.data.proxy.SessionStorage SessionStorage} proxies. It uses the new HTML5 key/value client-side storage objects to
+ * save {@link Ext.data.Model model instances} for offline use.
+ * @private
  */
 Ext.define('Ext.data.proxy.WebStorage', {
     extend: 'Ext.data.proxy.Client',
     alternateClassName: 'Ext.data.WebStorageProxy',
-    
+
     /**
-     * @cfg {String} id The unique ID used as the key in which all record data are stored in the local storage object
+     * @cfg {String} id
+     * The unique ID used as the key in which all record data are stored in the local storage object.
      */
     id: undefined,
 
     /**
-     * Creates the proxy, throws an error if local storage is not supported in the current browser
+     * Creates the proxy, throws an error if local storage is not supported in the current browser.
      * @param {Object} config (optional) Config object.
      */
     constructor: function(config) {
         this.callParent(arguments);
-        
+
         /**
-         * Cached map of records already retrieved by this Proxy - ensures that the same instance is always retrieved
-         * @property cache
-         * @type Object
+         * @property {Object} cache
+         * Cached map of records already retrieved by this Proxy. Ensures that the same instance is always retrieved.
          */
         this.cache = {};
 
@@ -57050,7 +59837,7 @@ Ext.define('Ext.data.proxy.WebStorage', {
             length  = records.length,
             ids     = this.getIds(),
             id, record, i;
-        
+
         operation.setStarted();
 
         for (i = 0; i < length; i++) {
@@ -57085,11 +59872,11 @@ Ext.define('Ext.data.proxy.WebStorage', {
             ids     = this.getIds(),
             length  = ids.length,
             i, recordData, record;
-        
+
         //read a single record
         if (operation.id) {
             record = this.getRecord(operation.id);
-            
+
             if (record) {
                 records.push(record);
                 operation.setSuccessful();
@@ -57100,7 +59887,7 @@ Ext.define('Ext.data.proxy.WebStorage', {
             }
             operation.setSuccessful();
         }
-        
+
         operation.setCompleted();
 
         operation.resultSet = Ext.create('Ext.data.ResultSet', {
@@ -57126,7 +59913,7 @@ Ext.define('Ext.data.proxy.WebStorage', {
         for (i = 0; i < length; i++) {
             record = records[i];
             this.setRecord(record);
-            
+
             //we need to update the set of ids here because it's possible that a non-phantom record was added
             //to this proxy - in which case the record's id would never have been added via the normal 'create' call
             id = record.getId();
@@ -57160,7 +59947,7 @@ Ext.define('Ext.data.proxy.WebStorage', {
         }
 
         this.setIds(newIds);
-        
+
         operation.setCompleted();
         operation.setSuccessful();
 
@@ -57171,7 +59958,7 @@ Ext.define('Ext.data.proxy.WebStorage', {
 
     /**
      * @private
-     * Fetches a model instance from the Proxy by ID. Runs each field's decode function (if present) to decode the data
+     * Fetches a model instance from the Proxy by ID. Runs each field's decode function (if present) to decode the data.
      * @param {String} id The record's unique ID
      * @return {Ext.data.Model} The model instance
      */
@@ -57200,14 +59987,14 @@ Ext.define('Ext.data.proxy.WebStorage', {
 
             this.cache[id] = record;
         }
-        
+
         return this.cache[id];
     },
 
     /**
-     * Saves the given record in the Proxy. Runs each field's encode function (if present) to encode the data
+     * Saves the given record in the Proxy. Runs each field's encode function (if present) to encode the data.
      * @param {Ext.data.Model} record The model instance
-     * @param {String} id The id to save the record under (defaults to the value of the record's getId() function)
+     * @param {String} [id] The id to save the record under (defaults to the value of the record's getId() function)
      */
     setRecord: function(record, id) {
         if (id) {
@@ -57238,10 +60025,10 @@ Ext.define('Ext.data.proxy.WebStorage', {
 
         obj = me.getStorageObject();
         key = me.getRecordKey(id);
-        
+
         //keep the cache up to date
         me.cache[id] = record;
-        
+
         //iPad bug requires that we remove the item before setting it
         obj.removeItem(key);
         obj.setItem(key, Ext.encode(data));
@@ -57251,12 +60038,12 @@ Ext.define('Ext.data.proxy.WebStorage', {
      * @private
      * Physically removes a given record from the local storage. Used internally by {@link #destroy}, which you should
      * use instead because it updates the list of currently-stored record ids
-     * @param {String|Number|Ext.data.Model} id The id of the record to remove, or an Ext.data.Model instance
+     * @param {String/Number/Ext.data.Model} id The id of the record to remove, or an Ext.data.Model instance
      */
     removeRecord: function(id, updateIds) {
         var me = this,
             ids;
-            
+
         if (id.isModel) {
             id = id.getId();
         }
@@ -57274,7 +60061,7 @@ Ext.define('Ext.data.proxy.WebStorage', {
      * @private
      * Given the id of a record, returns a unique string based on that id and the id of this proxy. This is used when
      * storing data in the local storage object and should prevent naming collisions.
-     * @param {String|Number|Ext.data.Model} id The record id, or a Model instance
+     * @param {String/Number/Ext.data.Model} id The record id, or a Model instance
      * @return {String} The unique key for this record
      */
     getRecordKey: function(id) {
@@ -57298,7 +60085,7 @@ Ext.define('Ext.data.proxy.WebStorage', {
     /**
      * @private
      * Returns the array of record IDs stored in this Proxy
-     * @return {Array} The record IDs. Each is cast as a Number
+     * @return {Number[]} The record IDs. Each is cast as a Number
      */
     getIds: function() {
         var ids    = (this.getStorageObject().getItem(this.id) || "").split(","),
@@ -57319,14 +60106,14 @@ Ext.define('Ext.data.proxy.WebStorage', {
     /**
      * @private
      * Saves the array of ids representing the set of all records in the Proxy
-     * @param {Array} ids The ids to set
+     * @param {Number[]} ids The ids to set
      */
     setIds: function(ids) {
         var obj = this.getStorageObject(),
             str = ids.join(",");
-        
+
         obj.removeItem(this.id);
-        
+
         if (!Ext.isEmpty(str)) {
             obj.setItem(this.id, str);
         }
@@ -57334,8 +60121,8 @@ Ext.define('Ext.data.proxy.WebStorage', {
 
     /**
      * @private
-     * Returns the next numerical ID that can be used when realizing a model instance (see getRecordCounterKey). Increments
-     * the counter.
+     * Returns the next numerical ID that can be used when realizing a model instance (see getRecordCounterKey).
+     * Increments the counter.
      * @return {Number} The id
      */
     getNextId: function() {
@@ -57343,15 +60130,15 @@ Ext.define('Ext.data.proxy.WebStorage', {
             key  = this.getRecordCounterKey(),
             last = obj.getItem(key),
             ids, id;
-        
+
         if (last === null) {
             ids = this.getIds();
             last = ids[ids.length - 1] || 0;
         }
-        
+
         id = parseInt(last, 10) + 1;
         obj.setItem(key, id);
-        
+
         return id;
     },
 
@@ -57366,7 +60153,8 @@ Ext.define('Ext.data.proxy.WebStorage', {
     },
 
     /**
-     * Destroys all records stored in the proxy and removes all keys and values used to support the proxy from the storage object
+     * Destroys all records stored in the proxy and removes all keys and values used to support the proxy from the
+     * storage object.
      */
     clear: function() {
         var obj = this.getStorageObject(),
@@ -57398,71 +60186,62 @@ Ext.define('Ext.data.proxy.WebStorage', {
 });
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.LocalStorage
- * @extends Ext.data.proxy.WebStorage
- * 
- * <p>The LocalStorageProxy uses the new HTML5 localStorage API to save {@link Ext.data.Model Model} data locally on
- * the client browser. HTML5 localStorage is a key-value store (e.g. cannot save complex objects like JSON), so
- * LocalStorageProxy automatically serializes and deserializes data when saving and retrieving it.</p>
- * 
- * <p>localStorage is extremely useful for saving user-specific information without needing to build server-side 
+ *
+ * The LocalStorageProxy uses the new HTML5 localStorage API to save {@link Ext.data.Model Model} data locally on the
+ * client browser. HTML5 localStorage is a key-value store (e.g. cannot save complex objects like JSON), so
+ * LocalStorageProxy automatically serializes and deserializes data when saving and retrieving it.
+ *
+ * localStorage is extremely useful for saving user-specific information without needing to build server-side
  * infrastructure to support it. Let's imagine we're writing a Twitter search application and want to save the user's
- * searches locally so they can easily perform a saved search again later. We'd start by creating a Search model:</p>
- * 
-<pre><code>
-Ext.define('Search', {
-    fields: ['id', 'query'],
-    extend: 'Ext.data.Model',
-    proxy: {
-        type: 'localstorage',
-        id  : 'twitter-Searches'
-    }
-});
-</code></pre>
- * 
- * <p>Our Search model contains just two fields - id and query - plus a Proxy definition. The only configuration we
- * need to pass to the LocalStorage proxy is an {@link #id}. This is important as it separates the Model data in this
- * Proxy from all others. The localStorage API puts all data into a single shared namespace, so by setting an id we
- * enable LocalStorageProxy to manage the saved Search data.</p>
- * 
- * <p>Saving our data into localStorage is easy and would usually be done with a {@link Ext.data.Store Store}:</p>
- * 
-<pre><code>
-//our Store automatically picks up the LocalStorageProxy defined on the Search model
-var store = new Ext.data.Store({
-    model: "Search"
-});
-
-//loads any existing Search data from localStorage
-store.load();
-
-//now add some Searches
-store.add({query: 'Sencha Touch'});
-store.add({query: 'Ext JS'});
-
-//finally, save our Search data to localStorage
-store.sync();
-</code></pre>
- * 
- * <p>The LocalStorageProxy automatically gives our new Searches an id when we call store.sync(). It encodes the Model
- * data and places it into localStorage. We can also save directly to localStorage, bypassing the Store altogether:</p>
- * 
-<pre><code>
-var search = Ext.ModelManager.create({query: 'Sencha Animator'}, 'Search');
-
-//uses the configured LocalStorageProxy to save the new Search to localStorage
-search.save();
-</code></pre>
- * 
- * <p><u>Limitations</u></p>
- * 
- * <p>If this proxy is used in a browser where local storage is not supported, the constructor will throw an error.
- * A local storage proxy requires a unique ID which is used as a key in which all record data are stored in the
- * local storage object.</p>
- * 
- * <p>It's important to supply this unique ID as it cannot be reliably determined otherwise. If no id is provided
- * but the attached store has a storeId, the storeId will be used. If neither option is presented the proxy will
- * throw an error.</p>
+ * searches locally so they can easily perform a saved search again later. We'd start by creating a Search model:
+ *
+ *     Ext.define('Search', {
+ *         fields: ['id', 'query'],
+ *         extend: 'Ext.data.Model',
+ *         proxy: {
+ *             type: 'localstorage',
+ *             id  : 'twitter-Searches'
+ *         }
+ *     });
+ *
+ * Our Search model contains just two fields - id and query - plus a Proxy definition. The only configuration we need to
+ * pass to the LocalStorage proxy is an {@link #id}. This is important as it separates the Model data in this Proxy from
+ * all others. The localStorage API puts all data into a single shared namespace, so by setting an id we enable
+ * LocalStorageProxy to manage the saved Search data.
+ *
+ * Saving our data into localStorage is easy and would usually be done with a {@link Ext.data.Store Store}:
+ *
+ *     //our Store automatically picks up the LocalStorageProxy defined on the Search model
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: "Search"
+ *     });
+ *
+ *     //loads any existing Search data from localStorage
+ *     store.load();
+ *
+ *     //now add some Searches
+ *     store.add({query: 'Sencha Touch'});
+ *     store.add({query: 'Ext JS'});
+ *
+ *     //finally, save our Search data to localStorage
+ *     store.sync();
+ *
+ * The LocalStorageProxy automatically gives our new Searches an id when we call store.sync(). It encodes the Model data
+ * and places it into localStorage. We can also save directly to localStorage, bypassing the Store altogether:
+ *
+ *     var search = Ext.create('Search', {query: 'Sencha Animator'});
+ *
+ *     //uses the configured LocalStorageProxy to save the new Search to localStorage
+ *     search.save();
+ *
+ * # Limitations
+ *
+ * If this proxy is used in a browser where local storage is not supported, the constructor will throw an error. A local
+ * storage proxy requires a unique ID which is used as a key in which all record data are stored in the local storage
+ * object.
+ *
+ * It's important to supply this unique ID as it cannot be reliably determined otherwise. If no id is provided but the
+ * attached store has a storeId, the storeId will be used. If neither option is presented the proxy will throw an error.
  */
 Ext.define('Ext.data.proxy.LocalStorage', {
     extend: 'Ext.data.proxy.WebStorage',
@@ -57476,58 +60255,54 @@ Ext.define('Ext.data.proxy.LocalStorage', {
 });
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.Memory
- * @extends Ext.data.proxy.Client
  *
- * <p>In-memory proxy. This proxy simply uses a local variable for data storage/retrieval, so its contents are lost on
- * every page refresh.</p>
+ * In-memory proxy. This proxy simply uses a local variable for data storage/retrieval, so its contents are lost on
+ * every page refresh.
  *
- * <p>Usually this Proxy isn't used directly, serving instead as a helper to a {@link Ext.data.Store Store} where a
- * reader is required to load data. For example, say we have a Store for a User model and have some inline data we want
- * to load, but this data isn't in quite the right format: we can use a MemoryProxy with a JsonReader to read it into
- * our Store:</p>
+ * Usually this Proxy isn't used directly, serving instead as a helper to a {@link Ext.data.Store Store} where a reader
+ * is required to load data. For example, say we have a Store for a User model and have some inline data we want to
+ * load, but this data isn't in quite the right format: we can use a MemoryProxy with a JsonReader to read it into our
+ * Store:
  *
-<pre><code>
-//this is the model we will be using in the store
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: [
-        {name: 'id',    type: 'int'},
-        {name: 'name',  type: 'string'},
-        {name: 'phone', type: 'string', mapping: 'phoneNumber'}
-    ]
-});
-
-//this data does not line up to our model fields - the phone field is called phoneNumber
-var data = {
-    users: [
-        {
-            id: 1,
-            name: 'Ed Spencer',
-            phoneNumber: '555 1234'
-        },
-        {
-            id: 2,
-            name: 'Abe Elias',
-            phoneNumber: '666 1234'
-        }
-    ]
-};
-
-//note how we set the 'root' in the reader to match the data structure above
-var store = new Ext.data.Store({
-    autoLoad: true,
-    model: 'User',
-    data : data,
-    proxy: {
-        type: 'memory',
-        reader: {
-            type: 'json',
-            root: 'users'
-        }
-    }
-});
-</code></pre>
+ *     //this is the model we will be using in the store
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             {name: 'id',    type: 'int'},
+ *             {name: 'name',  type: 'string'},
+ *             {name: 'phone', type: 'string', mapping: 'phoneNumber'}
+ *         ]
+ *     });
+ *
+ *     //this data does not line up to our model fields - the phone field is called phoneNumber
+ *     var data = {
+ *         users: [
+ *             {
+ *                 id: 1,
+ *                 name: 'Ed Spencer',
+ *                 phoneNumber: '555 1234'
+ *             },
+ *             {
+ *                 id: 2,
+ *                 name: 'Abe Elias',
+ *                 phoneNumber: '666 1234'
+ *             }
+ *         ]
+ *     };
+ *
+ *     //note how we set the 'root' in the reader to match the data structure above
+ *     var store = Ext.create('Ext.data.Store', {
+ *         autoLoad: true,
+ *         model: 'User',
+ *         data : data,
+ *         proxy: {
+ *             type: 'memory',
+ *             reader: {
+ *                 type: 'json',
+ *                 root: 'users'
+ *             }
+ *         }
+ *     });
  */
 Ext.define('Ext.data.proxy.Memory', {
     extend: 'Ext.data.proxy.Client',
@@ -57535,7 +60310,8 @@ Ext.define('Ext.data.proxy.Memory', {
     alternateClassName: 'Ext.data.MemoryProxy',
 
     /**
-     * @cfg {Array} data Optional array of Records to load into the Proxy
+     * @cfg {Ext.data.Model[]} data
+     * Optional array of Records to load into the Proxy
      */
 
     constructor: function(config) {
@@ -57546,7 +60322,7 @@ Ext.define('Ext.data.proxy.Memory', {
     },
 
     /**
-     * Reads data from the configured {@link #data} object. Uses the Proxy's {@link #reader}, if present
+     * Reads data from the configured {@link #data} object. Uses the Proxy's {@link #reader}, if present.
      * @param {Ext.data.Operation} operation The read Operation
      * @param {Function} callback The callback to call when reading has completed
      * @param {Object} scope The scope to call the callback function in
@@ -57570,116 +60346,100 @@ Ext.define('Ext.data.proxy.Memory', {
 
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.Rest
- * @extends Ext.data.proxy.Ajax
- * 
- * <p>RestProxy is a specialization of the {@link Ext.data.proxy.Ajax AjaxProxy} which simply maps the four actions 
+ *
+ * The Rest proxy is a specialization of the {@link Ext.data.proxy.Ajax AjaxProxy} which simply maps the four actions
  * (create, read, update and destroy) to RESTful HTTP verbs. For example, let's set up a {@link Ext.data.Model Model}
- * with an inline RestProxy</p>
- * 
-<pre><code>
-Ext.define('User', {
-    extend: 'Ext.data.Model',
-    fields: ['id', 'name', 'email'],
-
-    proxy: {
-        type: 'rest',
-        url : '/users'
-    }
-});
-</code></pre>
- * 
- * <p>Now we can create a new User instance and save it via the RestProxy. Doing this will cause the Proxy to send a
- * POST request to '/users':
- * 
-<pre><code>
-var user = Ext.ModelManager.create({name: 'Ed Spencer', email: 'ed@sencha.com'}, 'User');
-
-user.save(); //POST /users
-</code></pre>
- * 
- * <p>Let's expand this a little and provide a callback for the {@link Ext.data.Model#save} call to update the Model
- * once it has been created. We'll assume the creation went successfully and that the server gave this user an ID of 
- * 123:</p>
- * 
-<pre><code>
-user.save({
-    success: function(user) {
-        user.set('name', 'Khan Noonien Singh');
-
-        user.save(); //PUT /users/123
-    }
-});
-</code></pre>
- * 
- * <p>Now that we're no longer creating a new Model instance, the request method is changed to an HTTP PUT, targeting
- * the relevant url for that user. Now let's delete this user, which will use the DELETE method:</p>
- * 
-<pre><code>
-    user.destroy(); //DELETE /users/123
-</code></pre>
- * 
- * <p>Finally, when we perform a load of a Model or Store, RestProxy will use the GET method:</p>
- * 
-<pre><code>
-//1. Load via Store
-
-//the Store automatically picks up the Proxy from the User model
-var store = new Ext.data.Store({
-    model: 'User'
-});
-
-store.load(); //GET /users
-
-//2. Load directly from the Model
-
-//GET /users/123
-Ext.ModelManager.getModel('User').load(123, {
-    success: function(user) {
-        console.log(user.getId()); //outputs 123
-    }
-});
-</code></pre>
- * 
- * <p><u>Url generation</u></p>
- * 
- * <p>RestProxy is able to automatically generate the urls above based on two configuration options - {@link #appendId}
- * and {@link #format}. If appendId is true (it is by default) then RestProxy will automatically append the ID of the 
- * Model instance in question to the configured url, resulting in the '/users/123' that we saw above.</p>
- * 
- * <p>If the request is not for a specific Model instance (e.g. loading a Store), the url is not appended with an id. 
- * RestProxy will automatically insert a '/' before the ID if one is not already present.</p>
- * 
-<pre><code>
-new Ext.data.proxy.Rest({
-    url: '/users',
-    appendId: true //default
-});
-
-// Collection url: /users
-// Instance url  : /users/123
-</code></pre>
- * 
- * <p>RestProxy can also optionally append a format string to the end of any generated url:</p>
- * 
-<pre><code>
-new Ext.data.proxy.Rest({
-    url: '/users',
-    format: 'json'
-});
-
-// Collection url: /users.json
-// Instance url  : /users/123.json
-</code></pre>
- * 
- * <p>If further customization is needed, simply implement the {@link #buildUrl} method and add your custom generated
- * url onto the {@link Ext.data.Request Request} object that is passed to buildUrl. See 
- * <a href="source/RestProxy.html#method-Ext.data.proxy.Rest-buildUrl">RestProxy's implementation</a> for an example of
- * how to achieve this.</p>
- * 
- * <p>Note that RestProxy inherits from {@link Ext.data.proxy.Ajax AjaxProxy}, which already injects all of the sorter,
+ * with an inline Rest proxy
+ *
+ *     Ext.define('User', {
+ *         extend: 'Ext.data.Model',
+ *         fields: ['id', 'name', 'email'],
+ *
+ *         proxy: {
+ *             type: 'rest',
+ *             url : '/users'
+ *         }
+ *     });
+ *
+ * Now we can create a new User instance and save it via the Rest proxy. Doing this will cause the Proxy to send a POST
+ * request to '/users':
+ *
+ *     var user = Ext.create('User', {name: 'Ed Spencer', email: 'ed@sencha.com'});
+ *
+ *     user.save(); //POST /users
+ *
+ * Let's expand this a little and provide a callback for the {@link Ext.data.Model#save} call to update the Model once
+ * it has been created. We'll assume the creation went successfully and that the server gave this user an ID of 123:
+ *
+ *     user.save({
+ *         success: function(user) {
+ *             user.set('name', 'Khan Noonien Singh');
+ *
+ *             user.save(); //PUT /users/123
+ *         }
+ *     });
+ *
+ * Now that we're no longer creating a new Model instance, the request method is changed to an HTTP PUT, targeting the
+ * relevant url for that user. Now let's delete this user, which will use the DELETE method:
+ *
+ *         user.destroy(); //DELETE /users/123
+ *
+ * Finally, when we perform a load of a Model or Store, Rest proxy will use the GET method:
+ *
+ *     //1. Load via Store
+ *
+ *     //the Store automatically picks up the Proxy from the User model
+ *     var store = Ext.create('Ext.data.Store', {
+ *         model: 'User'
+ *     });
+ *
+ *     store.load(); //GET /users
+ *
+ *     //2. Load directly from the Model
+ *
+ *     //GET /users/123
+ *     Ext.ModelManager.getModel('User').load(123, {
+ *         success: function(user) {
+ *             console.log(user.getId()); //outputs 123
+ *         }
+ *     });
+ *
+ * # Url generation
+ *
+ * The Rest proxy is able to automatically generate the urls above based on two configuration options - {@link #appendId} and
+ * {@link #format}. If appendId is true (it is by default) then Rest proxy will automatically append the ID of the Model
+ * instance in question to the configured url, resulting in the '/users/123' that we saw above.
+ *
+ * If the request is not for a specific Model instance (e.g. loading a Store), the url is not appended with an id.
+ * The Rest proxy will automatically insert a '/' before the ID if one is not already present.
+ *
+ *     new Ext.data.proxy.Rest({
+ *         url: '/users',
+ *         appendId: true //default
+ *     });
+ *
+ *     // Collection url: /users
+ *     // Instance url  : /users/123
+ *
+ * The Rest proxy can also optionally append a format string to the end of any generated url:
+ *
+ *     new Ext.data.proxy.Rest({
+ *         url: '/users',
+ *         format: 'json'
+ *     });
+ *
+ *     // Collection url: /users.json
+ *     // Instance url  : /users/123.json
+ *
+ * If further customization is needed, simply implement the {@link #buildUrl} method and add your custom generated url
+ * onto the {@link Ext.data.Request Request} object that is passed to buildUrl. See [Rest proxy's implementation][1] for
+ * an example of how to achieve this.
+ *
+ * Note that Rest proxy inherits from {@link Ext.data.proxy.Ajax AjaxProxy}, which already injects all of the sorter,
  * filter, group and paging options into the generated url. See the {@link Ext.data.proxy.Ajax AjaxProxy docs} for more
- * details.</p>
+ * details.
+ *
+ * [1]: source/RestProxy.html#method-Ext.data.proxy.Rest-buildUrl
  */
 Ext.define('Ext.data.proxy.Rest', {
     extend: 'Ext.data.proxy.Ajax',
@@ -57687,26 +60447,29 @@ Ext.define('Ext.data.proxy.Rest', {
     alias : 'proxy.rest',
     
     /**
-     * @cfg {Boolean} appendId True to automatically append the ID of a Model instance when performing a request based
-     * on that single instance. See RestProxy intro docs for more details. Defaults to true.
+     * @cfg {Boolean} appendId
+     * True to automatically append the ID of a Model instance when performing a request based on that single instance.
+     * See Rest proxy intro docs for more details. Defaults to true.
      */
     appendId: true,
     
     /**
-     * @cfg {String} format Optional data format to send to the server when making any request (e.g. 'json'). See the
-     * RestProxy intro docs for full details. Defaults to undefined.
+     * @cfg {String} format
+     * Optional data format to send to the server when making any request (e.g. 'json'). See the Rest proxy intro docs
+     * for full details. Defaults to undefined.
      */
     
     /**
-     * @cfg {Boolean} batchActions True to batch actions of a particular type when synchronizing the store.
-     * Defaults to <tt>false</tt>.
+     * @cfg {Boolean} batchActions
+     * True to batch actions of a particular type when synchronizing the store. Defaults to false.
      */
     batchActions: false,
     
     /**
      * Specialized version of buildUrl that incorporates the {@link #appendId} and {@link #format} options into the
-     * generated url. Override this to provide further customizations, but remember to call the superclass buildUrl
-     * so that additional parameters like the cache buster string are appended
+     * generated url. Override this to provide further customizations, but remember to call the superclass buildUrl so
+     * that additional parameters like the cache buster string are appended.
+     * @param {Object} request
      */
     buildUrl: function(request) {
         var me        = this,
@@ -57740,11 +60503,11 @@ Ext.define('Ext.data.proxy.Rest', {
 }, function() {
     Ext.apply(this.prototype, {
         /**
+         * @property {Object} actionMethods
          * Mapping of action name to HTTP request method. These default to RESTful conventions for the 'create', 'read',
-         * 'update' and 'destroy' actions (which map to 'POST', 'GET', 'PUT' and 'DELETE' respectively). This object should
-         * not be changed except globally via {@link Ext#override Ext.override} - the {@link #getMethod} function can be overridden instead.
-         * @property actionMethods
-         * @type Object
+         * 'update' and 'destroy' actions (which map to 'POST', 'GET', 'PUT' and 'DELETE' respectively). This object
+         * should not be changed except globally via {@link Ext#override Ext.override} - the {@link #getMethod} function
+         * can be overridden instead.
          */
         actionMethods: {
             create : 'POST',
@@ -57757,40 +60520,32 @@ Ext.define('Ext.data.proxy.Rest', {
 
 /**
  * @author Ed Spencer
- * @class Ext.data.proxy.SessionStorage
- * @extends Ext.data.proxy.WebStorage
- * 
- * <p>Proxy which uses HTML5 session storage as its data storage/retrieval mechanism.
- * If this proxy is used in a browser where session storage is not supported, the constructor will throw an error.
- * A session storage proxy requires a unique ID which is used as a key in which all record data are stored in the
- * session storage object.</p>
- * 
- * <p>It's important to supply this unique ID as it cannot be reliably determined otherwise. If no id is provided
- * but the attached store has a storeId, the storeId will be used. If neither option is presented the proxy will
- * throw an error.</p>
- * 
- * <p>Proxies are almost always used with a {@link Ext.data.Store store}:<p>
- * 
-<pre><code>
-new Ext.data.Store({
-    proxy: {
-        type: 'sessionstorage',
-        id  : 'myProxyKey'
-    }
-});
-</code></pre>
- * 
- * <p>Alternatively you can instantiate the Proxy directly:</p>
- * 
-<pre><code>
-new Ext.data.proxy.SessionStorage({
-    id  : 'myOtherProxyKey'
-});
- </code></pre>
- * 
- * <p>Note that session storage is different to local storage (see {@link Ext.data.proxy.LocalStorage}) - if a browser
+ *
+ * Proxy which uses HTML5 session storage as its data storage/retrieval mechanism. If this proxy is used in a browser
+ * where session storage is not supported, the constructor will throw an error. A session storage proxy requires a
+ * unique ID which is used as a key in which all record data are stored in the session storage object.
+ *
+ * It's important to supply this unique ID as it cannot be reliably determined otherwise. If no id is provided but the
+ * attached store has a storeId, the storeId will be used. If neither option is presented the proxy will throw an error.
+ *
+ * Proxies are almost always used with a {@link Ext.data.Store store}:
+ *
+ *     new Ext.data.Store({
+ *         proxy: {
+ *             type: 'sessionstorage',
+ *             id  : 'myProxyKey'
+ *         }
+ *     });
+ *
+ * Alternatively you can instantiate the Proxy directly:
+ *
+ *     new Ext.data.proxy.SessionStorage({
+ *         id  : 'myOtherProxyKey'
+ *     });
+ *
+ * Note that session storage is different to local storage (see {@link Ext.data.proxy.LocalStorage}) - if a browser
  * session is ended (e.g. by closing the browser) then all data in a SessionStorageProxy are lost. Browser restarts
- * don't affect the {@link Ext.data.proxy.LocalStorage} - the data are preserved.</p>
+ * don't affect the {@link Ext.data.proxy.LocalStorage} - the data are preserved.
  */
 Ext.define('Ext.data.proxy.SessionStorage', {
     extend: 'Ext.data.proxy.WebStorage',
@@ -57854,16 +60609,18 @@ Ext.define('Ext.data.reader.Array', {
         this.callParent(arguments);
         
         var fields = this.model.prototype.fields.items,
+            i = 0,
             length = fields.length,
             extractorFunctions = [],
-            i;
+            map;
         
-        for (i = 0; i < length; i++) {
+        for (; i < length; i++) {
+            map = fields[i].mapping;
             extractorFunctions.push(function(index) {
                 return function(data) {
                     return data[index];
                 };
-            }(fields[i].mapping || i));
+            }(map !== null ? map : i));
         }
         
         this.extractorFunctions = extractorFunctions;
@@ -57874,17 +60631,17 @@ Ext.define('Ext.data.reader.Array', {
  * @author Ed Spencer
  * @class Ext.data.reader.Xml
  * @extends Ext.data.reader.Reader
- * 
+ *
  * <p>The XML Reader is used by a Proxy to read a server response that is sent back in XML format. This usually
  * happens as a result of loading a Store - for example we might create something like this:</p>
- * 
+ *
 <pre><code>
 Ext.define('User', {
     extend: 'Ext.data.Model',
     fields: ['id', 'name', 'email']
 });
 
-var store = new Ext.data.Store({
+var store = Ext.create('Ext.data.Store', {
     model: 'User',
     proxy: {
         type: 'ajax',
@@ -57896,14 +60653,14 @@ var store = new Ext.data.Store({
     }
 });
 </code></pre>
- * 
+ *
  * <p>The example above creates a 'User' model. Models are explained in the {@link Ext.data.Model Model} docs if you're
  * not already familiar with them.</p>
- * 
- * <p>We created the simplest type of XML Reader possible by simply telling our {@link Ext.data.Store Store}'s 
+ *
+ * <p>We created the simplest type of XML Reader possible by simply telling our {@link Ext.data.Store Store}'s
  * {@link Ext.data.proxy.Proxy Proxy} that we want a XML Reader. The Store automatically passes the configured model to the
  * Store, so it is as if we passed this instead:
- * 
+ *
 <pre><code>
 reader: {
     type : 'xml',
@@ -57911,7 +60668,7 @@ reader: {
     record: 'user'
 }
 </code></pre>
- * 
+ *
  * <p>The reader we set up is ready to read data from our server - at the moment it will accept a response like this:</p>
  *
 <pre><code>
@@ -57927,16 +60684,16 @@ reader: {
     &lt;email&gt;abe@sencha.com&lt;/email&gt;
 &lt;/user&gt;
 </code></pre>
- * 
+ *
  * <p>The XML Reader uses the configured {@link #record} option to pull out the data for each record - in this case we
  * set record to 'user', so each &lt;user&gt; above will be converted into a User model.</p>
- * 
+ *
  * <p><u>Reading other XML formats</u></p>
- * 
+ *
  * <p>If you already have your XML format defined and it doesn't look quite like what we have above, you can usually
- * pass XmlReader a couple of configuration options to make it parse your format. For example, we can use the 
+ * pass XmlReader a couple of configuration options to make it parse your format. For example, we can use the
  * {@link #root} configuration to parse data that comes back like this:</p>
- * 
+ *
 <pre><code>
 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
 &lt;users&gt;
@@ -57952,9 +60709,9 @@ reader: {
     &lt;/user&gt;
 &lt;/users&gt;
 </code></pre>
- * 
+ *
  * <p>To parse this we just pass in a {@link #root} configuration that matches the 'users' above:</p>
- * 
+ *
 <pre><code>
 reader: {
     type  : 'xml',
@@ -57962,10 +60719,10 @@ reader: {
     record: 'user'
 }
 </code></pre>
- * 
+ *
  * <p>Note that XmlReader doesn't care whether your {@link #root} and {@link #record} elements are nested deep inside
  * a larger structure, so a response like this will still work:
- * 
+ *
 <pre><code>
 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
 &lt;deeply&gt;
@@ -57987,13 +60744,13 @@ reader: {
     &lt;/nested&gt;
 &lt;/deeply&gt;
 </code></pre>
- * 
+ *
  * <p><u>Response metadata</u></p>
- * 
- * <p>The server can return additional data in its response, such as the {@link #totalProperty total number of records} 
+ *
+ * <p>The server can return additional data in its response, such as the {@link #totalProperty total number of records}
  * and the {@link #successProperty success status of the response}. These are typically included in the XML response
  * like this:</p>
- * 
+ *
 <pre><code>
 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
 &lt;total&gt;100&lt;/total&gt;
@@ -58011,11 +60768,11 @@ reader: {
     &lt;/user&gt;
 &lt;/users&gt;
 </code></pre>
- * 
+ *
  * <p>If these properties are present in the XML response they can be parsed out by the XmlReader and used by the
- * Store that loaded it. We can set up the names of these properties by specifying a final pair of configuration 
+ * Store that loaded it. We can set up the names of these properties by specifying a final pair of configuration
  * options:</p>
- * 
+ *
 <pre><code>
 reader: {
     type: 'xml',
@@ -58024,14 +60781,14 @@ reader: {
     successProperty: 'success'
 }
 </code></pre>
- * 
+ *
  * <p>These final options are not necessary to make the Reader work, but can be useful when the server needs to report
  * an error or if it needs to indicate that there is a lot of data available of which only a subset is currently being
  * returned.</p>
- * 
+ *
  * <p><u>Response format</u></p>
- * 
- * <p><b>Note:</b> in order for the browser to parse a returned XML document, the Content-Type header in the HTTP 
+ *
+ * <p><b>Note:</b> in order for the browser to parse a returned XML document, the Content-Type header in the HTTP
  * response must be set to "text/xml" or "application/xml". This is very important - the XmlReader will not
  * work correctly otherwise.</p>
  */
@@ -58039,9 +60796,10 @@ Ext.define('Ext.data.reader.Xml', {
     extend: 'Ext.data.reader.Reader',
     alternateClassName: 'Ext.data.XmlReader',
     alias : 'reader.xml',
-    
+
     /**
-     * @cfg {String} record The DomQuery path to the repeated element which contains record information.
+     * @cfg {String} record (required)
+     * The DomQuery path to the repeated element which contains record information.
      */
 
     /**
@@ -58053,20 +60811,20 @@ Ext.define('Ext.data.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;
@@ -58103,12 +60861,12 @@ Ext.define('Ext.data.reader.Xml', {
      * @private
      * Given an XML object, returns the Element that represents the root as configured by the Reader's meta data
      * @param {Object} data The XML data object
-     * @return {Element} The root node element
+     * @return {XMLElement} The root node element
      */
     getRoot: function(data) {
         var nodeName = data.nodeName,
             root     = this.root;
-        
+
         if (!root || (nodeName && nodeName == root)) {
             return data;
         } else if (Ext.DomQuery.isXml(data)) {
@@ -58122,18 +60880,18 @@ Ext.define('Ext.data.reader.Xml', {
     /**
      * @private
      * We're just preparing the data for the superclass by pulling out the record nodes we want
-     * @param {Element} root The XML root node
-     * @return {Array} The records
+     * @param {XMLElement} root The XML root node
+     * @return {Ext.data.Model[]} The records
      */
     extractData: function(root) {
         var recordName = this.record;
-        
+
         //<debug>
         if (!recordName) {
             Ext.Error.raise('Record is a required parameter');
         }
         //</debug>
-        
+
         if (recordName != root.nodeName) {
             root = Ext.DomQuery.select(recordName, root);
         } else {
@@ -58141,13 +60899,13 @@ Ext.define('Ext.data.reader.Xml', {
         }
         return this.callParent([root]);
     },
-    
+
     /**
      * @private
      * See Ext.data.reader.Reader's getAssociatedDataRoot docs
-     * @param {Mixed} data The raw data object
+     * @param {Object} data The raw data object
      * @param {String} associationName The name of the association to get data for (uses associationKey if present)
-     * @return {Mixed} The root
+     * @return {XMLElement} The root
      */
     getAssociatedDataRoot: function(data, associationName) {
         return Ext.DomQuery.select(associationName, data)[0];
@@ -58163,9 +60921,9 @@ Ext.define('Ext.data.reader.Xml', {
         if (Ext.isArray(doc)) {
             doc = doc[0];
         }
-        
+
         /**
-         * DEPRECATED - will be removed in Ext JS 5.0. This is just a copy of this.rawData - use that instead
+         * @deprecated will be removed in Ext JS 5.0. This is just a copy of this.rawData - use that instead
          * @property xmlData
          * @type Object
          */
@@ -58268,18 +61026,18 @@ Ext.define('Ext.data.writer.Xml', {
  * A base class for all Ext.direct events. An event is
  * created after some kind of interaction with the server.
  * The event class is essentially just a data structure
- * to hold a direct response.
+ * to hold a Direct response.
  */
 Ext.define('Ext.direct.Event', {
-    
+
     /* Begin Definitions */
-   
+
     alias: 'direct.event',
-    
+
     requires: ['Ext.direct.Manager'],
-    
+
     /* End Definitions */
-   
+
     status: true,
 
     /**
@@ -58289,7 +61047,7 @@ Ext.define('Ext.direct.Event', {
     constructor: function(config) {
         Ext.apply(this, config);
     },
-    
+
     /**
      * Return the raw data for this event.
      * @return {Object} The data from the event
@@ -58346,31 +61104,31 @@ Ext.define('Ext.direct.ExceptionEvent', {
 /**
  * @class Ext.direct.Provider
  * <p>Ext.direct.Provider is an abstract class meant to be extended.</p>
- * 
- * <p>For example ExtJs implements the following subclasses:</p>
+ *
+ * <p>For example Ext JS implements the following subclasses:</p>
  * <pre><code>
 Provider
 |
-+---{@link Ext.direct.JsonProvider JsonProvider} 
++---{@link Ext.direct.JsonProvider JsonProvider}
     |
-    +---{@link Ext.direct.PollingProvider PollingProvider}   
+    +---{@link Ext.direct.PollingProvider PollingProvider}
     |
-    +---{@link Ext.direct.RemotingProvider RemotingProvider}   
+    +---{@link Ext.direct.RemotingProvider RemotingProvider}
  * </code></pre>
  * @abstract
  */
 Ext.define('Ext.direct.Provider', {
-    
+
     /* Begin Definitions */
-   
+
    alias: 'direct.provider',
-   
+
     mixins: {
-        observable: 'Ext.util.Observable'   
+        observable: 'Ext.util.Observable'
     },
-   
+
     /* End Definitions */
-   
+
    /**
      * @cfg {String} id
      * The unique id of the provider (defaults to an {@link Ext#id auto-assigned id}).
@@ -58381,45 +61139,45 @@ Ext.direct.Manager.addProvider({
     type: 'polling',
     url:  'php/poll.php',
     id:   'poll-provider'
-});     
+});
 var p = {@link Ext.direct.Manager}.{@link Ext.direct.Manager#getProvider getProvider}('poll-provider');
 p.disconnect();
      * </code></pre>
      */
-    
+
     constructor : function(config){
         var me = this;
-        
+
         Ext.apply(me, config);
         me.addEvents(
             /**
              * @event connect
              * Fires when the Provider connects to the server-side
              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
-             */            
+             */
             'connect',
             /**
              * @event disconnect
              * Fires when the Provider disconnects from the server-side
              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
-             */            
+             */
             'disconnect',
             /**
              * @event data
              * Fires when the Provider receives data from the server-side
              * @param {Ext.direct.Provider} provider The {@link Ext.direct.Provider Provider}.
-             * @param {event} e The Ext.Direct.Event type that occurred.
-             */            
+             * @param {Ext.direct.Event} e The Ext.direct.Event type that occurred.
+             */
             'data',
             /**
              * @event exception
              * Fires when the Provider receives an exception from the server-side
-             */                        
+             */
             'exception'
         );
         me.mixins.observable.constructor.call(me, config);
     },
-    
+
     /**
      * Returns whether or not the server-side is currently connected.
      * Abstract method for subclasses to implement.
@@ -58433,7 +61191,7 @@ p.disconnect();
      * @method
      */
     connect: Ext.emptyFn,
-    
+
     /**
      * Abstract methods for subclasses to implement.
      * @method
@@ -58453,17 +61211,17 @@ and should not be instanced directly.
  */
 
 Ext.define('Ext.direct.JsonProvider', {
-    
+
     /* Begin Definitions */
-    
+
     extend: 'Ext.direct.Provider',
-    
+
     alias: 'direct.jsonprovider',
-    
+
     uses: ['Ext.direct.ExceptionEvent'],
-    
+
     /* End Definitions */
-   
+
    /**
     * Parse the JSON response
     * @private
@@ -58484,7 +61242,7 @@ Ext.define('Ext.direct.JsonProvider', {
      * Creates a set of events based on the XHR response
      * @private
      * @param {Object} response The XHR response
-     * @return {Array} An array of Ext.direct.Event
+     * @return {Ext.direct.Event[]} An array of Ext.direct.Event
      */
     createEvents: function(response){
         var data = null,
@@ -58492,7 +61250,7 @@ Ext.define('Ext.direct.JsonProvider', {
             event,
             i = 0,
             len;
-            
+
         try{
             data = this.parseResponse(response);
         } catch(e) {
@@ -58504,7 +61262,7 @@ Ext.define('Ext.direct.JsonProvider', {
             });
             return [event];
         }
-        
+
         if (Ext.isArray(data)) {
             for (len = data.length; i < len; ++i) {
                 events.push(this.createEvent(data[i]));
@@ -58514,7 +61272,7 @@ Ext.define('Ext.direct.JsonProvider', {
         }
         return events;
     },
-    
+
     /**
      * Create an event from a response object
      * @param {Object} response The XHR response object
@@ -58571,14 +61329,13 @@ Ext.define('Ext.direct.PollingProvider', {
     
     /**
      * @cfg {Number} interval
-     * How often to poll the server-side in milliseconds (defaults to <tt>3000</tt> - every
-     * 3 seconds).
+     * How often to poll the server-side in milliseconds. Defaults to every 3 seconds.
      */
     interval: 3000,
 
     /**
-     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
-     * on every polling request
+     * @cfg {Object} baseParams
+     * An object containing properties which are to be sent as parameters on every polling request
      */
     
     /**
@@ -58595,13 +61352,13 @@ Ext.define('Ext.direct.PollingProvider', {
              * @event beforepoll
              * Fired immediately before a poll takes place, an event handler can return false
              * in order to cancel the poll.
-             * @param {Ext.direct.PollingProvider}
+             * @param {Ext.direct.PollingProvider} this
              */
             'beforepoll',            
             /**
              * @event poll
              * This event has not yet been implemented.
-             * @param {Ext.direct.PollingProvider}
+             * @param {Ext.direct.PollingProvider} this
              */
             'poll'
         );
@@ -58684,17 +61441,16 @@ Ext.define('Ext.direct.PollingProvider', {
 });
 /**
  * Small utility class used internally to represent a Direct method.
- * Thi class is used internally.
  * @class Ext.direct.RemotingMethod
  * @ignore
  */
 Ext.define('Ext.direct.RemotingMethod', {
-    
+
     constructor: function(config){
         var me = this,
             params = Ext.isDefined(config.params) ? config.params : config.len,
             name;
-            
+
         me.name = config.name;
         me.formHandler = config.formHandler;
         if (Ext.isNumber(params)) {
@@ -58714,7 +61470,7 @@ Ext.define('Ext.direct.RemotingMethod', {
             });
         }
     },
-    
+
     /**
      * Takes the arguments for the Direct function and splits the arguments
      * from the scope and the callback.
@@ -58729,7 +61485,7 @@ Ext.define('Ext.direct.RemotingMethod', {
             callback,
             scope,
             name;
-            
+
         if (me.ordered) {
             callback = args[len];
             scope = args[len + 1];
@@ -58740,7 +61496,7 @@ Ext.define('Ext.direct.RemotingMethod', {
             data = Ext.apply({}, args[0]);
             callback = args[1];
             scope = args[2];
-            
+
             // filter out any non-existent properties
             for (name in data) {
                 if (data.hasOwnProperty(name)) {
@@ -58750,19 +61506,17 @@ Ext.define('Ext.direct.RemotingMethod', {
                 }
             }
         }
-        
+
         return {
             data: data,
             callback: callback,
-            scope: scope    
+            scope: scope
         };
     }
 });
 
 /**
- * @class Ext.direct.Transaction
- * @extends Object
- * <p>Supporting Class for Ext.Direct (not intended to be used directly).</p>
+ * Supporting Class for Ext.Direct (not intended to be used directly).
  */
 Ext.define('Ext.direct.Transaction', {
     
@@ -58779,7 +61533,7 @@ Ext.define('Ext.direct.Transaction', {
 
     /**
      * Creates new Transaction.
-     * @param {Object} config  (optional) Config object.
+     * @param {Object} [config] Config object.
      */
     constructor: function(config){
         var me = this;
@@ -58907,7 +61661,7 @@ TestAction.multiply(
      * @cfg {Number/Boolean} enableBuffer
      * <p><tt>true</tt> or <tt>false</tt> to enable or disable combining of method
      * calls. If a number is specified this is the amount of time in milliseconds
-     * to wait before sending a batched request (defaults to <tt>10</tt>).</p>
+     * to wait before sending a batched request.</p>
      * <br><p>Calls which are received within the specified timeframe will be
      * concatenated together and sent in a single request, optimizing the
      * application by reducing the amount of round trips that have to be made
@@ -58917,13 +61671,13 @@ TestAction.multiply(
     
     /**
      * @cfg {Number} maxRetries
-     * Number of times to re-attempt delivery on failure of a call. Defaults to <tt>1</tt>.
+     * Number of times to re-attempt delivery on failure of a call.
      */
     maxRetries: 1,
     
     /**
      * @cfg {Number} timeout
-     * The timeout to use for each request. Defaults to <tt>undefined</tt>.
+     * The timeout to use for each request.
      */
     timeout: undefined,
     
@@ -59254,7 +62008,7 @@ TestAction.multiply(
      * @param {Object} method The method being executed
      * @param {HTMLElement} form The form being submitted
      * @param {Function} callback (optional) A callback to run after the form submits
-     * @param {Object} scope A scope to execute the callback in
+     * @param {Object} scope (optional) A scope to execute the callback in
      */
     configureFormRequest : function(action, method, form, callback, scope){
         var me = this,
@@ -59447,14 +62201,14 @@ Ext.define('Ext.draw.Matrix', {
 
     toFilter: function() {
         var me = this;
-        return "progid:DXImageTransform.Microsoft.Matrix(M11=" + me.get(0, 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) + ", Dy=" + me.get(1, 2) + ")";
     },
 
     offset: function() {
         var matrix = this.matrix;
-        return [matrix[0][2].toFixed(4), matrix[1][2].toFixed(4)];
+        return [(matrix[0][2] || 0).toFixed(4), (matrix[1][2] || 0).toFixed(4)];
     },
 
     // Split matrix into Translate Scale, Shear, and Rotate
@@ -59475,7 +62229,7 @@ Ext.define('Ext.draw.Matrix', {
             row;
 
         // scale and shear
-        row = [[matrix[0][0], matrix[0][1]], [matrix[1][1], matrix[1][1]]];
+        row = [[matrix[0][0], matrix[0][1]], [matrix[1][0], matrix[1][1]]];
         out.scaleX = Math.sqrt(norm(row[0]));
         normalize(row[0]);
 
@@ -59494,6 +62248,7 @@ Ext.define('Ext.draw.Matrix', {
         return out;
     }
 });
+
 // private - DD implementation for Panels
 Ext.define('Ext.draw.SpriteDD', {
     extend: 'Ext.dd.DragSource',
@@ -59524,7 +62279,7 @@ Ext.define('Ext.draw.SpriteDD', {
         bbox = sprite.getBBox();
         
         try {
-            pos = Ext.core.Element.getXY(el);
+            pos = Ext.Element.getXY(el);
         } catch (e) { }
 
         if (!pos) {
@@ -59552,68 +62307,40 @@ Ext.define('Ext.draw.SpriteDD', {
      
     startDrag: function(x, y) {
         var me = this,
-            attr = me.sprite.attr,
-            trans = attr.translation;
-        if (me.sprite.vml) {
-            me.prevX = x + attr.x;
-            me.prevY = y + attr.y;
-        } else {
-            me.prevX = x - trans.x;
-            me.prevY = y - trans.y;
-        }
+            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;
-        me.translateX = xy[0] - me.prevX;
-        me.translateY = xy[1] - me.prevY;
+            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: me.translateX,
-                y: me.translateY
+                x: attr.translation.x + dx,
+                y: attr.translation.y + dy
             }
         }, true);
-        if (sprite.vml) {
-            me.prevX = xy[0] + attr.x || 0;
-            me.prevY = xy[1] + attr.y || 0;
-        }
+        me.prev = xy;
+    },
+
+    setDragElPos: function () {
+        // Disable automatic DOM move in DD that spoils layout of VML engine.
+        return false;
     }
 });
 /**
- * @class Ext.draw.Sprite
- * @extends Object
- *
- * A Sprite is an object rendered in a Drawing surface. There are different options and types of sprites.
- * The configuration of a Sprite is an object with the following properties:
- *
- * - **type** - (String) The type of the sprite. Possible options are 'circle', 'path', 'rect', 'text', 'square', 'image'. 
- * - **group** - (String/Array) The group that this sprite belongs to, or an array of groups. Only relevant when added to a {@link Ext.draw.Surface}.
- * - **width** - (Number) Used in rectangle sprites, the width of the rectangle.
- * - **height** - (Number) Used in rectangle sprites, the height of the rectangle.
- * - **size** - (Number) Used in square sprites, the dimension of the square.
- * - **radius** - (Number) Used in circle sprites, the radius of the circle.
- * - **x** - (Number) The position along the x-axis.
- * - **y** - (Number) The position along the y-axis.
- * - **path** - (Array) Used in path sprites, the path of the sprite written in SVG-like path syntax.
- * - **opacity** - (Number) The opacity of the sprite.
- * - **fill** - (String) The fill color.
- * - **stroke** - (String) The stroke color.
- * - **stroke-width** - (Number) The width of the stroke.
- * - **font** - (String) Used with text type sprites. The full font description. Uses the same syntax as the CSS `font` parameter.
- * - **text** - (String) Used with text type sprites. The text itself.
- * - **translate** - (Object) Defines a translation for the Sprite. There's more information on this property below.
- * - **rotate** - (Object) Defines a rotation for the Sprite. There's more information on this property below.
- * - **scale** - (Object) Defines a scaling for the Sprite. There's more information on this property below.
- * 
+ * A Sprite is an object rendered in a Drawing surface.
+ *
+ * # Translation
  *
- * ## Translation
- * 
  * For translate, the configuration object contains x and y attributes that indicate where to
  * translate the object. For example:
- * 
+ *
  *     sprite.setAttributes({
  *       translate: {
  *        x: 10,
@@ -59622,11 +62349,11 @@ Ext.define('Ext.draw.SpriteDD', {
  *     }, true);
  *
  *
- * ## Rotation
- * 
+ * # Rotation
+ *
  * For rotation, the configuration object contains x and y attributes for the center of the rotation (which are optional),
  * and a `degrees` attribute that specifies the rotation in degrees. For example:
- * 
+ *
  *     sprite.setAttributes({
  *       rotate: {
  *        degrees: 90
@@ -59646,10 +62373,10 @@ Ext.define('Ext.draw.SpriteDD', {
  * will create a rotation around the `(0, 0)` axis.
  *
  *
- * ## Scaling
- * 
+ * # Scaling
+ *
  * For scaling, the configuration object contains x and y attributes for the x-axis and y-axis scaling. For example:
- * 
+ *
  *     sprite.setAttributes({
  *       scale: {
  *        x: 10,
@@ -59669,33 +62396,33 @@ Ext.define('Ext.draw.SpriteDD', {
  *     }, true);
  *
  * That last example will scale a sprite taking as centers of scaling the `(0, 0)` coordinate.
- * 
- * 
- * ## Creating and adding a Sprite to a Surface
- * 
+ *
+ *
+ * # Creating and adding a Sprite to a Surface
+ *
  * Sprites can be created with a reference to a {@link Ext.draw.Surface}
  *
- *      var drawComponent = Ext.create('Ext.draw.Component', options here...);
+ *     var drawComponent = Ext.create('Ext.draw.Component', options here...);
  *
- *      var sprite = Ext.create('Ext.draw.Sprite', {
- *          type: 'circle',
- *          fill: '#ff0',
- *          surface: drawComponent.surface,
- *          radius: 5
- *      });
+ *     var sprite = Ext.create('Ext.draw.Sprite', {
+ *         type: 'circle',
+ *         fill: '#ff0',
+ *         surface: drawComponent.surface,
+ *         radius: 5
+ *     });
  *
  * Sprites can also be added to the surface as a configuration object:
  *
- *      var sprite = drawComponent.surface.add({
- *          type: 'circle',
- *          fill: '#ff0',
- *          radius: 5
- *      });
+ *     var sprite = drawComponent.surface.add({
+ *         type: 'circle',
+ *         fill: '#ff0',
+ *         radius: 5
+ *     });
  *
  * In order to properly apply properties and render the sprite we have to
  * `show` the sprite setting the option `redraw` to `true`:
  *
- *      sprite.show(true);
+ *     sprite.show(true);
  *
  * The constructor configuration object of the Sprite can also be used and passed into the {@link Ext.draw.Surface}
  * add method to append a new sprite to the canvas. For example:
@@ -59709,78 +62436,82 @@ Ext.define('Ext.draw.SpriteDD', {
  *     });
  */
 Ext.define('Ext.draw.Sprite', {
-    
+
+    /* Begin Definitions */
+
+    mixins: {
+        observable: 'Ext.util.Observable',
+        animate: 'Ext.util.Animate'
+    },
+
+    requires: ['Ext.draw.SpriteDD'],
+
+    /* End Definitions */
+
     /**
      * @cfg {String} type The type of the sprite. Possible options are 'circle', 'path', 'rect', 'text', 'square', 'image'
      */
-    
+
     /**
      * @cfg {Number} width Used in rectangle sprites, the width of the rectangle
      */
-    
+
     /**
      * @cfg {Number} height Used in rectangle sprites, the height of the rectangle
      */
-    
+
     /**
      * @cfg {Number} size Used in square sprites, the dimension of the square
      */
-    
+
     /**
      * @cfg {Number} radius Used in circle sprites, the radius of the circle
      */
-    
+
     /**
      * @cfg {Number} x The position along the x-axis
      */
-    
+
     /**
      * @cfg {Number} y The position along the y-axis
      */
-    
+
     /**
      * @cfg {Array} path Used in path sprites, the path of the sprite written in SVG-like path syntax
      */
-    
+
     /**
      * @cfg {Number} opacity The opacity of the sprite
      */
-    
+
     /**
      * @cfg {String} fill The fill color
      */
-    
+
     /**
      * @cfg {String} stroke The stroke color
      */
-    
+
     /**
      * @cfg {Number} stroke-width The width of the stroke
      */
-    
+
     /**
      * @cfg {String} font Used with text type sprites. The full font description. Uses the same syntax as the CSS font parameter
      */
-    
+
     /**
      * @cfg {String} text Used with text type sprites. The text itself
      */
-    
+
     /**
-     * @cfg {String/Array} group The group that this sprite belongs to, or an array of groups. Only relevant when added to a
+     * @cfg {String/String[]} group The group that this sprite belongs to, or an array of groups. Only relevant when added to a
      * {@link Ext.draw.Surface}
      */
-    
-    /* Begin Definitions */
-
-    mixins: {
-        observable: 'Ext.util.Observable',
-        animate: 'Ext.util.Animate'
-    },
 
-    requires: ['Ext.draw.SpriteDD'],
-
-    /* End Definitions */
+    /**
+     * @cfg {Boolean} draggable True to make the sprite draggable.
+     */
 
     dirty: false,
     dirtyHidden: false,
@@ -59860,13 +62591,14 @@ Ext.define('Ext.draw.Sprite', {
     },
 
     /**
-     * <p>If this Sprite is configured {@link #draggable}, this property will contain
-     * an instance of {@link Ext.dd.DragSource} which handles dragging the Sprite.</p>
+     * @property {Ext.dd.DragSource} dd
+     * If this Sprite is configured {@link #draggable}, this property will contain
+     * an instance of {@link Ext.dd.DragSource} which handles dragging the Sprite.
+     *
      * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
      * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
-     * @type Ext.dd.DragSource.
-     * @property dd
      */
+
     initDraggable: function() {
         var me = this;
         me.draggable = true;
@@ -59944,7 +62676,7 @@ Ext.define('Ext.draw.Sprite', {
         rotate = attrs.rotate;
         rotation = spriteAttrs.rotation;
         if (rotate) {
-            if ((rotate.x && rotate.x !== rotation.x) || 
+            if ((rotate.x && rotate.x !== rotation.x) ||
                 (rotate.y && rotate.y !== rotation.y) ||
                 (rotate.degrees && rotate.degrees !== rotation.degrees)) {
                 Ext.apply(rotation, rotate);
@@ -59956,7 +62688,7 @@ Ext.define('Ext.draw.Sprite', {
         scale = attrs.scale;
         scaling = spriteAttrs.scaling;
         if (scale) {
-            if ((scale.x && scale.x !== scaling.x) || 
+            if ((scale.x && scale.x !== scaling.x) ||
                 (scale.y && scale.y !== scaling.y) ||
                 (scale.cx && scale.cx !== scaling.cx) ||
                 (scale.cy && scale.cy !== scaling.cy)) {
@@ -59976,19 +62708,20 @@ Ext.define('Ext.draw.Sprite', {
     },
 
     /**
-     * Retrieve the bounding box of the sprite. This will be returned as an object with x, y, width, and height properties.
+     * Retrieves the bounding box of the sprite.
+     * This will be returned as an object with x, y, width, and height properties.
      * @return {Object} bbox
      */
     getBBox: function() {
         return this.surface.getBBox(this);
     },
-    
+
     setText: function(text) {
         return this.surface.setText(this, text);
     },
 
     /**
-     * Hide the sprite.
+     * Hides the sprite.
      * @param {Boolean} redraw Flag to immediatly draw the change.
      * @return {Ext.draw.Sprite} this
      */
@@ -60000,7 +62733,7 @@ Ext.define('Ext.draw.Sprite', {
     },
 
     /**
-     * Show the sprite.
+     * Shows the sprite.
      * @param {Boolean} redraw Flag to immediatly draw the change.
      * @return {Ext.draw.Sprite} this
      */
@@ -60012,7 +62745,7 @@ Ext.define('Ext.draw.Sprite', {
     },
 
     /**
-     * Remove the sprite.
+     * Removes the sprite.
      */
     remove: function() {
         if (this.surface) {
@@ -60040,7 +62773,7 @@ Ext.define('Ext.draw.Sprite', {
     },
 
     /**
-     * Redraw the sprite.
+     * Redraws the sprite.
      * @return {Ext.draw.Sprite} this
      */
     redraw: function() {
@@ -60062,7 +62795,7 @@ Ext.define('Ext.draw.Sprite', {
     /**
      * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.  Note this method
      * is severly limited in VML.
-     * @param {String/Array} className The CSS class to add, or an array of classes
+     * @param {String/String[]} className The CSS class to add, or an array of classes
      * @return {Ext.draw.Sprite} this
      */
     addCls: function(obj) {
@@ -60072,7 +62805,7 @@ Ext.define('Ext.draw.Sprite', {
 
     /**
      * Removes one or more CSS classes from the element.
-     * @param {String/Array} className The CSS class to remove, or an array of classes.  Note this method
+     * @param {String/String[]} className The CSS class to remove, or an array of classes.  Note this method
      * is severly limited in VML.
      * @return {Ext.draw.Sprite} this
      */
@@ -60093,7 +62826,7 @@ Ext.define('Ext.draw.engine.Svg', {
 
     extend: 'Ext.draw.Surface',
 
-    requires: ['Ext.draw.Draw', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.core.Element'],
+    requires: ['Ext.draw.Draw', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],
 
     /* End Definitions */
 
@@ -60650,17 +63383,19 @@ Ext.define('Ext.draw.engine.Svg', {
      * @param {Ext.draw.Sprite} sprite
      */
     applyZIndex: function(sprite) {
-        var idx = this.normalizeSpriteCollection(sprite),
+        var me = this,
+            items = me.items,
+            idx = items.indexOf(sprite),
             el = sprite.el,
             prevEl;
-        if (this.el.dom.childNodes[idx + 2] !== el.dom) { //shift by 2 to account for defs and bg rect 
+        if (me.el.dom.childNodes[idx + 2] !== el.dom) { //shift by 2 to account for defs and bg rect
             if (idx > 0) {
                 // Find the first previous sprite which has its DOM element created already
                 do {
-                    prevEl = this.items.getAt(--idx).el;
+                    prevEl = items.getAt(--idx).el;
                 } while (!prevEl && idx > 0);
             }
-            el.insertAfter(prevEl || this.bgRect);
+            el.insertAfter(prevEl || me.bgRect);
         }
         sprite.zIndexDirty = false;
     },
@@ -60799,7 +63534,7 @@ Ext.define('Ext.draw.engine.Vml', {
 
     extend: 'Ext.draw.Surface',
 
-    requires: ['Ext.draw.Draw', 'Ext.draw.Color', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.core.Element'],
+    requires: ['Ext.draw.Draw', 'Ext.draw.Color', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],
 
     /* End Definitions */
 
@@ -60821,6 +63556,9 @@ Ext.define('Ext.draw.engine.Vml', {
     coordsize: 1000,
     coordorigin: '0 0',
 
+    // VML uses CSS z-index and therefore doesn't need sprites to be kept in zIndex order
+    orderSpritesByZIndex: false,
+
     // @private
     // Convert an SVG standard path into a VML path
     path2vml: function (path) {
@@ -60974,7 +63712,7 @@ Ext.define('Ext.draw.engine.Vml', {
             zoom = me.zoom,
             vml = sprite.vml || (sprite.vml = {}),
             round = Math.round,
-            el = (type === 'image') ? me.createNode('image') : me.createNode('shape'),
+            el = me.createNode('shape'),
             path, skew, textPath;
 
         el.coordsize = zoom + ' ' + zoom;
@@ -61054,21 +63792,6 @@ Ext.define('Ext.draw.engine.Vml', {
         // Apply minimum default attributes
         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
-            });
-            bbox = sprite.getBBox();
-            el.setStyle({
-                width: bbox.width + 'px',
-                height: bbox.height + 'px'
-            });
-            dom.src = scrubbedAttrs.src;
-        }
-
         if (dom.href) {
             dom.href = scrubbedAttrs.href;
         }
@@ -61103,7 +63826,7 @@ Ext.define('Ext.draw.engine.Vml', {
                             Math.round(cx * me.zoom));
                 sprite.dirtyPath = false;
             }
-            else if (sprite.type !== "text" && sprite.type !== 'image') {
+            else if (sprite.type !== "text") {
                 sprite.attr.path = scrubbedAttrs.path = me.setPaths(sprite, scrubbedAttrs) || scrubbedAttrs.path;
                 dom.path = me.path2vml(scrubbedAttrs.path);
                 sprite.dirtyPath = false;
@@ -61121,7 +63844,7 @@ Ext.define('Ext.draw.engine.Vml', {
         }
 
         // Handle fill and opacity
-        if (scrubbedAttrs.opacity  || scrubbedAttrs['stroke-opacity'] || scrubbedAttrs.fill) {
+        if (sprite.type == 'image' || scrubbedAttrs.opacity  || scrubbedAttrs['fill-opacity'] || scrubbedAttrs.fill) {
             me.setFill(sprite, scrubbedAttrs);
         }
 
@@ -61163,7 +63886,7 @@ Ext.define('Ext.draw.engine.Vml', {
             spriteAttr.ry = params.ry;
             return Ext.draw.Draw.ellipsePath(sprite);
         }
-        else if (sprite.type == 'rect') {
+        else if (sprite.type == 'rect' || sprite.type == 'image') {
             spriteAttr.rx = spriteAttr.ry = params.r;
             return Ext.draw.Draw.rectPath(sprite);
         }
@@ -61175,23 +63898,27 @@ Ext.define('Ext.draw.engine.Vml', {
 
     setFill: function(sprite, params) {
         var me = this,
-            el = sprite.el.dom,
-            fillEl = el.fill,
-            newfill = false,
+            el = sprite.el,
+            dom = el.dom,
+            fillEl = dom.getElementsByTagName('fill')[0],
             opacity, gradient, fillUrl, rotation, angle;
 
-        if (!fillEl) {
-            // NOT an expando (but it sure looks like one)...
-            fillEl = el.fill = me.createNode("fill");
-            newfill = true;
+        if (fillEl) {
+            dom.removeChild(fillEl);
+        } else {
+            fillEl = me.createNode('fill');
         }
         if (Ext.isArray(params.fill)) {
             params.fill = params.fill[0];
         }
-        if (params.fill == "none") {
+        if (sprite.type == 'image') {
+            fillEl.on = true;
+            fillEl.src = params.src;
+            fillEl.type = "tile";
+            fillEl.rotate = true;
+        } else if (params.fill == "none") {
             fillEl.on = false;
-        }
-        else {
+        } else {
             if (typeof params.opacity == "number") {
                 fillEl.opacity = params.opacity;
             }
@@ -61218,24 +63945,23 @@ Ext.define('Ext.draw.engine.Vml', {
                         fillEl.angle = angle;
                         fillEl.type = "gradient";
                         fillEl.method = "sigma";
-                        fillEl.colors.value = gradient.colors;
+                        fillEl.colors = gradient.colors;
                     }
                     // Otherwise treat it as an image
                     else {
                         fillEl.src = fillUrl;
                         fillEl.type = "tile";
+                        fillEl.rotate = true;
                     }
                 }
                 else {
-                    fillEl.color = Ext.draw.Color.toHex(params.fill);
+                    fillEl.color = Ext.draw.Color.toHex(params.fill) || params.fill;
                     fillEl.src = "";
                     fillEl.type = "solid";
                 }
             }
         }
-        if (newfill) {
-            el.appendChild(fillEl);
-        }
+        dom.appendChild(fillEl);
     },
 
     setStroke: function(sprite, params) {
@@ -61470,24 +64196,26 @@ Ext.define('Ext.draw.engine.Vml', {
         this.callParent(arguments);
     },
 
+    // VML Node factory method (createNode)
+    createNode : (function () {
+        try {
+            var doc = Ext.getDoc().dom;
+            if (!doc.namespaces.rvml) {
+                doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
+            }
+            return function (tagName) {
+                return doc.createElement("<rvml:" + tagName + ' class="rvml">');
+            };
+        } catch (e) {
+            return function (tagName) {
+                return doc.createElement("<" + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
+            };
+        }
+    })(),
+
     render: function (container) {
         var me = this,
             doc = Ext.getDoc().dom;
-        // VML Node factory method (createNode)
-        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) {
             var el = doc.createElement("div");
@@ -61552,92 +64280,130 @@ Ext.define('Ext.draw.engine.Vml', {
         };
     },
 
-    transform: function(sprite) {
+    extractTransform: function (sprite) {
         var me = this,
-            matrix = Ext.create('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,
-            deltaX, deltaY, transform, type, compensate, y, fill, newAngle,zoomScaleX, zoomScaleY, newOrigin;
+            matrix = Ext.create('Ext.draw.Matrix'), scale,
+            transformstions, tranformationsLength,
+            transform, i = 0,
+            shift = me.viewBoxShift;
 
-        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;
+        for(transformstions = sprite.transformations, tranformationsLength = transformstions.length;
+            i < tranformationsLength; i ++) {
+            transform = transformstions[i];
+            switch (transform.type) {
+                case 'translate' :
+                    matrix.translate(transform.x, transform.y);
+                    break;
+                case 'rotate':
+                    matrix.rotate(transform.degrees, transform.x, transform.y);
+                    break;
+                case 'scale':
+                    matrix.scale(transform.x || transform.scale, transform.y || transform.scale, transform.centerX, transform.centerY);
+                    break;
             }
         }
 
-        if (me.viewBoxShift) {
-            matrix.scale(me.viewBoxShift.scale, me.viewBoxShift.scale, -1, -1);
-            matrix.add(1, 0, 0, 1, me.viewBoxShift.dx, me.viewBoxShift.dy);
+        if (shift) {
+            matrix.add(1, 0, 0, 1, shift.dx, shift.dy);
+            matrix.prepend(shift.scale, 0, 0, shift.scale, 0, 0);
         }
+        
+        return sprite.matrix = matrix;
+    },
 
-        sprite.matrix = matrix;
+    setSimpleCoords: function(sprite, sx, sy, dx, dy, rotate) {
+        var me = this,
+            matrix = sprite.matrix,
+            dom = sprite.el.dom,
+            style = dom.style,
+            yFlipper = 1,
+            flip = "",
+            fill = dom.getElementsByTagName('fill')[0],
+            kx = me.zoom / sx,
+            ky = me.zoom / sy,
+            rotationCompensation;
+        if (!sx || !sy) {
+            return;
+        }
+        dom.coordsize = Math.abs(kx) + ' ' + Math.abs(ky);
+        style.rotation = rotate * (sx * sy < 0 ? -1 : 1);
+        if (rotate) {
+            rotationCompensation = me.rotationCompensation(rotate, dx, dy);
+            dx = rotationCompensation.x;
+            dy = rotationCompensation.y;
+        }
+        if (sx < 0) {
+            flip += "x"
+        }
+        if (sy < 0) {
+            flip += " y";
+            yFlipper = -1;
+        }
+        style.flip = flip;
+        dom.coordorigin = (dx * -kx) + ' ' + (dy * -ky);
+        if (fill) {
+            dom.removeChild(fill);
+            rotationCompensation = me.rotationCompensation(rotate, matrix.x(sprite.x, sprite.y), matrix.y(sprite.x, sprite.y));
+            fill.position = rotationCompensation.x * yFlipper + ' ' + rotationCompensation.y * yFlipper;
+            fill.size = sprite.width * Math.abs(sx) + ' ' + sprite.height * Math.abs(sy);
+            dom.appendChild(fill);
+        }
+    },
+
+    transform : function (sprite) {
+        var me = this,
+            el = sprite.el,
+            skew = sprite.skew,
+            dom = el.dom,
+            domStyle = dom.style,
+            matrix = me.extractTransform(sprite).clone(),
+            split, zoom = me.zoom,
+            fill = dom.getElementsByTagName('fill')[0],
+            isPatt = !String(sprite.fill).indexOf("url("),
+            offset, c;
 
 
         // Hide element while we transform
 
-        if (sprite.type != "image" && skew) {
+        if (sprite.type != "image" && skew && !isPatt) {
             // matrix transform via VML skew
             skew.matrix = matrix.toString();
-            skew.offset = matrix.offset();
-        }
-        else {
-            deltaX = matrix.matrix[0][2];
-            deltaY = matrix.matrix[1][2];
-            // Scale via coordsize property
-            zoomScaleX = zoom / deltaScaleX;
-            zoomScaleY = zoom / deltaScaleY;
-
-            dom.coordsize = Math.abs(zoomScaleX) + " " + Math.abs(zoomScaleY);
-
-            // Rotate via rotation property
-            newAngle = deltaDegrees * (deltaScaleX * ((deltaScaleY < 0) ? -1 : 1));
-            if (newAngle != domStyle.rotation && !(newAngle === 0 && !domStyle.rotation)) {
-                domStyle.rotation = newAngle;
-            }
-            if (deltaDegrees) {
-                // Compensate x/y position due to rotation
-                compensate = me.rotationCompensation(deltaDegrees, deltaX, deltaY);
-                deltaX = compensate.x;
-                deltaY = compensate.y;
-            }
-
-            // Handle negative scaling via flipping
-            if (deltaScaleX < 0) {
-                flip += "x";
-            }
-            if (deltaScaleY < 0) {
-                flip += " y";
-                y = -1;
-            }
-            if (flip != "" && !dom.style.flip) {
-                domStyle.flip = flip;
-            }
-
-            // Translate via coordorigin property
-            newOrigin = (deltaX * -zoomScaleX) + " " + (deltaY * -zoomScaleY);
-            if (newOrigin != dom.coordorigin) {
-                dom.coordorigin = (deltaX * -zoomScaleX) + " " + (deltaY * -zoomScaleY);
+            // skew.offset = '32767,1' OK
+            // skew.offset = '32768,1' Crash
+            // M$, R U kidding??
+            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 {
+            if (skew) {
+                skew.matrix = "1 0 0 1";
+                skew.offset = "0 0";
+            }
+            split = matrix.split();
+            if (split.isSimple) {
+                domStyle.filter = '';
+                me.setSimpleCoords(sprite, split.scaleX, split.scaleY, split.translateX, split.translateY, split.rotate / Math.PI * 180);
+            } else {
+                domStyle.filter = matrix.toFilter();
+                var bb = me.getBBox(sprite),
+                    dx = bb.x - sprite.x,
+                    dy = bb.y - sprite.y;
+                dom.coordorigin = (dx * -zoom) + ' ' + (dy * -zoom);
+                if (fill) {
+                    dom.removeChild(fill);
+                    fill.position = dx + ' ' + dy;
+                    fill.size = sprite.width * sprite.scale.x + ' ' + sprite.height * 1.1;
+                    dom.appendChild(fill);
+                }
             }
         }
     },
@@ -61704,8 +64470,8 @@ Ext.define('Ext.draw.engine.Vml', {
  * @class Ext.fx.target.ElementCSS
  * @extends Ext.fx.target.Element
  * 
- * This class represents a animation target for an {@link Ext.core.Element} that supports CSS
- * based animation. In general this class will not be created directly, the {@link Ext.core.Element} 
+ * This class represents a animation target for an {@link Ext.Element} that supports CSS
+ * based animation. In general this class will not be created directly, the {@link Ext.Element} 
  * will be passed to the animation and the appropriate target will be created.
  */
 Ext.define('Ext.fx.target.ElementCSS', {
@@ -61783,7 +64549,7 @@ Ext.define('Ext.fx.target.ElementCSS', {
  * @extends Ext.fx.target.CompositeElement
  * 
  * This class represents a animation target for a {@link Ext.CompositeElement}, where the
- * constituent elements support CSS based animation. It allows each {@link Ext.core.Element} in 
+ * constituent elements support CSS based animation. It allows each {@link Ext.Element} in 
  * the group to be animated as a whole. In general this class will not be created directly, 
  * the {@link Ext.CompositeElement} will be passed to the animation and the appropriate target 
  * will be created.
@@ -61804,23 +64570,7 @@ Ext.define('Ext.fx.target.CompositeElementCSS', {
 /**
  * @class Ext.layout.container.AbstractFit
  * @extends Ext.layout.container.Container
- * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
- * container.  This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.container.Container#layout}
- * config, and should generally not need to be created directly via the new keyword.</p>
- * <p>FitLayout does not have any direct config options (other than inherited ones).  To fit a panel to a container
- * using FitLayout, simply set layout:'fit' on the container and add a single panel to it.  If the container has
- * multiple panels, only the first one will be displayed.  Example usage:</p>
- * <pre><code>
-var p = new Ext.panel.Panel({
-    title: 'Fit Layout',
-    layout:'fit',
-    items: {
-        title: 'Inner Panel',
-        html: '&lt;p&gt;This is the inner panel content&lt;/p&gt;',
-        border: false
-    }
-});
-</code></pre>
+ * @private
  */
 Ext.define('Ext.layout.container.AbstractFit', {
 
@@ -61835,31 +64585,28 @@ Ext.define('Ext.layout.container.AbstractFit', {
     type: 'fit'
 });
 /**
- * @class Ext.layout.container.Fit
- * @extends Ext.layout.container.AbstractFit
- * <p>This is a base class for layouts that contain <b>a single item</b> that automatically expands to fill the layout's
- * container.  This class is intended to be extended or created via the <tt>layout:'fit'</tt> {@link Ext.container.Container#layout}
- * config, and should generally not need to be created directly via the new keyword.</p>
- * <p>FitLayout does not have any direct config options (other than inherited ones).  To fit a panel to a container
- * using FitLayout, simply set layout:'fit' on the container and add a single panel to it.  If the container has
- * multiple panels, only the first one will be displayed.  
- * {@img Ext.layout.container.Fit/Ext.layout.container.Fit.png Ext.layout.container.Fit container layout}
- * Example usage:</p>
- * <pre><code>
-    Ext.create('Ext.panel.Panel', {
-        title: 'Fit Layout',
-        width: 300,
-        height: 150,
-        layout:'fit',
-        items: {
-            title: 'Inner Panel',
-            html: 'This is the inner panel content',
-            bodyPadding: 20,
-            border: false
-        },
-        renderTo: Ext.getBody()
-    });  
-</code></pre>
+ * This is a base class for layouts that contain **a single item** that automatically expands to fill the layout's
+ * container. This class is intended to be extended or created via the `layout: 'fit'`
+ * {@link Ext.container.Container#layout} config, and should generally not need to be created directly via the new keyword.
+ *
+ * Fit layout does not have any direct config options (other than inherited ones). To fit a panel to a container using
+ * Fit layout, simply set `layout: 'fit'` on the container and add a single panel to it. If the container has multiple
+ * panels, only the first one will be displayed.
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Fit Layout',
+ *         width: 300,
+ *         height: 150,
+ *         layout:'fit',
+ *         items: {
+ *             title: 'Inner Panel',
+ *             html: 'This is the inner panel content',
+ *             bodyPadding: 20,
+ *             border: false
+ *         },
+ *         renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.layout.container.Fit', {
 
@@ -61868,16 +64615,67 @@ Ext.define('Ext.layout.container.Fit', {
     extend: 'Ext.layout.container.AbstractFit',
     alias: 'layout.fit',
     alternateClassName: 'Ext.layout.FitLayout',
+    requires: ['Ext.layout.container.Box'],
 
     /* End Definitions */
-   
+
+    /**
+     * @cfg {Object} defaultMargins
+     * <p>If the individual contained items do not have a <tt>margins</tt>
+     * property specified or margin specified via CSS, the default margins from this property will be
+     * applied to each item.</p>
+     * <br><p>This property may be specified as an object containing margins
+     * to apply in the format:</p><pre><code>
+{
+    top: (top margin),
+    right: (right margin),
+    bottom: (bottom margin),
+    left: (left margin)
+}</code></pre>
+     * <p>This property may also be specified as a string containing
+     * space-separated, numeric margin values. The order of the sides associated
+     * with each value matches the way CSS processes margin values:</p>
+     * <div class="mdetail-params"><ul>
+     * <li>If there is only one value, it applies to all sides.</li>
+     * <li>If there are two values, the top and bottom borders are set to the
+     * first value and the right and left are set to the second.</li>
+     * <li>If there are three values, the top is set to the first value, the left
+     * and right are set to the second, and the bottom is set to the third.</li>
+     * <li>If there are four values, they apply to the top, right, bottom, and
+     * left, respectively.</li>
+     * </ul></div>
+     * <p>Defaults to:</p><pre><code>
+     * {top:0, right:0, bottom:0, left:0}
+     * </code></pre>
+     */
+    defaultMargins: {
+        top: 0,
+        right: 0,
+        bottom: 0,
+        left: 0
+    },
+
     // @private
     onLayout : function() {
-        var me = this;
+        var me = this,
+            size,
+            item,
+            margins;
         me.callParent();
 
         if (me.owner.items.length) {
-            me.setItemBox(me.owner.items.get(0), me.getLayoutTargetSize());
+            item = me.owner.items.get(0);
+            margins = item.margins || me.defaultMargins;
+            size = me.getLayoutTargetSize();
+            size.width  -= margins.width;
+            size.height -= margins.height;
+            me.setItemBox(item, size);
+
+            // If any margins were configure either through the margins config, or in the CSS style,
+            // Then positioning will be used.
+            if (margins.left || margins.top) {
+                item.setPosition(margins.left, margins.top);
+            }
         }
     },
 
@@ -61907,31 +64705,14 @@ Ext.define('Ext.layout.container.Fit', {
 
         this.callParent(arguments);
     }
+}, function() {
+    // Use Box layout's renderItem which reads CSS margins, and adds them to any configured item margins
+    // (Defaulting to "0 0 0 0")
+    this.prototype.renderItem = Ext.layout.container.Box.prototype.renderItem;
 });
 /**
- * This layout manages multiple child Components, each is fit to the Container, where only a single child Component
- * can be visible at any given time.  This layout style is most commonly used for wizards, tab implementations, etc.
- * This class is intended to be extended or created via the layout:'card' {@link Ext.container.Container#layout} config,
- * and should generally not need to be created directly via the new keyword.
- *
- * The CardLayout's focal method is {@link #setActiveItem}.  Since only one panel is displayed at a time,
- * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
- * the next panel to display.  The layout itself does not provide a user interface for handling this navigation,
- * so that functionality must be provided by the developer.
- *
- * Containers that are configured with a card layout will have a method setActiveItem dynamically added to it.
- *
- *     var p = new Ext.panel.Panel({
- *         fullscreen: true,
- *         layout: 'card',
- *         items: [{
- *             html: 'Card 1'
- *         },{
- *             html: 'Card 2'
- *         }]
- *     });
- *     p.setActiveItem(1);
- *
+ * Abstract base class for {@link Ext.layout.container.Card Card layout}.
+ * @private
  */
 Ext.define('Ext.layout.container.AbstractCard', {
 
@@ -61950,7 +64731,7 @@ Ext.define('Ext.layout.container.AbstractCard', {
     /**
      * @cfg {Boolean} deferredRender
      * True to render each contained item at the time it becomes active, false to render all contained items
-     * as soon as the layout is rendered (defaults to false).  If there is a significant amount of content or
+     * as soon as the layout is rendered.  If there is a significant amount of content or
      * a lot of heavy controls being rendered into panels that are not displayed by default, setting this to
      * true might improve performance.
      */
@@ -61958,7 +64739,7 @@ Ext.define('Ext.layout.container.AbstractCard', {
 
     beforeLayout: function() {
         var me = this;
-        me.activeItem = me.getActiveItem();
+        me.getActiveItem();
         if (me.activeItem && me.deferredRender) {
             me.renderItems([me.activeItem], me.getRenderTarget());
             return true;
@@ -61968,6 +64749,13 @@ Ext.define('Ext.layout.container.AbstractCard', {
         }
     },
 
+    renderChildren: function () {
+        if (!this.deferredRender) {
+            this.getActiveItem();
+            this.callParent();
+        }
+    },
+
     onLayout: function() {
         var me = this,
             activeItem = me.activeItem,
@@ -62060,7 +64848,7 @@ Ext.define('Ext.layout.container.AbstractCard', {
      * @returns {Ext.Component} The next component or false.
      */
     getNext: function() {
-        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This 
+        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
         //should come back in 4.1
         var wrap = arguments[0];
         var items = this.getLayoutItems(),
@@ -62073,7 +64861,7 @@ Ext.define('Ext.layout.container.AbstractCard', {
      * @return {Ext.Component} the activated component or false when nothing activated.
      */
     next: function() {
-        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This 
+        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
         //should come back in 4.1
         var anim = arguments[0], wrap = arguments[1];
         return this.setActiveItem(this.getNext(wrap), anim);
@@ -62084,7 +64872,7 @@ Ext.define('Ext.layout.container.AbstractCard', {
      * @returns {Ext.Component} The previous component or false.
      */
     getPrev: function() {
-        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This 
+        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
         //should come back in 4.1
         var wrap = arguments[0];
         var items = this.getLayoutItems(),
@@ -62097,7 +64885,7 @@ Ext.define('Ext.layout.container.AbstractCard', {
      * @return {Ext.Component} the activated component or false when nothing activated.
      */
     prev: function() {
-        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This 
+        //NOTE: Removed the JSDoc for this function's arguments because it is not actually supported in 4.0. This
         //should come back in 4.1
         var anim = arguments[0], wrap = arguments[1];
         return this.setActiveItem(this.getPrev(wrap), anim);
@@ -62105,19 +64893,14 @@ Ext.define('Ext.layout.container.AbstractCard', {
 });
 
 /**
- * @class Ext.selection.Model
- * @extends Ext.util.Observable
+ * Tracks what records are currently selected in a databound component.
  *
- * Tracks what records are currently selected in a databound widget.
+ * This is an abstract class and is not meant to be directly used. Databound UI widgets such as
+ * {@link Ext.grid.Panel Grid} and {@link Ext.tree.Panel Tree} should subclass Ext.selection.Model
+ * and provide a way to binding to the component.
  *
- * This is an abstract class and is not meant to be directly used.
- *
- * DataBound UI widgets such as GridPanel, TreePanel, and ListView
- * should subclass AbstractStoreSelectionModel and provide a way
- * to binding to the component.
- *
- * The abstract methods onSelectChange and onLastFocusChanged should
- * be implemented in these subclasses to update the UI widget.
+ * The abstract methods `onSelectChange` and `onLastFocusChanged` should be implemented in these
+ * subclasses to update the UI widget.
  */
 Ext.define('Ext.selection.Model', {
     extend: 'Ext.util.Observable',
@@ -62127,24 +64910,28 @@ Ext.define('Ext.selection.Model', {
 
     /**
      * @cfg {String} mode
-     * Modes of selection.
-     * Valid values are SINGLE, SIMPLE, and MULTI. Defaults to 'SINGLE'
+     * Mode of selection.  Valid values are:
+     *
+     * - **SINGLE** - Only allows selecting one item at a time.  Use {@link #allowDeselect} to allow
+     *   deselecting that item.  This is the default.
+     * - **SIMPLE** - Allows simple selection of multiple items one-by-one. Each click in grid will either
+     *   select or deselect an item.
+     * - **MULTI** - Allows complex selection of multiple items using Ctrl and Shift keys.
      */
 
     /**
      * @cfg {Boolean} allowDeselect
-     * Allow users to deselect a record in a DataView, List or Grid. Only applicable when the SelectionModel's mode is 'SINGLE'. Defaults to false.
+     * Allow users to deselect a record in a DataView, List or Grid.
+     * Only applicable when the {@link #mode} is 'SINGLE'.
      */
     allowDeselect: false,
 
     /**
-     * @property selected
-     * READ-ONLY A MixedCollection that maintains all of the currently selected
-     * records.
+     * @property {Ext.util.MixedCollection} selected
+     * A MixedCollection that maintains all of the currently selected records. Read-only.
      */
     selected: null,
 
-
     /**
      * Prune records when they are removed from the store from the selection.
      * This is a private flag. For an example of its usage, take a look at
@@ -62161,12 +64948,12 @@ Ext.define('Ext.selection.Model', {
 
         me.addEvents(
             /**
-             * @event selectionchange
+             * @event
              * Fired after a selection change has occurred
              * @param {Ext.selection.Model} this
-             * @param  {Array} selected The selected records
+             * @param {Ext.data.Model[]} selected The selected records
              */
-             'selectionchange'
+            'selectionchange'
         );
 
         me.modes = {
@@ -62190,7 +64977,7 @@ Ext.define('Ext.selection.Model', {
 
         if(!initial && me.store){
             if(store !== me.store && me.store.autoDestroy){
-                me.store.destroy();
+                me.store.destroyStore();
             }else{
                 me.store.un("add", me.onStoreAdd, me);
                 me.store.un("clear", me.onStoreClear, me);
@@ -62215,8 +65002,8 @@ Ext.define('Ext.selection.Model', {
     },
 
     /**
-     * Select all records in the view.
-     * @param {Boolean} suppressEvent True to suppress any selects event
+     * Selects all records in the view.
+     * @param {Boolean} suppressEvent True to suppress any select events
      */
     selectAll: function(suppressEvent) {
         var me = this,
@@ -62235,7 +65022,7 @@ Ext.define('Ext.selection.Model', {
     },
 
     /**
-     * Deselect all records in the view.
+     * Deselects all records in the view.
      * @param {Boolean} suppressEvent True to suppress any deselect events
      */
     deselectAll: function(suppressEvent) {
@@ -62298,7 +65085,7 @@ Ext.define('Ext.selection.Model', {
      * All rows in between startRow and endRow are also selected.
      * @param {Ext.data.Model/Number} startRow The record or index of the first row in the range
      * @param {Ext.data.Model/Number} endRow The record or index of the last row in the range
-     * @param {Boolean} keepExisting (optional) True to retain existing selections
+     * @param {Boolean} [keepExisting] True to retain existing selections
      */
     selectRange : function(startRow, endRow, keepExisting, dir){
         var me = this,
@@ -62357,18 +65144,21 @@ Ext.define('Ext.selection.Model', {
 
     /**
      * Selects a record instance by record instance or index.
-     * @param {Ext.data.Model/Index} records An array of records or an index
-     * @param {Boolean} keepExisting
-     * @param {Boolean} suppressEvent Set to false to not fire a select event
+     * @param {Ext.data.Model[]/Number} records An array of records or an index
+     * @param {Boolean} [keepExisting] True to retain existing selections
+     * @param {Boolean} [suppressEvent] Set to true to not fire a select event
      */
     select: function(records, keepExisting, suppressEvent) {
-        this.doSelect(records, keepExisting, suppressEvent);
+        // Automatically selecting eg store.first() or store.last() will pass undefined, so that must just return;
+        if (Ext.isDefined(records)) {
+            this.doSelect(records, keepExisting, suppressEvent);
+        }
     },
 
     /**
      * Deselects a record instance by record instance or index.
-     * @param {Ext.data.Model/Index} records An array of records or an index
-     * @param {Boolean} suppressEvent Set to false to not fire a deselect event
+     * @param {Ext.data.Model[]/Number} records An array of records or an index
+     * @param {Boolean} [suppressEvent] Set to true to not fire a deselect event
      */
     deselect: function(records, suppressEvent) {
         this.doDeselect(records, suppressEvent);
@@ -62457,7 +65247,7 @@ Ext.define('Ext.selection.Model', {
         }
 
         len = records.length;
-        
+
         for (; i < len; i++) {
             record = records[i];
             if (me.isSelected(record)) {
@@ -62512,9 +65302,9 @@ Ext.define('Ext.selection.Model', {
     },
 
     /**
-     * @param {Ext.data.Model} record
-     * Set a record as the last focused record. This does NOT mean
+     * Sets a record as the last focused record. This does NOT mean
      * that the record has been selected.
+     * @param {Ext.data.Model} record
      */
     setLastFocused: function(record, supressFocus) {
         var me = this,
@@ -62525,7 +65315,7 @@ Ext.define('Ext.selection.Model', {
 
     /**
      * Determines if this record is currently focused.
-     * @param Ext.data.Record record
+     * @param {Ext.data.Model} record
      */
     isFocused: function(record) {
         return record === this.getLastFocused();
@@ -62554,22 +65344,23 @@ Ext.define('Ext.selection.Model', {
 
     /**
      * Returns an array of the currently selected records.
-     * @return {Array} The selected records
+     * @return {Ext.data.Model[]} The selected records
      */
     getSelection: function() {
         return this.selected.getRange();
     },
 
     /**
-     * Returns the current selectionMode. SINGLE, MULTI or SIMPLE.
-     * @return {String} The selectionMode
+     * Returns the current selectionMode.
+     * @return {String} The selectionMode: 'SINGLE', 'MULTI' or 'SIMPLE'.
      */
     getSelectionMode: function() {
         return this.selectionMode;
     },
 
     /**
-     * Sets the current selectionMode. SINGLE, MULTI or SIMPLE.
+     * Sets the current selectionMode.
+     * @param {String} selModel 'SINGLE', 'MULTI' or 'SIMPLE'.
      */
     setSelectionMode: function(selMode) {
         selMode = selMode ? selMode.toUpperCase() : 'SINGLE';
@@ -62587,17 +65378,16 @@ Ext.define('Ext.selection.Model', {
     },
 
     /**
-     * Locks the current selection and disables any changes from
-     * happening to the selection.
-     * @param {Boolean} locked
+     * Locks the current selection and disables any changes from happening to the selection.
+     * @param {Boolean} locked  True to lock, false to unlock.
      */
     setLocked: function(locked) {
         this.locked = !!locked;
     },
 
     /**
-     * Returns <tt>true</tt> if the specified row is selected.
-     * @param {Record/Number} record The record or index of the record to check
+     * Returns true if the specified row is selected.
+     * @param {Ext.data.Model/Number} record The record or index of the record to check
      * @return {Boolean}
      */
     isSelected: function(record) {
@@ -62703,7 +65493,7 @@ Ext.define('Ext.selection.Model', {
     },
 
     /**
-     * Gets the count of selected records.
+     * Returns the count of selected records.
      * @return {Number} The number of selected records
      */
     getCount: function() {
@@ -62754,7 +65544,7 @@ Ext.define('Ext.selection.DataViewModel', {
     /**
      * @cfg {Boolean} enableKeyNav
      *
-     * Turns on/off keyboard navigation within the DataView. Defaults to true.
+     * Turns on/off keyboard navigation within the DataView.
      */
     enableKeyNav: true,
 
@@ -62889,44 +65679,67 @@ Ext.define('Ext.selection.DataViewModel', {
                 me.fireEvent(eventName, me, record);
             }
         }
+    },
+    
+    destroy: function(){
+        Ext.destroy(this.keyNav);
+        this.callParent();
     }
 });
 
 /**
- * @class Ext.state.CookieProvider
- * @extends Ext.state.Provider
- * A Provider implementation which saves and retrieves state via cookies.
- * The CookieProvider supports the usual cookie options, such as:
- * <ul>
- * <li>{@link #path}</li>
- * <li>{@link #expires}</li>
- * <li>{@link #domain}</li>
- * <li>{@link #secure}</li>
- * </ul>
- <pre><code>
-   var cp = new Ext.state.CookieProvider({
-       path: "/cgi-bin/",
-       expires: new Date(new Date().getTime()+(1000*60*60*24*30)), //30 days
-       domain: "sencha.com"
-   });
-   Ext.state.Manager.setProvider(cp);
- </code></pre>
- * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
- * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
- * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
- * your page is on, but you can specify a sub-domain, or simply the domain itself like 'sencha.com' to include
- * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
- * domain the page is running on including the 'www' like 'www.sencha.com')
- * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
+ * A Provider implementation which saves and retrieves state via cookies. The CookieProvider supports the usual cookie
+ * options, such as:
+ *
+ * - {@link #path}
+ * - {@link #expires}
+ * - {@link #domain}
+ * - {@link #secure}
+ *
+ * Example:
+ *
+ *     Ext.create('Ext.state.CookieProvider', {
+ *         path: "/cgi-bin/",
+ *         expires: new Date(new Date().getTime()+(1000*60*60*24*30)), //30 days
+ *         domain: "sencha.com"
+ *     });
+ *
+ *     Ext.state.Manager.setProvider(cp);
+ *
+ * @constructor
+ * Creates a new CookieProvider.
+ * @param {Object} config (optional) Config object.
+ * @return {Object}
  */
 Ext.define('Ext.state.CookieProvider', {
     extend: 'Ext.state.Provider',
 
+    /**
+     * @cfg {String} path
+     * The path for which the cookie is active. Defaults to root '/' which makes it active for all pages in the site.
+     */
+
+    /**
+     * @cfg {Date} expires
+     * The cookie expiration date. Defaults to 7 days from now.
+     */
+
+    /**
+     * @cfg {String} domain
+     * The domain to save the cookie for. Note that you cannot specify a different domain than your page is on, but you can
+     * specify a sub-domain, or simply the domain itself like 'sencha.com' to include all sub-domains if you need to access
+     * cookies across different sub-domains. Defaults to null which uses the same domain the page is running on including
+     * the 'www' like 'www.sencha.com'.
+     */
+
+    /**
+     * @cfg {Boolean} [secure=false]
+     * True if the site is using SSL
+     */
+
     /**
      * Creates a new CookieProvider.
-     * @param {Object} config (optional) Config object.
+     * @param {Object} [config] Config object.
      */
     constructor : function(config){
         var me = this;
@@ -62937,11 +65750,11 @@ Ext.define('Ext.state.CookieProvider', {
         me.callParent(arguments);
         me.state = me.readCookies();
     },
-    
+
     // private
     set : function(name, value){
         var me = this;
-        
+
         if(typeof value == "undefined" || value === null){
             me.clear(name);
             return;
@@ -62966,7 +65779,7 @@ Ext.define('Ext.state.CookieProvider', {
             matches,
             name,
             value;
-            
+
         while((matches = re.exec(c)) != null){
             name = matches[1];
             value = matches[2];
@@ -62980,7 +65793,7 @@ Ext.define('Ext.state.CookieProvider', {
     // private
     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)) +
@@ -62991,7 +65804,7 @@ Ext.define('Ext.state.CookieProvider', {
     // private
     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)) +
@@ -63074,16 +65887,12 @@ Ext.define('Ext.state.LocalStorageProvider', {
 });
 
 /**
- * @class Ext.util.Point
- * @extends Ext.util.Region
- *
  * Represents a 2D point with x and y properties, useful for comparison and instantiation
  * from an event:
- * <pre><code>
- * var point = Ext.util.Point.fromEvent(e);
- * </code></pre>
+ *
+ *     var point = Ext.util.Point.fromEvent(e);
+ *
  */
-
 Ext.define('Ext.util.Point', {
 
     /* Begin Definitions */
@@ -63095,7 +65904,7 @@ Ext.define('Ext.util.Point', {
          * Returns a new instance of Ext.util.Point base on the pageX / pageY values of the given event
          * @static
          * @param {Event} e The event
-         * @returns Ext.util.Point
+         * @return {Ext.util.Point}
          */
         fromEvent: function(e) {
             e = (e.changedTouches && e.changedTouches.length > 0) ? e.changedTouches[0] : e;
@@ -63105,6 +65914,11 @@ Ext.define('Ext.util.Point', {
 
     /* End Definitions */
 
+    /**
+     * Creates a point from two coordinates.
+     * @param {Number} x X coordinate.
+     * @param {Number} y Y coordinate.
+     */
     constructor: function(x, y) {
         this.callParent([y, x, y, x]);
     },
@@ -63130,8 +65944,7 @@ Ext.define('Ext.util.Point', {
 
     /**
      * Whether the given point is not away from this point within the given threshold amount.
-     * TODO: Rename this isNear.
-     * @param {Ext.util.Point/Object} The point to check with, either an instance
+     * @param {Ext.util.Point/Object} p The point to check with, either an instance
      * of Ext.util.Point or an object with left and top properties
      * @param {Object/Number} threshold Can be either an object with x and y properties or a number
      * @return {Boolean}
@@ -63151,7 +65964,7 @@ Ext.define('Ext.util.Point', {
     /**
      * Compare this point with another point when the x and y values of both points are rounded. E.g:
      * [100.3,199.8] will equals to [100, 200]
-     * @param {Ext.util.Point/Object} The point to compare with, either an instance
+     * @param {Ext.util.Point/Object} The point to compare with, either an instance
      * of Ext.util.Point or an object with x and y properties
      * @return {Boolean}
      */
@@ -63160,20 +65973,253 @@ Ext.define('Ext.util.Point', {
     }
 }, function() {
     /**
-     * Translate this region by the given offset amount. TODO: Either use translate or translateBy!
-     * @param {Ext.util.Offset/Object} offset Object containing the <code>x</code> and <code>y</code> properties.
-     * Or the x value is using the two argument form.
-     * @param {Number} The y value unless using an Offset object.
-     * @return {Ext.util.Region} this This Region
      * @method
+     * Alias for {@link #translateBy}
+     * @alias Ext.util.Region#translateBy
      */
     this.prototype.translate = Ext.util.Region.prototype.translateBy;
 });
 
+/**
+ * @class Ext.LoadMask
+ * <p>A modal, floating Component which may be shown above a specified {@link Ext.core.Element Element}, or a specified
+ * {@link Ext.Component Component} while loading data. When shown, the configured owning Element or Component will
+ * be covered with a modality mask, and the LoadMask's {@link #msg} will be displayed centered, accompanied by a spinner image.</p>
+ * <p>If the {@link #store} config option is specified, the masking will be automatically shown and then hidden synchronized with
+ * the Store's loading process.</p>
+ * <p>Because this is a floating Component, its z-index will be managed by the global {@link Ext.WindowManager ZIndexManager}
+ * object, and upon show, it will place itsef at the top of the hierarchy.</p>
+ * <p>Example usage:</p>
+ * <pre><code>
+// Basic mask:
+var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
+myMask.show();
+</code></pre>
+
+ */
+
+Ext.define('Ext.LoadMask', {
+
+    extend: 'Ext.Component',
+
+    alias: 'widget.loadmask',
+
+    /* Begin Definitions */
+
+    mixins: {
+        floating: 'Ext.util.Floating'
+    },
+
+    uses: ['Ext.data.StoreManager'],
+
+    /* End Definitions */
+
+    /**
+     * @cfg {Ext.data.Store} store
+     * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
+     * hidden on either load success, or load fail.
+     */
+
+    /**
+     * @cfg {String} msg
+     * The text to display in a centered loading message box.
+     */
+    msg : 'Loading...',
+    /**
+     * @cfg {String} [msgCls="x-mask-loading"]
+     * The CSS class to apply to the loading message element.
+     */
+    msgCls : Ext.baseCSSPrefix + 'mask-loading',
+    
+    /**
+     * @cfg {Boolean} useMsg
+     * Whether or not to use a loading message class or simply mask the bound element.
+     */
+    useMsg: true,
+
+    /**
+     * Read-only. True if the mask is currently disabled so that it will not be displayed
+     * @type Boolean
+     */
+    disabled: false,
+
+    baseCls: Ext.baseCSSPrefix + 'mask-msg',
+
+    renderTpl: '<div style="position:relative" class="{msgCls}"></div>',
+
+    // Private. The whole point is that there's a mask.
+    modal: true,
+
+    // Private. Obviously, it's floating.
+    floating: {
+        shadow: 'frame'
+    },
+
+    // Private. Masks are not focusable
+    focusOnToFront: false,
+
+    /**
+     * Creates new LoadMask.
+     * @param {String/HTMLElement/Ext.Element} el The element, element ID, or DOM node you wish to mask.
+     * <p>Also, may be a {@link Ext.Component Component} who's element you wish to mask. If a Component is specified, then
+     * the mask will be automatically sized upon Component resize, the message box will be kept centered,
+     * and the mask only be visible when the Component is.</p>
+     * @param {Object} [config] The config object
+     */
+    constructor : function(el, config) {
+        var me = this;
+
+        // If a Component passed, bind to it.
+        if (el.isComponent) {
+            me.ownerCt = el;
+            me.bindComponent(el);
+        }
+        // Create a dumy Component encapsulating the specified Element
+        else {
+            me.ownerCt = new Ext.Component({
+                el: Ext.get(el),
+                rendered: true,
+                componentLayoutCounter: 1
+            });
+            me.container = el;
+        }
+        me.callParent([config]);
+
+        if (me.store) {
+            me.bindStore(me.store, true);
+        }
+        me.renderData = {
+            msgCls: me.msgCls
+        };
+        me.renderSelectors = {
+            msgEl: 'div'
+        };
+    },
+
+    bindComponent: function(comp) {
+        this.mon(comp, {
+            resize: this.onComponentResize,
+            scope: this
+        });
+    },
+
+    afterRender: function() {
+        this.callParent(arguments);
+        this.container = this.floatParent.getContentTarget();
+    },
+
+    /**
+     * @private
+     * Called when this LoadMask's Component is resized. The toFront method rebases and resizes the modal mask.
+     */
+    onComponentResize: function() {
+        var me = this;
+        if (me.rendered && me.isVisible()) {
+            me.toFront();
+            me.center();
+        }
+    },
+
+    /**
+     * Changes the data store bound to this LoadMask.
+     * @param {Ext.data.Store} store The store to bind to this LoadMask
+     */
+    bindStore : function(store, initial) {
+        var me = this;
+
+        if (!initial && me.store) {
+            me.mun(me.store, {
+                scope: me,
+                beforeload: me.onBeforeLoad,
+                load: me.onLoad,
+                exception: me.onLoad
+            });
+            if (!store) {
+                me.store = null;
+            }
+        }
+        if (store) {
+            store = Ext.data.StoreManager.lookup(store);
+            me.mon(store, {
+                scope: me,
+                beforeload: me.onBeforeLoad,
+                load: me.onLoad,
+                exception: me.onLoad
+            });
+
+        }
+        me.store = store;
+        if (store && store.isLoading()) {
+            me.onBeforeLoad();
+        }
+    },
+
+    onDisable : function() {
+        this.callParent(arguments);
+        if (this.loading) {
+            this.onLoad();
+        }
+    },
+
+    // private
+    onBeforeLoad : function() {
+        var me = this,
+            owner = me.ownerCt || me.floatParent,
+            origin;
+        if (!this.disabled) {
+            // If the owning Component has not been layed out, defer so that the ZIndexManager
+            // gets to read its layed out size when sizing the modal mask
+            if (owner.componentLayoutCounter) {
+                Ext.Component.prototype.show.call(me);
+            } else {
+                // The code below is a 'run-once' interceptor.
+                origin = owner.afterComponentLayout;
+                owner.afterComponentLayout = function() {
+                    owner.afterComponentLayout = origin;
+                    origin.apply(owner, arguments);
+                    if(me.loading) {
+                        Ext.Component.prototype.show.call(me);
+                    }
+                };
+            }
+        }
+    },
+
+    onHide: function(){
+        var me = this;
+        me.callParent(arguments);
+        me.showOnParentShow = true;
+    },
+
+    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();
+        }
+    },
+
+    afterShow: function() {
+        this.callParent(arguments);
+        this.center();
+    },
+
+    // private
+    onLoad : function() {
+        this.loading = false;
+        Ext.Component.prototype.hide.call(this);
+    }
+});
 /**
  * @class Ext.view.AbstractView
  * @extends Ext.Component
  * This is an abstract superclass and should not be used directly. Please see {@link Ext.view.View}.
+ * @private
  */
 Ext.define('Ext.view.AbstractView', {
     extend: 'Ext.Component',
@@ -63197,20 +66243,28 @@ Ext.define('Ext.view.AbstractView', {
     },
 
     /**
-     * @cfg {String/Array/Ext.XTemplate} tpl
-     * @required
+     * @cfg {String/String[]/Ext.XTemplate} tpl (required)
      * The HTML fragment or an array of fragments that will make up the template used by this DataView.  This should
      * be specified in the same format expected by the constructor of {@link Ext.XTemplate}.
      */
     /**
-     * @cfg {Ext.data.Store} store
-     * @required
+     * @cfg {Ext.data.Store} store (required)
      * The {@link Ext.data.Store} to bind this DataView to.
      */
 
     /**
-     * @cfg {String} itemSelector
-     * @required
+     * @cfg {Boolean} deferInitialRefresh
+     * <p>Defaults to <code>true</code> to defer the initial refresh of the view.</p>
+     * <p>This allows the View to execute its render and initial layout more quickly because the process will not be encumbered
+     * by the expensive update of the view structure.</p>
+     * <p><b>Important: </b>Be aware that this will mean that the View's item elements will not be available immediately upon render, so
+     * <i>selection</i> may not take place at render time. To access a View's item elements as soon as possible, use the {@link #viewready} event.
+     * Or set <code>deferInitialrefresh</code> to false, but this will be at the cost of slower rendering.</p>
+     */
+    deferInitialRefresh: true,
+
+    /**
+     * @cfg {String} itemSelector (required)
      * <b>This is a required setting</b>. A simple CSS selector (e.g. <tt>div.some-class</tt> or
      * <tt>span:first-child</tt>) that will be used to determine what nodes this DataView will be
      * working with. The itemSelector is used to map DOM nodes to records. As such, there should
@@ -63225,35 +66279,35 @@ Ext.define('Ext.view.AbstractView', {
     itemCls: Ext.baseCSSPrefix + 'dataview-item',
 
     /**
-     * @cfg {String/Array/Ext.XTemplate} itemTpl
+     * @cfg {String/String[]/Ext.XTemplate} itemTpl
      * The inner portion of the item template to be rendered. Follows an XTemplate
      * structure and will be placed inside of a tpl.
      */
 
     /**
      * @cfg {String} overItemCls
-     * A CSS class to apply to each item in the view on mouseover (defaults to undefined).
+     * A CSS class to apply to each item in the view on mouseover.
      * Ensure {@link #trackOver} is set to `true` to make use of this.
      */
 
     /**
      * @cfg {String} loadingText
-     * A string to display during data load operations (defaults to undefined).  If specified, this text will be
+     * A string to display during data load operations.  If specified, this text will be
      * displayed in a loading div and the view's contents will be cleared while loading, otherwise the view's
      * contents will continue to display normally until the new data is loaded and the contents are replaced.
      */
     loadingText: 'Loading...',
-    
+
     /**
      * @cfg {Boolean/Object} loadMask
      * False to disable a load mask from displaying will the view is loading. This can also be a
-     * {@link Ext.LoadMask} configuration object. Defaults to <tt>true</tt>.
+     * {@link Ext.LoadMask} configuration object.
      */
     loadMask: true,
 
     /**
      * @cfg {String} loadingCls
-     * The CSS class to apply to the loading message element (defaults to Ext.LoadMask.prototype.msgCls "x-mask-loading")
+     * The CSS class to apply to the loading message element. Defaults to Ext.LoadMask.prototype.msgCls "x-mask-loading".
      */
 
     /**
@@ -63268,42 +66322,46 @@ Ext.define('Ext.view.AbstractView', {
      * @cfg {Number} loadingHeight
      * If specified, gives an explicit height for the data view when it is showing the {@link #loadingText},
      * if that is specified. This is useful to prevent the view's height from collapsing to zero when the
-     * loading mask is applied and there are no other contents in the data view. Defaults to undefined.
+     * loading mask is applied and there are no other contents in the data view.
      */
 
     /**
-     * @cfg {String} selectedItemCls
-     * A CSS class to apply to each selected item in the view (defaults to 'x-view-selected').
+     * @cfg {String} [selectedItemCls='x-view-selected']
+     * A CSS class to apply to each selected item in the view.
      */
     selectedItemCls: Ext.baseCSSPrefix + 'item-selected',
 
     /**
      * @cfg {String} emptyText
-     * The text to display in the view when there is no data to display (defaults to '').
+     * The text to display in the view when there is no data to display.
      * Note that when using local data the emptyText will not be displayed unless you set
      * the {@link #deferEmptyText} option to false.
      */
     emptyText: "",
 
     /**
-     * @cfg {Boolean} deferEmptyText True to defer emptyText being applied until the store's first load
+     * @cfg {Boolean} deferEmptyText
+     * True to defer emptyText being applied until the store's first load.
      */
     deferEmptyText: true,
 
     /**
-     * @cfg {Boolean} trackOver True to enable mouseenter and mouseleave events
+     * @cfg {Boolean} trackOver
+     * True to enable mouseenter and mouseleave events
      */
     trackOver: false,
 
     /**
-     * @cfg {Boolean} blockRefresh Set this to true to ignore datachanged events on the bound store. This is useful if
-     * you wish to provide custom transition animations via a plugin (defaults to false)
+     * @cfg {Boolean} blockRefresh
+     * Set this to true to ignore datachanged events on the bound store. This is useful if
+     * you wish to provide custom transition animations via a plugin
      */
     blockRefresh: false,
 
     /**
-     * @cfg {Boolean} disableSelection <p><tt>true</tt> to disable selection within the DataView. Defaults to <tt>false</tt>.
-     * This configuration will lock the selection model that the DataView uses.</p>
+     * @cfg {Boolean} disableSelection
+     * True to disable selection within the DataView. This configuration will lock the selection model
+     * that the DataView uses.
      */
 
 
@@ -63397,6 +66455,14 @@ Ext.define('Ext.view.AbstractView', {
              * @param {Ext.view.View} this The DataView object
              */
             'refresh',
+            /**
+             * @event viewready
+             * Fires when the View's item elements representing Store items has been rendered. If the {@link #deferInitialRefresh} flag
+             * was set (and it is <code>true</code> by default), this will be <b>after</b> initial render, and no items will be available
+             * for selection until this event fires.
+             * @param {Ext.view.View} this
+             */
+            'viewready',
             /**
              * @event itemupdate
              * Fires when the node associated with an individual record is updated
@@ -63408,9 +66474,9 @@ Ext.define('Ext.view.AbstractView', {
             /**
              * @event itemadd
              * Fires when the nodes associated with an recordset have been added to the underlying store
-             * @param {Array[Ext.data.Model]} records The model instance
+             * @param {Ext.data.Model[]} records The model instance
              * @param {Number} index The index at which the set of record/nodes starts
-             * @param {Array[HTMLElement]} node The node that has just been updated
+             * @param {HTMLElement[]} node The node that has just been updated
              */
             'itemadd',
             /**
@@ -63424,9 +66490,8 @@ Ext.define('Ext.view.AbstractView', {
 
         me.addCmpEvents();
 
-        if (me.store) {
-            me.store = Ext.data.StoreManager.lookup(me.store);
-        }
+        // Look up the configured Store. If none configured, use the fieldless, empty Store defined in Ext.data.Store.
+        me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
         me.all = new Ext.CompositeElementLite();
     },
 
@@ -63442,7 +66507,7 @@ Ext.define('Ext.view.AbstractView', {
         me.callParent(arguments);
 
         if (mask) {
-            // either a config object 
+            // either a config object
             if (Ext.isObject(mask)) {
                 cfg = Ext.apply(cfg, mask);
             }
@@ -63450,7 +66515,7 @@ Ext.define('Ext.view.AbstractView', {
             // If this DataView is floating, then mask this DataView.
             // Otherwise, mask its owning Container (or this, if there *is* no owning Container).
             // LoadMask captures the element upon render.
-            me.loadMask = Ext.create('Ext.LoadMask', me.floating ? me : me.ownerCt || me, cfg);
+            me.loadMask = Ext.create('Ext.LoadMask', me, cfg);
             me.loadMask.on({
                 scope: me,
                 beforeshow: me.onMaskBeforeShow,
@@ -63458,19 +66523,21 @@ Ext.define('Ext.view.AbstractView', {
             });
         }
     },
-    
+
     onMaskBeforeShow: function(){
-        var me = this;
-        me.getSelectionModel().deselectAll();
-        me.all.clear();
-        if (me.loadingHeight) {
-            me.setCalculatedSize(undefined, me.loadingHeight);
+        var loadingHeight = this.loadingHeight;
+        
+        this.getSelectionModel().deselectAll();
+        if (loadingHeight) {
+            this.setCalculatedSize(undefined, loadingHeight);
         }
     },
-    
+
     onMaskHide: function(){
-        if (!this.destroying && this.loadingHeight) {
-            this.setHeight(this.height);
+        var me = this;
+        
+        if (!me.destroying && me.loadingHeight) {
+            me.setHeight(me.height);
         }
     },
 
@@ -63534,7 +66601,7 @@ Ext.define('Ext.view.AbstractView', {
             el,
             records;
 
-        if (!me.rendered) {
+        if (!me.rendered || me.isDestroyed) {
             return;
         }
 
@@ -63557,14 +66624,23 @@ Ext.define('Ext.view.AbstractView', {
         me.selModel.refresh();
         me.hasSkippedEmptyText = true;
         me.fireEvent('refresh', me);
+
+        // Upon first refresh, fire the viewready event.
+        // Reconfiguring the grid "renews" this event.
+        if (!me.viewReady) {
+            // Fire an event when deferred content becomes available.
+            // This supports grid Panel's deferRowRender capability
+            me.viewReady = true;
+            me.fireEvent('viewready', me);
+        }
     },
 
     /**
      * Function which can be overridden to provide custom formatting for each Record that is used by this
      * DataView's {@link #tpl template} to render each node.
-     * @param {Array/Object} data The raw data object that was used to create the Record.
+     * @param {Object/Object[]} data The raw data object that was used to create the Record.
      * @param {Number} recordIndex the index number of the Record being prepared for rendering.
-     * @param {Record} record The Record being prepared for rendering.
+     * @param {Ext.data.Model} record The Record being prepared for rendering.
      * @return {Array/Object} The formatted data in a format expected by the internal {@link #tpl template}'s overwrite() method.
      * (either an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}))
      */
@@ -63582,9 +66658,9 @@ Ext.define('Ext.view.AbstractView', {
      * {@link Ext.XTemplate XTemplate} which uses <tt>'&lt;tpl for="."&gt;'</tt> to iterate over its supplied
      * data object as an Array. However, <i>named</i> properties may be placed into the data object to
      * provide non-repeating data such as headings, totals etc.</p>
-     * @param {Array} records An Array of {@link Ext.data.Model}s to be rendered into the DataView.
+     * @param {Ext.data.Model[]} records An Array of {@link Ext.data.Model}s to be rendered into the DataView.
      * @param {Number} startIndex the index number of the Record being prepared for rendering.
-     * @return {Array} An Array of data objects to be processed by a repeating XTemplate. May also
+     * @return {Object[]} An Array of data objects to be processed by a repeating XTemplate. May also
      * contain <i>named</i> properties.
      */
     collectData : function(records, startIndex){
@@ -63615,14 +66691,15 @@ Ext.define('Ext.view.AbstractView', {
 
         if (index > -1){
             node = me.bufferRender([record], index)[0];
-
-            me.all.replaceElement(index, node, true);
-            me.updateIndexes(index, index);
-
-            // Maintain selection after update
-            // TODO: Move to approriate event handler.
-            me.selModel.refresh();
-            me.fireEvent('itemupdate', record, index, node);
+            // ensure the node actually exists in the DOM
+            if (me.getNode(record)) {
+                me.all.replaceElement(index, node, true);
+                me.updateIndexes(index, index);
+                // Maintain selection after update
+                // TODO: Move to approriate event handler.
+                me.selModel.refresh();
+                me.fireEvent('itemupdate', record, index, node);
+            }
         }
 
     },
@@ -63650,8 +66727,7 @@ Ext.define('Ext.view.AbstractView', {
 
         if (index < all.getCount()) {
             all.item(index).insertSibling(nodes, 'before', true);
-        }
-        else {
+        } else {
             all.last().insertSibling(nodes, 'after', true);
         }
 
@@ -63685,10 +66761,12 @@ Ext.define('Ext.view.AbstractView', {
     // private
     updateIndexes : function(startIndex, endIndex) {
         var ns = this.all.elements,
-            records = this.store.getRange();
+            records = this.store.getRange(),
+            i;
+            
         startIndex = startIndex || 0;
         endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));
-        for(var i = startIndex; i <= endIndex; i++){
+        for(i = startIndex; i <= endIndex; i++){
             ns[i].viewIndex = i;
             ns[i].viewRecordId = records[i].internalId;
             if (!ns[i].boundView) {
@@ -63707,14 +66785,15 @@ Ext.define('Ext.view.AbstractView', {
 
     /**
      * Changes the data store bound to this view and refreshes it.
-     * @param {Store} store The store to bind to this view
+     * @param {Ext.data.Store} store The store to bind to this view
      */
     bindStore : function(store, initial) {
-        var me = this;
+        var me = this,
+            maskStore;
 
         if (!initial && me.store) {
             if (store !== me.store && me.store.autoDestroy) {
-                me.store.destroy();
+                me.store.destroyStore();
             }
             else {
                 me.mun(me.store, {
@@ -63727,7 +66806,8 @@ Ext.define('Ext.view.AbstractView', {
                 });
             }
             if (!store) {
-                if (me.loadMask) {
+                // Ensure we have an instantiated LoadMask before we unbind it.
+                if (me.loadMask && me.loadMask.bindStore) {
                     me.loadMask.bindStore(null);
                 }
                 me.store = null;
@@ -63743,17 +66823,43 @@ Ext.define('Ext.view.AbstractView', {
                 update: me.onUpdate,
                 clear: me.refresh
             });
-            if (me.loadMask) {
-                me.loadMask.bindStore(store);
+            // Ensure we have an instantiated LoadMask before we bind it.
+            if (me.loadMask && me.loadMask.bindStore) {
+                // View's store is a NodeStore, use owning TreePanel's Store
+                if (Ext.Array.contains(store.alias, 'store.node')) {
+                    maskStore = this.ownerCt.store;
+                } else {
+                    maskStore = store;
+                }
+                me.loadMask.bindStore(maskStore);
             }
         }
 
+        // Flag to say that initial refresh has not been performed.
+        // Set here rather than at initialization time, so that a reconfigure with a new store will refire viewready
+        me.viewReady = false;
+
         me.store = store;
         // Bind the store to our selection model
         me.getSelectionModel().bind(store);
 
-        if (store && (!initial || store.getCount())) {
-            me.refresh(true);
+        /*
+         * This code used to have checks for:
+         * if (store && (!initial || store.getCount() || me.emptyText)) {
+         * Instead, just trigger a refresh and let the view itself figure out
+         * what needs to happen. It can cause incorrect display if our store
+         * has no data.
+         */
+        if (store) {
+            if (initial && me.deferInitialRefresh) {
+                Ext.Function.defer(function () {
+                    if (!me.isDestroyed) {
+                        me.refresh(true);
+                    }
+                }, 1);
+            } else {
+                me.refresh(true);
+            }
         }
     },
 
@@ -63787,7 +66893,7 @@ Ext.define('Ext.view.AbstractView', {
 
     /**
      * Gets the currently selected nodes.
-     * @return {Array} An array of HTMLElements
+     * @return {HTMLElement[]} An array of HTMLElements
      */
     getSelectedNodes: function(){
         var nodes   = [],
@@ -63804,8 +66910,8 @@ Ext.define('Ext.view.AbstractView', {
 
     /**
      * Gets an array of the records from an array of nodes
-     * @param {Array} nodes The nodes to evaluate
-     * @return {Array} records The {@link Ext.data.Model} objects
+     * @param {HTMLElement[]} nodes The nodes to evaluate
+     * @return {Ext.data.Model[]} records The {@link Ext.data.Model} objects
      */
     getRecords: function(nodes) {
         var records = [],
@@ -63822,9 +66928,9 @@ Ext.define('Ext.view.AbstractView', {
 
     /**
      * Gets a record from a node
-     * @param {Element/HTMLElement} node The node to evaluate
+     * @param {Ext.Element/HTMLElement} node The node to evaluate
      *
-     * @return {Record} record The {@link Ext.data.Model} object
+     * @return {Ext.data.Model} record The {@link Ext.data.Model} object
      */
     getRecord: function(node){
         return this.store.data.getByKey(Ext.getDom(node).viewRecordId);
@@ -63844,9 +66950,9 @@ Ext.define('Ext.view.AbstractView', {
 
     /**
      * Selects a record instance by record instance or index.
-     * @param {Ext.data.Model/Index} records An array of records or an index
-     * @param {Boolean} keepExisting
-     * @param {Boolean} suppressEvent Set to false to not fire a select event
+     * @param {Ext.data.Model[]/Number} records An array of records or an index
+     * @param {Boolean} [keepExisting] True to keep existing selections
+     * @param {Boolean} [suppressEvent] Set to true to not fire a select event
      */
     select: function(records, keepExisting, suppressEvent) {
         this.selModel.select(records, keepExisting, suppressEvent);
@@ -63854,8 +66960,8 @@ Ext.define('Ext.view.AbstractView', {
 
     /**
      * Deselects a record instance by record instance or index.
-     * @param {Ext.data.Model/Index} records An array of records or an index
-     * @param {Boolean} suppressEvent Set to false to not fire a deselect event
+     * @param {Ext.data.Model[]/Number} records An array of records or an index
+     * @param {Boolean} [suppressEvent] Set to true to not fire a deselect event
      */
     deselect: function(records, suppressEvent) {
         this.selModel.deselect(records, suppressEvent);
@@ -63868,14 +66974,19 @@ Ext.define('Ext.view.AbstractView', {
      * @return {HTMLElement} The node or null if it wasn't found
      */
     getNode : function(nodeInfo) {
+        if (!this.rendered) {
+            return null;
+        }
         if (Ext.isString(nodeInfo)) {
             return document.getElementById(nodeInfo);
-        } else if (Ext.isNumber(nodeInfo)) {
+        }
+        if (Ext.isNumber(nodeInfo)) {
             return this.all.elements[nodeInfo];
-        } else if (nodeInfo instanceof Ext.data.Model) {
+        }
+        if (nodeInfo instanceof Ext.data.Model) {
             return this.getNodeByRecord(nodeInfo);
         }
-        return nodeInfo;
+        return nodeInfo; // already an HTMLElement
     },
 
     /**
@@ -63899,7 +67010,7 @@ Ext.define('Ext.view.AbstractView', {
      * Gets a range nodes.
      * @param {Number} start (optional) The index of the first node in the range
      * @param {Number} end (optional) The index of the last node in the range
-     * @return {Array} An array of nodes
+     * @return {HTMLElement[]} An array of nodes
      */
     getNodes: function(start, end) {
         var ns = this.all.elements,
@@ -63922,7 +67033,7 @@ Ext.define('Ext.view.AbstractView', {
 
     /**
      * Finds the index of the passed node.
-     * @param {HTMLElement/String/Number/Record} nodeInfo An HTMLElement template node, index of a template node, the id of a template node
+     * @param {HTMLElement/String/Number/Ext.data.Model} nodeInfo An HTMLElement template node, index of a template node, the id of a template node
      * or a record associated with a node.
      * @return {Number} The index of the node or -1
      */
@@ -63946,13 +67057,19 @@ Ext.define('Ext.view.AbstractView', {
     // invoked by the selection model to maintain visual UI cues
     onItemSelect: function(record) {
         var node = this.getNode(record);
-        Ext.fly(node).addCls(this.selectedItemCls);
+        
+        if (node) {
+            Ext.fly(node).addCls(this.selectedItemCls);
+        }
     },
 
     // invoked by the selection model to maintain visual UI cues
     onItemDeselect: function(record) {
         var node = this.getNode(record);
-        Ext.fly(node).removeCls(this.selectedItemCls);
+        
+        if (node) {
+            Ext.fly(node).removeCls(this.selectedItemCls);
+        }
     },
 
     getItemSelector: function() {
@@ -63966,19 +67083,19 @@ Ext.define('Ext.view.AbstractView', {
     Ext.deprecate('extjs', '4.0', function() {
         Ext.view.AbstractView.override({
             /**
-             * @cfg {Boolean} multiSelect
+             * @cfg {Boolean} [multiSelect=false]
              * True to allow selection of more than one item at a time, false to allow selection of only a single item
-             * at a time or no selection at all, depending on the value of {@link #singleSelect} (defaults to false).
+             * at a time or no selection at all, depending on the value of {@link #singleSelect}.
              */
             /**
-             * @cfg {Boolean} singleSelect
-             * True to allow selection of exactly one item at a time, false to allow no selection at all (defaults to false).
+             * @cfg {Boolean} [singleSelect=false]
+             * True to allow selection of exactly one item at a time, false to allow no selection at all.
              * Note that if {@link #multiSelect} = true, this value will be ignored.
              */
             /**
-             * @cfg {Boolean} simpleSelect
+             * @cfg {Boolean} [simpleSelect=false]
              * True to enable multiselection by clicking on multiple items without requiring the user to hold Shift or Ctrl,
-             * false to force the user to hold Ctrl or Shift to select more than on item (defaults to false).
+             * false to force the user to hold Ctrl or Shift to select more than on item.
              */
 
             /**
@@ -63994,7 +67111,7 @@ Ext.define('Ext.view.AbstractView', {
 
             /**
              * Gets an array of the selected records
-             * @return {Array} An array of {@link Ext.data.Model} objects
+             * @return {Ext.data.Model[]} An array of {@link Ext.data.Model} objects
              */
             getSelectedRecords : function(){
                 if (Ext.global.console) {
@@ -64037,7 +67154,7 @@ Ext.define('Ext.view.AbstractView', {
  * <li><code>setIconCls(string)</code></li>
  * <li><code>setDisabled(boolean)</code></li>
  * <li><code>setVisible(boolean)</code></li>
- * <li><code>setHandler(function)</code></li></ul>.</p>
+ * <li><code>setHandler(function)</code></li></ul></p>
  * <p>This allows the Action to control its associated Components.</p>
  * Example usage:<br>
  * <pre><code>
@@ -64088,12 +67205,13 @@ Ext.define('Ext.Action', {
     /* End Definitions */
 
     /**
-     * @cfg {String} text The text to set for all components configured by this Action (defaults to '').
+     * @cfg {String} [text='']
+     * The text to set for all components configured by this Action.
      */
     /**
-     * @cfg {String} iconCls
+     * @cfg {String} [iconCls='']
      * The CSS class selector that specifies a background image to be used as the header icon for
-     * all components configured by this Action (defaults to '').
+     * all components configured by this Action.
      * <p>An example of specifying a custom icon class would be something like:
      * </p><pre><code>
 // specify the property in the config for the class:
@@ -64105,22 +67223,26 @@ Ext.define('Ext.Action', {
 </code></pre>
      */
     /**
-     * @cfg {Boolean} disabled True to disable all components configured by this Action, false to enable them (defaults to false).
+     * @cfg {Boolean} [disabled=false]
+     * True to disable all components configured by this Action, false to enable them.
      */
     /**
-     * @cfg {Boolean} hidden True to hide all components configured by this Action, false to show them (defaults to false).
+     * @cfg {Boolean} [hidden=false]
+     * True to hide all components configured by this Action, false to show them.
      */
     /**
-     * @cfg {Function} handler The function that will be invoked by each component tied to this Action
-     * when the component's primary event is triggered (defaults to undefined).
+     * @cfg {Function} handler
+     * The function that will be invoked by each component tied to this Action
+     * when the component's primary event is triggered.
      */
     /**
      * @cfg {String} itemId
      * See {@link Ext.Component}.{@link Ext.Component#itemId itemId}.
      */
     /**
-     * @cfg {Object} scope The scope (<code><b>this</b></code> reference) in which the
-     * <code>{@link #handler}</code> is executed. Defaults to the browser window.
+     * @cfg {Object} scope
+     * The scope (this reference) in which the {@link #handler} is executed.
+     * Defaults to the browser window.
      */
 
     /**
@@ -64194,7 +67316,7 @@ Ext.define('Ext.Action', {
     },
 
     /**
-     * Returns true if the components using this Action are currently disabled, else returns false.  
+     * Returns true if the components using this Action are currently disabled, else returns false.
      */
     isDisabled : function(){
         return this.initialConfig.disabled;
@@ -64258,7 +67380,7 @@ Ext.define('Ext.Action', {
         var items = this.items,
             i = 0,
             len = items.length;
-            
+
         for(; i < len; i++){
             items[i][fnName].apply(items[i], args);
         }
@@ -64279,9 +67401,7 @@ Ext.define('Ext.Action', {
      * Executes this Action manually using the handler function specified in the original config object
      * or the handler function set with <code>{@link #setHandler}</code>.  Any arguments passed to this
      * function will be passed on to the handler function.
-     * @param {Mixed} arg1 (optional) Variable number of arguments passed to the handler function
-     * @param {Mixed} arg2 (optional)
-     * @param {Mixed} etc... (optional)
+     * @param {Object...} args (optional) Variable number of arguments passed to the handler function
      */
     execute : function(){
         this.initialConfig.handler.apply(this.initialConfig.scope || Ext.global, arguments);
@@ -64394,7 +67514,7 @@ Ext.define('Ext.Editor', {
     /**
      * @cfg {Boolean} allowBlur
      * True to {@link #completeEdit complete the editing process} if in edit mode when the
-     * field is blurred. Defaults to <tt>true</tt>.
+     * field is blurred.
      */
     allowBlur: true,
 
@@ -64423,73 +67543,79 @@ autoSize: {
     /**
      * @cfg {Boolean} revertInvalid
      * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
-     * validation fails (defaults to true)
+     * validation fails
      */
     revertInvalid: true,
 
     /**
-     * @cfg {Boolean} ignoreNoChange
+     * @cfg {Boolean} [ignoreNoChange=false]
      * True to skip the edit completion process (no save, no events fired) if the user completes an edit and
-     * the value has not changed (defaults to false).  Applies only to string values - edits for other data types
+     * the value has not changed.  Applies only to string values - edits for other data types
      * will never be ignored.
      */
 
     /**
-     * @cfg {Boolean} hideEl
-     * False to keep the bound element visible while the editor is displayed (defaults to true)
+     * @cfg {Boolean} [hideEl=true]
+     * False to keep the bound element visible while the editor is displayed
      */
 
     /**
-     * @cfg {Mixed} value
-     * The data value of the underlying field (defaults to "")
+     * @cfg {Object} value
+     * The data value of the underlying field
      */
     value : '',
 
     /**
      * @cfg {String} alignment
-     * The position to align to (see {@link Ext.core.Element#alignTo} for more details, defaults to "c-c?").
+     * The position to align to (see {@link Ext.Element#alignTo} for more details).
      */
     alignment: 'c-c?',
 
     /**
-     * @cfg {Array} offsets
-     * The offsets to use when aligning (see {@link Ext.core.Element#alignTo} for more details. Defaults to <tt>[0, 0]</tt>.
+     * @cfg {Number[]} offsets
+     * The offsets to use when aligning (see {@link Ext.Element#alignTo} for more details.
      */
     offsets: [0, 0],
 
     /**
-     * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
-     * for bottom-right shadow (defaults to "frame")
+     * @cfg {Boolean/String} shadow
+     * "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop" for bottom-right shadow.
      */
     shadow : 'frame',
 
     /**
-     * @cfg {Boolean} constrain True to constrain the editor to the viewport
+     * @cfg {Boolean} constrain
+     * True to constrain the editor to the viewport
      */
     constrain : false,
 
     /**
-     * @cfg {Boolean} swallowKeys Handle the keydown/keypress events so they don't propagate (defaults to true)
+     * @cfg {Boolean} swallowKeys
+     * Handle the keydown/keypress events so they don't propagate
      */
     swallowKeys : true,
 
     /**
-     * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed. Defaults to <tt>true</tt>.
+     * @cfg {Boolean} completeOnEnter
+     * True to complete the edit when the enter key is pressed.
      */
     completeOnEnter : true,
 
     /**
-     * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed. Defaults to <tt>true</tt>.
+     * @cfg {Boolean} cancelOnEsc
+     * True to cancel the edit when the escape key is pressed.
      */
     cancelOnEsc : true,
 
     /**
-     * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
+     * @cfg {Boolean} updateEl
+     * True to update the innerHTML of the bound element when the update completes
      */
     updateEl : false,
 
     /**
-     * @cfg {Mixed} parentEl An element to render to. Defaults to the <tt>document.body</tt>.
+     * @cfg {String/HTMLElement/Ext.Element} parentEl
+     * An element to render to. Defaults to the <tt>document.body</tt>.
      */
 
     // private overrides
@@ -64529,43 +67655,45 @@ autoSize: {
              * Fires when editing is initiated, but before the value changes.  Editing can be canceled by returning
              * false from the handler of this event.
              * @param {Ext.Editor} this
-             * @param {Ext.core.Element} boundEl The underlying element bound to this editor
-             * @param {Mixed} value The field value being set
+             * @param {Ext.Element} boundEl The underlying element bound to this editor
+             * @param {Object} value The field value being set
              */
             'beforestartedit',
+
             /**
              * @event startedit
              * Fires when this editor is displayed
              * @param {Ext.Editor} this
-             * @param {Ext.core.Element} boundEl The underlying element bound to this editor
-             * @param {Mixed} value The starting field value
+             * @param {Ext.Element} boundEl The underlying element bound to this editor
+             * @param {Object} value The starting field value
              */
             'startedit',
+
             /**
              * @event beforecomplete
              * Fires after a change has been made to the field, but before the change is reflected in the underlying
              * field.  Saving the change to the field can be canceled by returning false from the handler of this event.
              * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
              * event will not fire since no edit actually occurred.
-             * @param {Editor} this
-             * @param {Mixed} value The current field value
-             * @param {Mixed} startValue The original field value
+             * @param {Ext.Editor} this
+             * @param {Object} value The current field value
+             * @param {Object} startValue The original field value
              */
             'beforecomplete',
             /**
              * @event complete
              * Fires after editing is complete and any changed value has been written to the underlying field.
              * @param {Ext.Editor} this
-             * @param {Mixed} value The current field value
-             * @param {Mixed} startValue The original field value
+             * @param {Object} value The current field value
+             * @param {Object} startValue The original field value
              */
             'complete',
             /**
              * @event canceledit
              * Fires after editing has been canceled and the editor's value has been reset.
              * @param {Ext.Editor} this
-             * @param {Mixed} value The user-entered field value that was discarded
-             * @param {Mixed} startValue The original field value that was set back into the editor after cancel
+             * @param {Object} value The user-entered field value that was discarded
+             * @param {Object} startValue The original field value that was set back into the editor after cancel
              */
             'canceledit',
             /**
@@ -64588,19 +67716,22 @@ autoSize: {
     // private
     onRender : function(ct, position) {
         var me = this,
-            field = me.field;
+            field = me.field,
+            inputEl = field.inputEl;
 
         me.callParent(arguments);
 
         field.render(me.el);
         //field.hide();
         // Ensure the field doesn't get submitted as part of any form
-        field.inputEl.dom.name = '';
-        if (me.swallowKeys) {
-            field.inputEl.swallowEvent([
-                'keypress', // *** Opera
-                'keydown'   // *** all other browsers
-            ]);
+        if (inputEl) {
+            inputEl.dom.name = '';
+            if (me.swallowKeys) {
+                inputEl.swallowEvent([
+                    'keypress', // *** Opera
+                    'keydown'   // *** all other browsers
+                ]);
+            }
         }
     },
 
@@ -64632,7 +67763,7 @@ autoSize: {
 
     /**
      * Starts the editing process and shows the editor.
-     * @param {Mixed} el The element to edit
+     * @param {String/HTMLElement/Ext.Element} el The element to edit
      * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
       * to the innerHTML of el.
      */
@@ -64676,7 +67807,7 @@ autoSize: {
 
     /**
      * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
-     * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
+     * @param {Boolean} [remainVisible=false] Override the default behavior and keep the editor visible after edit
      */
     completeEdit : function(remainVisible) {
         var me = this,
@@ -64730,8 +67861,7 @@ autoSize: {
     /**
      * Cancels the editing process and hides the editor without persisting any changes.  The field value will be
      * reverted to the original starting value.
-     * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
-     * cancel (defaults to false)
+     * @param {Boolean} [remainVisible=false] Override the default behavior and keep the editor visible after cancel
      */
     cancelEdit : function(remainVisible) {
         var me = this,
@@ -64787,7 +67917,7 @@ autoSize: {
 
     /**
      * Sets the data value of the editor
-     * @param {Mixed} value Any valid value supported by the underlying field
+     * @param {Object} value Any valid value supported by the underlying field
      */
     setValue : function(value) {
         this.field.setValue(value);
@@ -64795,7 +67925,7 @@ autoSize: {
 
     /**
      * Gets the data value of the editor
-     * @return {Mixed} The data value
+     * @return {Object} The data value
      */
     getValue : function() {
         return this.field.getValue();
@@ -64862,22 +67992,40 @@ Ext.define('Ext.Img', {
 
 /**
  * @class Ext.Layer
- * @extends Ext.core.Element
- * An extended {@link Ext.core.Element} object that supports a shadow and shim, constrain to viewport and
+ * @extends Ext.Element
+ * An extended {@link Ext.Element} object that supports a shadow and shim, constrain to viewport and
  * automatic maintaining of shadow/shim positions.
- * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
- * @cfg {String/Boolean} shadow True to automatically create an {@link Ext.Shadow}, or a string indicating the
- * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow. (defaults to false)
- * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: 'div', cls: 'x-layer'}).
- * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
- * @cfg {String} cls CSS class to add to the element
- * @cfg {Number} zindex Starting z-index (defaults to 11000)
- * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 4)
- * @cfg {Boolean} useDisplay
+ *
+ * @cfg {Boolean} [shim=true]
+ * False to disable the iframe shim in browsers which need one.
+ *
+ * @cfg {String/Boolean} [shadow=false]
+ * True to automatically create an {@link Ext.Shadow}, or a string indicating the
+ * shadow's display {@link Ext.Shadow#mode}. False to disable the shadow.
+ *
+ * @cfg {Object} [dh={tag: 'div', cls: 'x-layer'}]
+ * DomHelper object config to create element with.
+ *
+ * @cfg {Boolean} [constrain=true]
+ * False to disable constrain to viewport.
+ *
+ * @cfg {String} cls
+ * CSS class to add to the element
+ *
+ * @cfg {Number} [zindex=11000]
+ * Starting z-index.
+ *
+ * @cfg {Number} [shadowOffset=4]
+ * Number of pixels to offset the shadow
+ *
+ * @cfg {Boolean} [useDisplay=false]
  * Defaults to use css offsets to hide the Layer. Specify <tt>true</tt>
  * to use css style <tt>'display:none;'</tt> to hide the Layer.
- * @cfg {String} visibilityCls The CSS class name to add in order to hide this Layer if this layer
+ *
+ * @cfg {String} visibilityCls
+ * The CSS class name to add in order to hide this Layer if this layer
  * is configured with <code>{@link #hideMode}: 'asclass'</code>
+ *
  * @cfg {String} hideMode
  * A String which specifies how this Layer will be hidden.
  * Values may be<div class="mdetail-params"><ul>
@@ -64895,7 +68043,7 @@ Ext.define('Ext.Layer', {
         shims: []
     },
 
-    extend: 'Ext.core.Element',
+    extend: 'Ext.Element',
 
     /**
      * Creates new Layer.
@@ -64906,7 +68054,7 @@ Ext.define('Ext.Layer', {
     constructor: function(config, existingEl) {
         config = config || {};
         var me = this,
-            dh = Ext.core.DomHelper,
+            dh = Ext.DomHelper,
             cp = config.parentEl,
             pel = cp ? Ext.getDom(cp) : document.body,
         hm = config.hideMode;
@@ -64935,14 +68083,14 @@ Ext.define('Ext.Layer', {
         // Otherwise, allow useDisplay to override the default hiding method which is visibility.
         // TODO: Have ExtJS's Element implement visibilityMode by using classes as in Mobile.
         if (hm) {
-            me.setVisibilityMode(Ext.core.Element[hm.toUpperCase()]);
-            if (me.visibilityMode == Ext.core.Element.ASCLASS) {
+            me.setVisibilityMode(Ext.Element[hm.toUpperCase()]);
+            if (me.visibilityMode == Ext.Element.ASCLASS) {
                 me.visibilityCls = config.visibilityCls;
             }
         } else if (config.useDisplay) {
-            me.setVisibilityMode(Ext.core.Element.DISPLAY);
+            me.setVisibilityMode(Ext.Element.DISPLAY);
         } else {
-            me.setVisibilityMode(Ext.core.Element.VISIBILITY);
+            me.setVisibilityMode(Ext.Element.VISIBILITY);
         }
 
         if (config.id) {
@@ -64965,7 +68113,7 @@ Ext.define('Ext.Layer', {
         if (config.hidden === true) {
             me.hide();
         } else {
-            this.show();
+            me.show();
         }
     },
 
@@ -64997,29 +68145,35 @@ Ext.define('Ext.Layer', {
     },
 
     hideShim: function() {
-        if (this.shim) {
-            this.shim.setDisplayed(false);
-            this.self.shims.push(this.shim);
-            delete this.shim;
+        var me = this;
+        
+        if (me.shim) {
+            me.shim.setDisplayed(false);
+            me.self.shims.push(me.shim);
+            delete me.shim;
         }
     },
 
     disableShadow: function() {
-        if (this.shadow) {
-            this.shadowDisabled = true;
-            this.shadow.hide();
-            this.lastShadowOffset = this.shadowOffset;
-            this.shadowOffset = 0;
+        var me = this;
+        
+        if (me.shadow && !me.shadowDisabled) {
+            me.shadowDisabled = true;
+            me.shadow.hide();
+            me.lastShadowOffset = me.shadowOffset;
+            me.shadowOffset = 0;
         }
     },
 
     enableShadow: function(show) {
-        if (this.shadow) {
-            this.shadowDisabled = false;
-            this.shadowOffset = this.lastShadowOffset;
-            delete this.lastShadowOffset;
+        var me = this;
+        
+        if (me.shadow && me.shadowDisabled) {
+            me.shadowDisabled = false;
+            me.shadowOffset = me.lastShadowOffset;
+            delete me.lastShadowOffset;
             if (show) {
-                this.sync(true);
+                me.sync(true);
             }
         }
     },
@@ -65037,17 +68191,17 @@ Ext.define('Ext.Layer', {
             shadow = me.shadow,
             shadowPos, shimStyle, shadowSize;
 
-        if (!this.updating && this.isVisible() && (shadow || this.useShim)) {
-            var shim = this.getShim(),
-                l = this.getLeft(true),
-                t = this.getTop(true),
-                w = this.getWidth(),
-                h = this.getHeight(),
+        if (!me.updating && me.isVisible() && (shadow || me.useShim)) {
+            var shim = me.getShim(),
+                l = me.getLeft(true),
+                t = me.getTop(true),
+                w = me.dom.offsetWidth,
+                h = me.dom.offsetHeight,
                 shimIndex;
 
-            if (shadow && !this.shadowDisabled) {
+            if (shadow && !me.shadowDisabled) {
                 if (doShow && !shadow.isVisible()) {
-                    shadow.show(this);
+                    shadow.show(me);
                 } else {
                     shadow.realign(l, t, w, h);
                 }
@@ -65063,6 +68217,12 @@ Ext.define('Ext.Layer', {
                         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';
@@ -65083,7 +68243,7 @@ Ext.define('Ext.Layer', {
                 shim.setLeftTop(l, t);
             }
         }
-        return this;
+        return me;
     },
 
     remove: function() {
@@ -65113,8 +68273,8 @@ Ext.define('Ext.Layer', {
     // private
     constrainXY: function() {
         if (this.constrain) {
-            var vw = Ext.core.Element.getViewWidth(),
-                vh = Ext.core.Element.getViewHeight(),
+            var vw = Ext.Element.getViewWidth(),
+                vh = Ext.Element.getViewHeight(),
                 s = Ext.getDoc().getScroll(),
                 xy = this.getXY(),
                 x = xy[0],
@@ -65170,13 +68330,13 @@ Ext.define('Ext.Layer', {
 
         // Hide shadow and shim if hiding
         if (!visible) {
-            this.hideUnders(true);
+            me.hideUnders(true);
         }
-        this.callParent([visible, animate, duration, callback, easing]);
+        me.callParent([visible, animate, duration, callback, easing]);
         if (!animate) {
             cb();
         }
-        return this;
+        return me;
     },
 
     // private
@@ -65215,17 +68375,18 @@ Ext.define('Ext.Layer', {
     },
 
     setXY: function(xy, animate, duration, callback, easing) {
-
+        var me = this;
+        
         // Callback will restore shadow state and call the passed callback
-        callback = this.createCB(callback);
+        callback = me.createCB(callback);
 
-        this.fixDisplay();
-        this.beforeAction();
-        this.callParent([xy, animate, duration, callback, easing]);
+        me.fixDisplay();
+        me.beforeAction();
+        me.callParent([xy, animate, duration, callback, easing]);
         if (!animate) {
             callback();
         }
-        return this;
+        return me;
     },
 
     // private
@@ -65256,57 +68417,65 @@ Ext.define('Ext.Layer', {
 
     // overridden Element method
     setSize: function(w, h, animate, duration, callback, easing) {
+        var me = this;
+        
         // Callback will restore shadow state and call the passed callback
-        callback = this.createCB(callback);
+        callback = me.createCB(callback);
 
-        this.beforeAction();
-        this.callParent([w, h, animate, duration, callback, easing]);
+        me.beforeAction();
+        me.callParent([w, h, animate, duration, callback, easing]);
         if (!animate) {
             callback();
         }
-        return this;
+        return me;
     },
 
     // overridden Element method
     setWidth: function(w, animate, duration, callback, easing) {
+        var me = this;
+        
         // Callback will restore shadow state and call the passed callback
-        callback = this.createCB(callback);
+        callback = me.createCB(callback);
 
-        this.beforeAction();
-        this.callParent([w, animate, duration, callback, easing]);
+        me.beforeAction();
+        me.callParent([w, animate, duration, callback, easing]);
         if (!animate) {
             callback();
         }
-        return this;
+        return me;
     },
 
     // overridden Element method
     setHeight: function(h, animate, duration, callback, easing) {
+        var me = this;
+        
         // Callback will restore shadow state and call the passed callback
-        callback = this.createCB(callback);
+        callback = me.createCB(callback);
 
-        this.beforeAction();
-        this.callParent([h, animate, duration, callback, easing]);
+        me.beforeAction();
+        me.callParent([h, animate, duration, callback, easing]);
         if (!animate) {
             callback();
         }
-        return this;
+        return me;
     },
 
     // overridden Element method
     setBounds: function(x, y, width, height, animate, duration, callback, easing) {
+        var me = this;
+        
         // Callback will restore shadow state and call the passed callback
-        callback = this.createCB(callback);
+        callback = me.createCB(callback);
 
-        this.beforeAction();
+        me.beforeAction();
         if (!animate) {
-            Ext.Layer.superclass.setXY.call(this, [x, y]);
-            Ext.Layer.superclass.setSize.call(this, width, height);
+            Ext.Layer.superclass.setXY.call(me, [x, y]);
+            Ext.Layer.superclass.setSize.call(me, width, height);
             callback();
         } else {
-            this.callParent([x, y, width, height, animate, duration, callback, easing]);
+            me.callParent([x, y, width, height, animate, duration, callback, easing]);
         }
-        return this;
+        return me;
     },
 
     /**
@@ -65315,18 +68484,26 @@ Ext.define('Ext.Layer', {
      * <p>Any shim, will be assigned the passed z-index. A shadow will be assigned the next highet z-index, and the Layer's
      * element will receive the highest  z-index.
      * @param {Number} zindex The new z-index to set
-     * @return {this} The Layer
+     * @return {Ext.Layer} The Layer
      */
     setZIndex: function(zindex) {
-        this.zindex = zindex;
-        if (this.getShim()) {
-            this.shim.setStyle('z-index', 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);
+    },
+    
+    setOpacity: function(opacity){
         if (this.shadow) {
-            this.shadow.setZIndex(zindex++);
+            this.shadow.setOpacity(opacity);
         }
-        this.setStyle('z-index', zindex);
-        return this;
+        return this.callParent(arguments);
     }
 });
 
@@ -65362,39 +68539,34 @@ Ext.define('Ext.layout.component.ProgressBar', {
     }
 });
 /**
- * @class Ext.ProgressBar
- * @extends Ext.Component
- * <p>An updateable progress bar component.  The progress bar supports two different modes: manual and automatic.</p>
- * <p>In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the
- * progress bar as needed from your own code.  This method is most appropriate when you want to show progress
- * throughout an operation that has predictable points of interest at which you can update the control.</p>
- * <p>In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it
- * once the operation is complete.  You can optionally have the progress bar wait for a specific amount of time
- * and then clear itself.  Automatic mode is most appropriate for timed operations or asynchronous operations in
- * which you have no need for indicating intermediate progress.</p>
- * {@img Ext.ProgressBar/Ext.ProgressBar.png Ext.ProgressBar component}
- * Example Usage:
-     var p = Ext.create('Ext.ProgressBar', {
-       renderTo: Ext.getBody(),
-       width: 300
-    });
-
-    //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
-    p.wait({
-       interval: 500, //bar will move fast!
-       duration: 50000,
-       increment: 15,
-       text: 'Updating...',
-       scope: this,
-       fn: function(){
-          p.updateText('Done!');
-       }
-    });
- * @cfg {Float} value A floating point value between 0 and 1 (e.g., .5, defaults to 0)
- * @cfg {String} text The progress bar text (defaults to '')
- * @cfg {Mixed} textEl The element to render the progress text to (defaults to the progress
- * bar's internal text element)
- * @cfg {String} id The progress bar element's id (defaults to an auto-generated id)
+ * An updateable progress bar component. The progress bar supports two different modes: manual and automatic.
+ *
+ * In manual mode, you are responsible for showing, updating (via {@link #updateProgress}) and clearing the progress bar
+ * as needed from your own code. This method is most appropriate when you want to show progress throughout an operation
+ * that has predictable points of interest at which you can update the control.
+ *
+ * In automatic mode, you simply call {@link #wait} and let the progress bar run indefinitely, only clearing it once the
+ * operation is complete. You can optionally have the progress bar wait for a specific amount of time and then clear
+ * itself. Automatic mode is most appropriate for timed operations or asynchronous operations in which you have no need
+ * for indicating intermediate progress.
+ *
+ *     @example
+ *     var p = Ext.create('Ext.ProgressBar', {
+ *        renderTo: Ext.getBody(),
+ *        width: 300
+ *     });
+ *
+ *     // Wait for 5 seconds, then update the status el (progress bar will auto-reset)
+ *     p.wait({
+ *         interval: 500, //bar will move fast!
+ *         duration: 50000,
+ *         increment: 15,
+ *         text: 'Updating...',
+ *         scope: this,
+ *         fn: function(){
+ *             p.updateText('Done!');
+ *         }
+ *     });
  */
 Ext.define('Ext.ProgressBar', {
     extend: 'Ext.Component',
@@ -65408,21 +68580,43 @@ Ext.define('Ext.ProgressBar', {
     ],
 
     uses: ['Ext.fx.Anim'],
+
    /**
-    * @cfg {String} baseCls
-    * The base CSS class to apply to the progress bar's wrapper element (defaults to 'x-progress')
+    * @cfg {Number} [value=0]
+    * A floating point value between 0 and 1 (e.g., .5)
+    */
+
+   /**
+    * @cfg {String} [text='']
+    * The progress bar text (defaults to '')
+    */
+
+   /**
+    * @cfg {String/HTMLElement/Ext.Element} textEl
+    * The element to render the progress text to (defaults to the progress bar's internal text element)
+    */
+
+   /**
+    * @cfg {String} id
+    * The progress bar element's id (defaults to an auto-generated id)
+    */
+
+   /**
+    * @cfg {String} [baseCls='x-progress']
+    * The base CSS class to apply to the progress bar's wrapper element.
     */
     baseCls: Ext.baseCSSPrefix + 'progress',
 
     config: {
         /**
         * @cfg {Boolean} animate
-        * True to animate the progress bar during transitions (defaults to false)
+        * True to animate the progress bar during transitions
         */
         animate: false,
 
         /**
-         * @cfg {String} text The text shown in the progress bar (defaults to '')
+         * @cfg {String} text
+         * The text shown in the progress bar
          */
         text: ''
     },
@@ -65434,7 +68628,7 @@ Ext.define('Ext.ProgressBar', {
         '<div class="{baseCls}-text {baseCls}-text-back">',
             '<div>&#160;</div>',
         '</div>',
-        '<div class="{baseCls}-bar">',
+        '<div id="{id}-bar" class="{baseCls}-bar">',
             '<div class="{baseCls}-text">',
                 '<div>&#160;</div>',
             '</div>',
@@ -65447,19 +68641,15 @@ Ext.define('Ext.ProgressBar', {
     initComponent: function() {
         this.callParent();
 
-        this.renderSelectors = Ext.apply(this.renderSelectors || {}, {
-            textTopEl: '.' + this.baseCls + '-text',
-            textBackEl: '.' + this.baseCls + '-text-back',
-            bar: '.' + this.baseCls + '-bar'
-        });
+        this.addChildEls('bar');
 
         this.addEvents(
             /**
              * @event update
              * Fires after each update interval
              * @param {Ext.ProgressBar} this
-             * @param {Number} The current progress value
-             * @param {String} The current progress text
+             * @param {Number} value The current progress value
+             * @param {String} text The current progress text
              */
             "update"
         );
@@ -65468,9 +68658,11 @@ Ext.define('Ext.ProgressBar', {
     afterRender : function() {
         var me = this;
 
+        // This produces a composite w/2 el's (which is why we cannot use childEls or
+        // renderSelectors):
         me.textEl = me.textEl ? Ext.get(me.textEl) : me.el.select('.' + me.baseCls + '-text');
 
-        this.callParent(arguments);
+        me.callParent(arguments);
 
         if (me.value) {
             me.updateProgress(me.value, me.text);
@@ -65481,54 +68673,63 @@ Ext.define('Ext.ProgressBar', {
     },
 
     /**
-     * Updates the progress bar value, and optionally its text.  If the text argument is not specified,
-     * any existing text value will be unchanged.  To blank out existing text, pass ''.  Note that even
-     * if the progress bar value exceeds 1, it will never automatically reset -- you are responsible for
-     * determining when the progress is complete and calling {@link #reset} to clear and/or hide the control.
-     * @param {Float} value (optional) A floating point value between 0 and 1 (e.g., .5, defaults to 0)
-     * @param {String} text (optional) The string to display in the progress text element (defaults to '')
-     * @param {Boolean} animate (optional) Whether to animate the transition of the progress bar. If this value is
-     * not specified, the default for the class is used (default to false)
+     * Updates the progress bar value, and optionally its text. If the text argument is not specified, any existing text
+     * value will be unchanged. To blank out existing text, pass ''. Note that even if the progress bar value exceeds 1,
+     * it will never automatically reset -- you are responsible for determining when the progress is complete and
+     * calling {@link #reset} to clear and/or hide the control.
+     * @param {Number} [value=0] A floating point value between 0 and 1 (e.g., .5)
+     * @param {String} [text=''] The string to display in the progress text element
+     * @param {Boolean} [animate=false] Whether to animate the transition of the progress bar. If this value is not
+     * specified, the default for the class is used
      * @return {Ext.ProgressBar} this
      */
     updateProgress: function(value, text, animate) {
-        var newWidth;
-        this.value = value || 0;
+        var me = this,
+            newWidth;
+            
+        me.value = value || 0;
         if (text) {
-            this.updateText(text);
+            me.updateText(text);
         }
-        if (this.rendered && !this.isDestroyed) {
-            newWidth = Math.floor(this.value * this.el.getWidth(true));
-            if (Ext.isForcedBorderBox) {
-                newWidth += this.bar.getBorderWidth("lr");
-            }
-            if (animate === true || (animate !== false && this.animate)) {
-                this.bar.stopAnimation();
-                this.bar.animate(Ext.apply({
-                    to: {
-                        width: newWidth + 'px'
-                    }
-                }, this.animate));
+        if (me.rendered && !me.isDestroyed) {
+            if (me.isVisible(true)) {
+                newWidth = Math.floor(me.value * me.el.getWidth(true));
+                if (Ext.isForcedBorderBox) {
+                    newWidth += me.bar.getBorderWidth("lr");
+                }
+                if (animate === true || (animate !== false && me.animate)) {
+                    me.bar.stopAnimation();
+                    me.bar.animate(Ext.apply({
+                        to: {
+                            width: newWidth + 'px'
+                        }
+                    }, me.animate));
+                } else {
+                    me.bar.setWidth(newWidth);
+                }
             } else {
-                this.bar.setWidth(newWidth);
+                // force a layout when we're visible again
+                me.doComponentLayout();
             }
         }
-        this.fireEvent('update', this, this.value, text);
-        return this;
+        me.fireEvent('update', me, me.value, text);
+        return me;
     },
 
     /**
-     * Updates the progress bar text.  If specified, textEl will be updated, otherwise the progress
-     * bar itself will display the updated text.
-     * @param {String} text (optional) The string to display in the progress text element (defaults to '')
+     * Updates the progress bar text. If specified, textEl will be updated, otherwise the progress bar itself will
+     * display the updated text.
+     * @param {String} [text=''] The string to display in the progress text element
      * @return {Ext.ProgressBar} this
      */
     updateText: function(text) {
-        this.text = text;
-        if (this.rendered) {
-            this.textEl.update(this.text);
+        var me = this;
+        
+        me.text = text;
+        if (me.rendered) {
+            me.textEl.update(me.text);
         }
-        return this;
+        return me;
     },
 
     applyText : function(text) {
@@ -65536,91 +68737,87 @@ Ext.define('Ext.ProgressBar', {
     },
 
     /**
-         * Initiates an auto-updating progress bar.  A duration can be specified, in which case the progress
-         * bar will automatically reset after a fixed amount of time and optionally call a callback function
-         * if specified.  If no duration is passed in, then the progress bar will run indefinitely and must
-         * be manually cleared by calling {@link #reset}.  The wait method accepts a config object with
-         * the following properties:
-         * <pre>
-    Property   Type          Description
-    ---------- ------------  ----------------------------------------------------------------------
-    duration   Number        The length of time in milliseconds that the progress bar should
-                             run before resetting itself (defaults to undefined, in which case it
-                             will run indefinitely until reset is called)
-    interval   Number        The length of time in milliseconds between each progress update
-                             (defaults to 1000 ms)
-    animate    Boolean       Whether to animate the transition of the progress bar. If this value is
-                             not specified, the default for the class is used.
-    increment  Number        The number of progress update segments to display within the progress
-                             bar (defaults to 10).  If the bar reaches the end and is still
-                             updating, it will automatically wrap back to the beginning.
-    text       String        Optional text to display in the progress bar element (defaults to '').
-    fn         Function      A callback function to execute after the progress bar finishes auto-
-                             updating.  The function will be called with no arguments.  This function
-                             will be ignored if duration is not specified since in that case the
-                             progress bar can only be stopped programmatically, so any required function
-                             should be called by the same code after it resets the progress bar.
-    scope      Object        The scope that is passed to the callback function (only applies when
-                             duration and fn are both passed).
-    </pre>
-             *
-             * Example usage:
-             * <pre><code>
-    var p = new Ext.ProgressBar({
-       renderTo: 'my-el'
-    });
-
-    //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
-    var p = Ext.create('Ext.ProgressBar', {
-       renderTo: Ext.getBody(),
-       width: 300
-    });
-
-    //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
-    p.wait({
-       interval: 500, //bar will move fast!
-       duration: 50000,
-       increment: 15,
-       text: 'Updating...',
-       scope: this,
-       fn: function(){
-          p.updateText('Done!');
-       }
-    });
-
-    //Or update indefinitely until some async action completes, then reset manually
-    p.wait();
-    myAction.on('complete', function(){
-        p.reset();
-        p.updateText('Done!');
-    });
-    </code></pre>
-         * @param {Object} config (optional) Configuration options
-         * @return {Ext.ProgressBar} this
-         */
+     * Initiates an auto-updating progress bar. A duration can be specified, in which case the progress bar will
+     * automatically reset after a fixed amount of time and optionally call a callback function if specified. If no
+     * duration is passed in, then the progress bar will run indefinitely and must be manually cleared by calling
+     * {@link #reset}.
+     *
+     * Example usage:
+     *
+     *     var p = new Ext.ProgressBar({
+     *        renderTo: 'my-el'
+     *     });
+     *
+     *     //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
+     *     var p = Ext.create('Ext.ProgressBar', {
+     *        renderTo: Ext.getBody(),
+     *        width: 300
+     *     });
+     *
+     *     //Wait for 5 seconds, then update the status el (progress bar will auto-reset)
+     *     p.wait({
+     *        interval: 500, //bar will move fast!
+     *        duration: 50000,
+     *        increment: 15,
+     *        text: 'Updating...',
+     *        scope: this,
+     *        fn: function(){
+     *           p.updateText('Done!');
+     *        }
+     *     });
+     *
+     *     //Or update indefinitely until some async action completes, then reset manually
+     *     p.wait();
+     *     myAction.on('complete', function(){
+     *         p.reset();
+     *         p.updateText('Done!');
+     *     });
+     *
+     * @param {Object} config (optional) Configuration options
+     * @param {Number} config.duration The length of time in milliseconds that the progress bar should
+     * run before resetting itself (defaults to undefined, in which case it will run indefinitely
+     * until reset is called)
+     * @param {Number} config.interval The length of time in milliseconds between each progress update
+     * (defaults to 1000 ms)
+     * @param {Boolean} config.animate Whether to animate the transition of the progress bar. If this
+     * value is not specified, the default for the class is used.
+     * @param {Number} config.increment The number of progress update segments to display within the
+     * progress bar (defaults to 10).  If the bar reaches the end and is still updating, it will
+     * automatically wrap back to the beginning.
+     * @param {String} config.text Optional text to display in the progress bar element (defaults to '').
+     * @param {Function} config.fn A callback function to execute after the progress bar finishes auto-
+     * updating.  The function will be called with no arguments.  This function will be ignored if
+     * duration is not specified since in that case the progress bar can only be stopped programmatically,
+     * so any required function should be called by the same code after it resets the progress bar.
+     * @param {Object} config.scope The scope that is passed to the callback function (only applies when
+     * duration and fn are both passed).
+     * @return {Ext.ProgressBar} this
+     */
     wait: function(o) {
-        if (!this.waitTimer) {
-            var scope = this;
+        var me = this;
+            
+        if (!me.waitTimer) {
+            scope = me;
             o = o || {};
-            this.updateText(o.text);
-            this.waitTimer = Ext.TaskManager.start({
+            me.updateText(o.text);
+            me.waitTimer = Ext.TaskManager.start({
                 run: function(i){
                     var inc = o.increment || 10;
                     i -= 1;
-                    this.updateProgress(((((i+inc)%inc)+1)*(100/inc))*0.01, null, o.animate);
+                    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 || this);
+                        o.fn.apply(o.scope || me);
                     }
-                    this.reset();
+                    me.reset();
                 },
                 scope: scope
             });
         }
-        return this;
+        return me;
     },
 
     /**
@@ -65632,50 +68829,54 @@ Ext.define('Ext.ProgressBar', {
     },
 
     /**
-     * Resets the progress bar value to 0 and text to empty string.  If hide = true, the progress
-     * bar will also be hidden (using the {@link #hideMode} property internally).
-     * @param {Boolean} hide (optional) True to hide the progress bar (defaults to false)
+     * Resets the progress bar value to 0 and text to empty string. If hide = true, the progress bar will also be hidden
+     * (using the {@link #hideMode} property internally).
+     * @param {Boolean} [hide=false] True to hide the progress bar.
      * @return {Ext.ProgressBar} this
      */
     reset: function(hide){
-        this.updateProgress(0);
-        this.clearTimer();
+        var me = this;
+        
+        me.updateProgress(0);
+        me.clearTimer();
         if (hide === true) {
-            this.hide();
+            me.hide();
         }
-        return this;
+        return me;
     },
 
     // private
     clearTimer: function(){
-        if (this.waitTimer) {
-            this.waitTimer.onStop = null; //prevent recursion
-            Ext.TaskManager.stop(this.waitTimer);
-            this.waitTimer = null;
+        var me = this;
+        
+        if (me.waitTimer) {
+            me.waitTimer.onStop = null; //prevent recursion
+            Ext.TaskManager.stop(me.waitTimer);
+            me.waitTimer = null;
         }
     },
 
     onDestroy: function(){
-        this.clearTimer();
-        if (this.rendered) {
-            if (this.textEl.isComposite) {
-                this.textEl.clear();
+        var me = this;
+        
+        me.clearTimer();
+        if (me.rendered) {
+            if (me.textEl.isComposite) {
+                me.textEl.clear();
             }
-            Ext.destroyMembers(this, 'textEl', 'progressBar', 'textTopEl');
+            Ext.destroyMembers(me, 'textEl', 'progressBar');
         }
-        this.callParent();
+        me.callParent();
     }
 });
 
 /**
- * @class Ext.ShadowPool
- * @extends Object
  * Private utility class that manages the internal Shadow cache
  * @private
  */
 Ext.define('Ext.ShadowPool', {
     singleton: true,
-    requires: ['Ext.core.DomHelper'],
+    requires: ['Ext.DomHelper'],
 
     markup: function() {
         if (Ext.supports.CSS3BoxShadow) {
@@ -65708,7 +68909,7 @@ Ext.define('Ext.ShadowPool', {
     pull: function() {
         var sh = this.shadows.shift();
         if (!sh) {
-            sh = Ext.get(Ext.core.DomHelper.insertHtml("beforeBegin", document.body.firstChild, this.markup));
+            sh = Ext.get(Ext.DomHelper.insertHtml("beforeBegin", document.body.firstChild, this.markup));
             sh.autoBoxAdjust = false;
         }
         return sh;
@@ -65739,17 +68940,21 @@ Ext.define('Ext.Shadow', {
      * @param {Object} config (optional) Config object.
      */
     constructor: function(config) {
-        Ext.apply(this, config);
-        if (typeof this.mode != "string") {
-            this.mode = this.defaultMode;
-        }
-        var offset = this.offset,
+        var me = this,
             adjusts = {
                 h: 0
             },
-            rad = Math.floor(this.offset / 2);
-
-        switch (this.mode.toLowerCase()) {
+            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()) {
             // all this hideous nonsense calculates the various offsets for shadows
             case "drop":
                 if (Ext.supports.CSS3BoxShadow) {
@@ -65806,7 +69011,7 @@ Ext.define('Ext.Shadow', {
                     break;
                 }
         }
-        this.adjusts = adjusts;
+        me.adjusts = adjusts;
     },
 
     /**
@@ -65818,8 +69023,8 @@ Ext.define('Ext.Shadow', {
      * </ul></div>
      */
     /**
-     * @cfg {String} offset
-     * The number of pixels to offset the shadow from the element (defaults to <tt>4</tt>)
+     * @cfg {Number} offset
+     * The number of pixels to offset the shadow from the element
      */
     offset: 4,
 
@@ -65828,27 +69033,31 @@ Ext.define('Ext.Shadow', {
 
     /**
      * Displays the shadow under the target element
-     * @param {Mixed} targetEl The id or element under which the shadow should display
+     * @param {String/HTMLElement/Ext.Element} targetEl The id or element under which the shadow should display
      */
     show: function(target) {
+        var me = this,
+            index;
+        
         target = Ext.get(target);
-        if (!this.el) {
-            this.el = Ext.ShadowPool.pull();
-            if (this.el.dom.nextSibling != target.dom) {
-                this.el.insertBefore(target);
+        if (!me.el) {
+            me.el = Ext.ShadowPool.pull();
+            if (me.el.dom.nextSibling != target.dom) {
+                me.el.insertBefore(target);
             }
         }
-        this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10) - 1);
+        index = (parseInt(target.getStyle("z-index"), 10) - 1) || 0;
+        me.el.setStyle("z-index", me.zIndex || index);
         if (Ext.isIE && !Ext.supports.CSS3BoxShadow) {
-            this.el.dom.style.filter = "progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius=" + (this.offset) + ")";
+            me.el.dom.style.filter = "progid:DXImageTransform.Microsoft.alpha(opacity=" + me.opacity + ") progid:DXImageTransform.Microsoft.Blur(pixelradius=" + (me.offset) + ")";
         }
-        this.realign(
+        me.realign(
             target.getLeft(true),
             target.getTop(true),
-            target.getWidth(),
-            target.getHeight()
+            target.dom.offsetWidth,
+            target.dom.offsetHeight
         );
-        this.el.dom.style.display = "block";
+        me.el.dom.style.display = "block";
     },
 
     /**
@@ -65910,10 +69119,12 @@ Ext.define('Ext.Shadow', {
      * Hides this shadow
      */
     hide: function() {
-        if (this.el) {
-            this.el.dom.style.display = "none";
-            Ext.ShadowPool.push(this.el);
-            delete this.el;
+        var me = this;
+        
+        if (me.el) {
+            me.el.dom.style.display = "none";
+            Ext.ShadowPool.push(me.el);
+            delete me.el;
         }
     },
 
@@ -65926,51 +69137,73 @@ Ext.define('Ext.Shadow', {
         if (this.el) {
             this.el.setStyle("z-index", z);
         }
+    },
+    
+    /**
+     * Sets the opacity of the shadow
+     * @param {Number} opacity The opacity
+     */
+    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);
+        }
     }
 });
 /**
- * @class Ext.button.Split
- * @extends Ext.button.Button
- * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
- * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
- * options to the primary button action, but any custom handler can provide the arrowclick implementation.  
- * {@img Ext.button.Split/Ext.button.Split.png Ext.button.Split component}
- * Example usage:
- * <pre><code>
-// display a dropdown menu:
-    Ext.create('Ext.button.Split', {
-        renderTo: 'button-ct', // the container id
-        text: 'Options',
-        handler: optionsHandler, // handle a click on the button itself
-        menu: new Ext.menu.Menu({
-        items: [
-                // these items will render as dropdown menu items when the arrow is clicked:
-                {text: 'Item 1', handler: item1Handler},
-                {text: 'Item 2', handler: item2Handler}
-        ]
-        })
-    });
-
-// Instead of showing a menu, you provide any type of custom
-// functionality you want when the dropdown arrow is clicked:
-    Ext.create('Ext.button.Split', {
-        renderTo: 'button-ct',
-        text: 'Options',
-        handler: optionsHandler,
-        arrowHandler: myCustomHandler
-    });
-</code></pre>
- * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
- * @cfg {String} arrowTooltip The title attribute of the arrow
+ * A split button that provides a built-in dropdown arrow that can fire an event separately from the default click event
+ * of the button. Typically this would be used to display a dropdown menu that provides additional options to the
+ * primary button action, but any custom handler can provide the arrowclick implementation.  Example usage:
+ *
+ *     @example
+ *     // display a dropdown menu:
+ *     Ext.create('Ext.button.Split', {
+ *         renderTo: Ext.getBody(),
+ *         text: 'Options',
+ *         // handle a click on the button itself
+ *         handler: function() {
+ *             alert("The button was clicked");
+ *         },
+ *         menu: new Ext.menu.Menu({
+ *             items: [
+ *                 // these will render as dropdown menu items when the arrow is clicked:
+ *                 {text: 'Item 1', handler: function(){ alert("Item 1 clicked"); }},
+ *                 {text: 'Item 2', handler: function(){ alert("Item 2 clicked"); }}
+ *             ]
+ *         })
+ *     });
+ *
+ * Instead of showing a menu, you can provide any type of custom functionality you want when the dropdown
+ * arrow is clicked:
+ *
+ *     Ext.create('Ext.button.Split', {
+ *         renderTo: 'button-ct',
+ *         text: 'Options',
+ *         handler: optionsHandler,
+ *         arrowHandler: myCustomHandler
+ *     });
+ *
  */
 Ext.define('Ext.button.Split', {
 
     /* Begin Definitions */
-
     alias: 'widget.splitbutton',
 
     extend: 'Ext.button.Button',
     alternateClassName: 'Ext.SplitButton',
+    /* End Definitions */
+    
+    /**
+     * @cfg {Function} arrowHandler
+     * A function called when the arrow button is clicked (can be used instead of click event)
+     */
+    /**
+     * @cfg {String} arrowTooltip
+     * The title attribute of the arrow
+     */
 
     // private
     arrowCls      : 'split',
@@ -65981,14 +69214,14 @@ Ext.define('Ext.button.Split', {
         this.callParent();
         /**
          * @event arrowclick
-         * Fires when this button's arrow is clicked
-         * @param {MenuButton} this
-         * @param {EventObject} e The click event
+         * Fires when this button's arrow is clicked.
+         * @param {Ext.button.Split} this
+         * @param {Event} e The click event
          */
         this.addEvents("arrowclick");
     },
 
-     /**
+    /**
      * Sets this button's arrow click handler.
      * @param {Function} handler The function to call when the arrow is clicked
      * @param {Object} scope (optional) Scope for the function passed above
@@ -66005,56 +69238,44 @@ Ext.define('Ext.button.Split', {
         e.preventDefault();
         if (!me.disabled) {
             if (me.overMenuTrigger) {
-                if (me.menu && !me.menu.isVisible() && !me.ignoreNextClick) {
-                    me.showMenu();
-                }
+                me.maybeShowMenu();
                 me.fireEvent("arrowclick", me, e);
                 if (me.arrowHandler) {
                     me.arrowHandler.call(me.scope || me, me, e);
                 }
             } else {
-                if (me.enableToggle) {
-                    me.toggle();
-                }
-                me.fireEvent("click", me, e);
-                if (me.handler) {
-                    me.handler.call(me.scope || me, me, e);
-                }
-                me.onBlur();
+                me.doToggle();
+                me.fireHandler();
             }
         }
     }
 });
 /**
- * @class Ext.button.Cycle
- * @extends Ext.button.Split
- * A specialized SplitButton that contains a menu of {@link Ext.menu.CheckItem} elements.  The button automatically
+ * A specialized SplitButton that contains a menu of {@link Ext.menu.CheckItem} elements. The button automatically
  * cycles through each menu item on click, raising the button's {@link #change} event (or calling the button's
  * {@link #changeHandler} function, if supplied) for the active menu item. Clicking on the arrow section of the
- * button displays the dropdown menu just like a normal SplitButton.  
- * {@img Ext.button.Cycle/Ext.button.Cycle.png Ext.button.Cycle component}
- * Example usage:
- * <pre><code>
-Ext.create('Ext.button.Cycle', {
-    showText: true,
-    prependText: 'View as ',
-    renderTo: Ext.getBody(),
-    menu: {
-        id: 'view-type-menu',
-        items: [{
-            text:'text only',
-            iconCls:'view-text',
-            checked:true
-        },{
-            text:'HTML',
-            iconCls:'view-html'
-        }]
-    },
-    changeHandler:function(cycleBtn, activeItem){
-        Ext.Msg.alert('Change View', activeItem.text);
-    }
-});
-</code></pre>
+ * button displays the dropdown menu just like a normal SplitButton.  Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.button.Cycle', {
+ *         showText: true,
+ *         prependText: 'View as ',
+ *         renderTo: Ext.getBody(),
+ *         menu: {
+ *             id: 'view-type-menu',
+ *             items: [{
+ *                 text: 'text only',
+ *                 iconCls: 'view-text',
+ *                 checked: true
+ *             },{
+ *                 text: 'HTML',
+ *                 iconCls: 'view-html'
+ *             }]
+ *         },
+ *         changeHandler: function(cycleBtn, activeItem) {
+ *             Ext.Msg.alert('Change View', activeItem.text);
+ *         }
+ *     });
  */
 Ext.define('Ext.button.Cycle', {
 
@@ -66068,34 +69289,40 @@ Ext.define('Ext.button.Cycle', {
     /* End Definitions */
 
     /**
-     * @cfg {Array} items <p>Deprecated as of 4.0. Use the {@link #menu} config instead. All menu items will be created
-     * as {@link Ext.menu.CheckItem CheckItem}s.</p>
-     * <p>An array of {@link Ext.menu.CheckItem} <b>config</b> objects to be used when creating the
-     * button's menu items (e.g., {text:'Foo', iconCls:'foo-icon'})
+     * @cfg {Object[]} items
+     * An array of {@link Ext.menu.CheckItem} **config** objects to be used when creating the button's menu items (e.g.,
+     * `{text:'Foo', iconCls:'foo-icon'}`)
+     * 
+     * @deprecated 4.0 Use the {@link #menu} config instead. All menu items will be created as
+     * {@link Ext.menu.CheckItem CheckItems}.
      */
     /**
-     * @cfg {Boolean} showText True to display the active item's text as the button text (defaults to false).
-     * The Button will show its configured {@link #text} if this. config is omitted.
+     * @cfg {Boolean} [showText=false]
+     * True to display the active item's text as the button text. The Button will show its
+     * configured {@link #text} if this config is omitted.
      */
     /**
-     * @cfg {String} prependText A static string to prepend before the active item's text when displayed as the
-     * button's text (only applies when showText = true, defaults to '')
+     * @cfg {String} [prependText='']
+     * A static string to prepend before the active item's text when displayed as the button's text (only applies when
+     * showText = true).
      */
     /**
-     * @cfg {Function} changeHandler A callback function that will be invoked each time the active menu
-     * item in the button's menu has changed.  If this callback is not supplied, the SplitButton will instead
-     * fire the {@link #change} event on active item change.  The changeHandler function will be called with the
-     * following argument list: (SplitButton this, Ext.menu.CheckItem item)
+     * @cfg {Function} changeHandler
+     * A callback function that will be invoked each time the active menu item in the button's menu has changed. If this
+     * callback is not supplied, the SplitButton will instead fire the {@link #change} event on active item change. The
+     * changeHandler function will be called with the following argument list: (SplitButton this, Ext.menu.CheckItem
+     * item)
      */
     /**
-     * @cfg {String} forceIcon A css class which sets an image to be used as the static icon for this button.  This
-     * icon will always be displayed regardless of which item is selected in the dropdown list.  This overrides the 
-     * default behavior of changing the button's icon to match the selected item's icon on change.
+     * @cfg {String} forceIcon
+     * A css class which sets an image to be used as the static icon for this button. This icon will always be displayed
+     * regardless of which item is selected in the dropdown list. This overrides the default behavior of changing the
+     * button's icon to match the selected item's icon on change.
      */
     /**
-     * @property menu
-     * @type Menu
-     * The {@link Ext.menu.Menu Menu} object used to display the {@link Ext.menu.CheckItem CheckItems} representing the available choices.
+     * @property {Ext.menu.Menu} menu
+     * The {@link Ext.menu.Menu Menu} object used to display the {@link Ext.menu.CheckItem CheckItems} representing the
+     * available choices.
      */
 
     // private
@@ -66116,7 +69343,7 @@ Ext.define('Ext.button.Cycle', {
     /**
      * Sets the button's active menu item.
      * @param {Ext.menu.CheckItem} item The item to activate
-     * @param {Boolean} suppressEvent True to prevent the button's change event from firing (defaults to false)
+     * @param {Boolean} [suppressEvent=false] True to prevent the button's change event from firing.
      */
     setActiveItem: function(item, suppressEvent) {
         var me = this;
@@ -66162,9 +69389,9 @@ Ext.define('Ext.button.Cycle', {
         me.addEvents(
             /**
              * @event change
-             * Fires after the button's active menu item has changed.  Note that if a {@link #changeHandler} function
-             * is set on this CycleButton, it will be called instead on active item change and this change event will
-             * not be fired.
+             * Fires after the button's active menu item has changed. Note that if a {@link #changeHandler} function is
+             * set on this CycleButton, it will be called instead on active item change and this change event will not
+             * be fired.
              * @param {Ext.button.Cycle} this
              * @param {Ext.menu.CheckItem} item The menu item that was selected
              */
@@ -66217,9 +69444,9 @@ Ext.define('Ext.button.Cycle', {
     },
 
     /**
-     * This is normally called internally on button click, but can be called externally to advance the button's
-     * active item programmatically to the next one in the menu.  If the current item is the last one in the menu
-     * the active item will be set to the first item in the menu.
+     * This is normally called internally on button click, but can be called externally to advance the button's active
+     * item programmatically to the next one in the menu. If the current item is the last one in the menu the active
+     * item will be set to the first item in the menu.
      */
     toggleSelected: function() {
         var me = this,
@@ -66231,48 +69458,46 @@ Ext.define('Ext.button.Cycle', {
     }
 });
 /**
- * @class Ext.container.ButtonGroup
- * @extends Ext.panel.Panel
- * <p>Provides a container for arranging a group of related Buttons in a tabular manner.</p>
- * Example usage:
- * {@img Ext.container.ButtonGroup/Ext.container.ButtonGroup.png Ext.container.ButtonGroup component}
- * <pre><code>
-    Ext.create('Ext.panel.Panel', {
-        title: 'Panel with ButtonGroup',
-        width: 300,
-        height:200,
-        renderTo: document.body,
-        html: 'HTML Panel Content',
-        tbar: [{
-            xtype: 'buttongroup',
-            columns: 3,
-            title: 'Clipboard',
-            items: [{
-                text: 'Paste',
-                scale: 'large',
-                rowspan: 3,
-                iconCls: 'add',
-                iconAlign: 'top',
-                cls: 'x-btn-as-arrow'
-            },{
-                xtype:'splitbutton',
-                text: 'Menu Button',
-                scale: 'large',
-                rowspan: 3,
-                iconCls: 'add',
-                iconAlign: 'top',
-                arrowAlign:'bottom',
-                menu: [{text: 'Menu Item 1'}]
-            },{
-                xtype:'splitbutton', text: 'Cut', iconCls: 'add16', menu: [{text: 'Cut Menu Item'}]
-            },{
-                text: 'Copy', iconCls: 'add16'
-            },{
-                text: 'Format', iconCls: 'add16'
-            }]
-        }]
-    });
- * </code></pre>
+ * Provides a container for arranging a group of related Buttons in a tabular manner.
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Panel with ButtonGroup',
+ *         width: 300,
+ *         height:200,
+ *         renderTo: document.body,
+ *         bodyPadding: 10,
+ *         html: 'HTML Panel Content',
+ *         tbar: [{
+ *             xtype: 'buttongroup',
+ *             columns: 3,
+ *             title: 'Clipboard',
+ *             items: [{
+ *                 text: 'Paste',
+ *                 scale: 'large',
+ *                 rowspan: 3,
+ *                 iconCls: 'add',
+ *                 iconAlign: 'top',
+ *                 cls: 'btn-as-arrow'
+ *             },{
+ *                 xtype:'splitbutton',
+ *                 text: 'Menu Button',
+ *                 scale: 'large',
+ *                 rowspan: 3,
+ *                 iconCls: 'add',
+ *                 iconAlign: 'top',
+ *                 arrowAlign:'bottom',
+ *                 menu: [{ text: 'Menu Item 1' }]
+ *             },{
+ *                 xtype:'splitbutton', text: 'Cut', iconCls: 'add16', menu: [{text: 'Cut Menu Item'}]
+ *             },{
+ *                 text: 'Copy', iconCls: 'add16'
+ *             },{
+ *                 text: 'Format', iconCls: 'add16'
+ *             }]
+ *         }]
+ *     });
+ *
  */
 Ext.define('Ext.container.ButtonGroup', {
     extend: 'Ext.panel.Panel',
@@ -66280,7 +69505,7 @@ Ext.define('Ext.container.ButtonGroup', {
     alternateClassName: 'Ext.ButtonGroup',
 
     /**
-     * @cfg {Number} columns The <tt>columns</tt> configuration property passed to the
+     * @cfg {Number} columns The `columns` configuration property passed to the
      * {@link #layout configured layout manager}. See {@link Ext.layout.container.Table#columns}.
      */
 
@@ -66302,9 +69527,9 @@ Ext.define('Ext.container.ButtonGroup', {
      * @cfg {Boolean} frame  Defaults to <tt>true</tt>.  See {@link Ext.panel.Panel#frame}.
      */
     frame: true,
-    
+
     frameHeader: false,
-    
+
     internalDefaults: {removeMode: 'container', hideParent: true},
 
     initComponent : function(){
@@ -66325,7 +69550,7 @@ Ext.define('Ext.container.ButtonGroup', {
 
     afterLayout: function() {
         var me = this;
-        
+
         me.callParent(arguments);
 
         // Pugly hack for a pugly browser:
@@ -66334,11 +69559,16 @@ Ext.define('Ext.container.ButtonGroup', {
             var t = me.getTargetEl();
             t.setWidth(me.layout.table.offsetWidth + t.getPadding('lr'));
         }
+
+        // IE7 needs a forced repaint to make the top framing div expand to full width
+        if (Ext.isIE7) {
+            me.el.repaint();
+        }
     },
 
     afterRender: function() {
         var me = this;
-        
+
         //we need to add an addition item in here so the ButtonGroup title is centered
         if (me.header) {
             // Header text cannot flex, but must be natural size if it's being centered
@@ -66358,10 +69588,10 @@ Ext.define('Ext.container.ButtonGroup', {
             });
             me.suspendLayout = false;
         }
-        
+
         me.callParent(arguments);
     },
-    
+
     // private
     onBeforeAdd: function(component) {
         if (component.is('button')) {
@@ -66403,75 +69633,72 @@ Ext.define('Ext.container.ButtonGroup', {
 });
 
 /**
- * @class Ext.container.Viewport
- * @extends Ext.container.Container
-
-A specialized container representing the viewable application area (the browser viewport).
-
-The Viewport renders itself to the document body, and automatically sizes itself to the size of
-the browser viewport and manages window resizing. There may only be one Viewport created
-in a page.
-
-Like any {@link Ext.container.Container Container}, a Viewport will only perform sizing and positioning
-on its child Components if you configure it with a {@link #layout}.
-
-A Common layout used with Viewports is {@link Ext.layout.container.Border border layout}, but if the
-required layout is simpler, a different layout should be chosen.
-
-For example, to simply make a single child item occupy all available space, use {@link Ext.layout.container.Fit fit layout}.
-
-To display one "active" item at full size from a choice of several child items, use {@link Ext.layout.container.Card card layout}.
-
-Inner layouts are available by virtue of the fact that all {@link Ext.panel.Panel Panel}s
-added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
-method of any of its child Panels may themselves have a layout.
-
-The Viewport does not provide scrolling, so child Panels within the Viewport should provide
-for scrolling if needed using the {@link #autoScroll} config.
-{@img Ext.container.Viewport/Ext.container.Viewport.png Ext.container.Viewport component}
-An example showing a classic application border layout:
-
-    Ext.create('Ext.container.Viewport', {
-        layout: 'border',
-        renderTo: Ext.getBody(),
-        items: [{
-            region: 'north',
-            html: '<h1 class="x-panel-header">Page Title</h1>',
-            autoHeight: true,
-            border: false,
-            margins: '0 0 5 0'
-        }, {
-            region: 'west',
-            collapsible: true,
-            title: 'Navigation',
-            width: 150
-            // could use a TreePanel or AccordionLayout for navigational items
-        }, {
-            region: 'south',
-            title: 'South Panel',
-            collapsible: true,
-            html: 'Information goes here',
-            split: true,
-            height: 100,
-            minHeight: 100
-        }, {
-            region: 'east',
-            title: 'East Panel',
-            collapsible: true,
-            split: true,
-            width: 150
-        }, {
-            region: 'center',
-            xtype: 'tabpanel', // TabPanel itself has no title
-            activeTab: 0,      // First tab active by default
-            items: {
-                title: 'Default Tab',
-                html: 'The first tab\'s content. Others may be added dynamically'
-            }
-        }]
-    });
-
- * @markdown
+ * A specialized container representing the viewable application area (the browser viewport).
+ *
+ * The Viewport renders itself to the document body, and automatically sizes itself to the size of
+ * the browser viewport and manages window resizing. There may only be one Viewport created
+ * in a page.
+ *
+ * Like any {@link Ext.container.Container Container}, a Viewport will only perform sizing and positioning
+ * on its child Components if you configure it with a {@link #layout}.
+ *
+ * A Common layout used with Viewports is {@link Ext.layout.container.Border border layout}, but if the
+ * required layout is simpler, a different layout should be chosen.
+ *
+ * For example, to simply make a single child item occupy all available space, use
+ * {@link Ext.layout.container.Fit fit layout}.
+ *
+ * To display one "active" item at full size from a choice of several child items, use
+ * {@link Ext.layout.container.Card card layout}.
+ *
+ * Inner layouts are available by virtue of the fact that all {@link Ext.panel.Panel Panel}s
+ * added to the Viewport, either through its {@link #items}, or through the items, or the {@link #add}
+ * method of any of its child Panels may themselves have a layout.
+ *
+ * The Viewport does not provide scrolling, so child Panels within the Viewport should provide
+ * for scrolling if needed using the {@link #autoScroll} config.
+ *
+ * An example showing a classic application border layout:
+ *
+ *     @example
+ *     Ext.create('Ext.container.Viewport', {
+ *         layout: 'border',
+ *         items: [{
+ *             region: 'north',
+ *             html: '<h1 class="x-panel-header">Page Title</h1>',
+ *             autoHeight: true,
+ *             border: false,
+ *             margins: '0 0 5 0'
+ *         }, {
+ *             region: 'west',
+ *             collapsible: true,
+ *             title: 'Navigation',
+ *             width: 150
+ *             // could use a TreePanel or AccordionLayout for navigational items
+ *         }, {
+ *             region: 'south',
+ *             title: 'South Panel',
+ *             collapsible: true,
+ *             html: 'Information goes here',
+ *             split: true,
+ *             height: 100,
+ *             minHeight: 100
+ *         }, {
+ *             region: 'east',
+ *             title: 'East Panel',
+ *             collapsible: true,
+ *             split: true,
+ *             width: 150
+ *         }, {
+ *             region: 'center',
+ *             xtype: 'tabpanel', // TabPanel itself has no title
+ *             activeTab: 0,      // First tab active by default
+ *             items: {
+ *                 title: 'Default Tab',
+ *                 html: 'The first tab\'s content. Others may be added dynamically'
+ *             }
+ *         }]
+ *     });
  */
 Ext.define('Ext.container.Viewport', {
     extend: 'Ext.container.Container',
@@ -66479,48 +69706,69 @@ Ext.define('Ext.container.Viewport', {
     requires: ['Ext.EventManager'],
     alternateClassName: 'Ext.Viewport',
 
-    /*
-     * Privatize config options which, if used, would interfere with the
-     * correct operation of the Viewport as the sole manager of the
-     * layout of the document body.
-     */
+    // Privatize config options which, if used, would interfere with the
+    // correct operation of the Viewport as the sole manager of the
+    // layout of the document body.
+
     /**
-     * @cfg {Mixed} applyTo @hide
+     * @cfg {String/HTMLElement/Ext.Element} applyTo
+     * Not applicable.
      */
+
     /**
-     * @cfg {Boolean} allowDomMove @hide
+     * @cfg {Boolean} allowDomMove
+     * Not applicable.
      */
+
     /**
-     * @cfg {Boolean} hideParent @hide
+     * @cfg {Boolean} hideParent
+     * Not applicable.
      */
+
     /**
-     * @cfg {Mixed} renderTo @hide
+     * @cfg {String/HTMLElement/Ext.Element} renderTo
+     * Not applicable. Always renders to document body.
      */
+
     /**
-     * @cfg {Boolean} hideParent @hide
+     * @cfg {Boolean} hideParent
+     * Not applicable.
      */
+
     /**
-     * @cfg {Number} height @hide
+     * @cfg {Number} height
+     * Not applicable. Sets itself to viewport width.
      */
+
     /**
-     * @cfg {Number} width @hide
+     * @cfg {Number} width
+     * Not applicable. Sets itself to viewport height.
      */
+
     /**
-     * @cfg {Boolean} autoHeight @hide
+     * @cfg {Boolean} autoHeight
+     * Not applicable.
      */
+
     /**
-     * @cfg {Boolean} autoWidth @hide
+     * @cfg {Boolean} autoWidth
+     * Not applicable.
      */
+
     /**
-     * @cfg {Boolean} deferHeight @hide
+     * @cfg {Boolean} deferHeight
+     * Not applicable.
      */
+
     /**
-     * @cfg {Boolean} monitorResize @hide
+     * @cfg {Boolean} monitorResize
+     * Not applicable.
      */
 
     isViewport: true,
 
     ariaRole: 'application',
+
     initComponent : function() {
         var me = this,
             html = Ext.fly(document.body.parentNode),
@@ -66538,8 +69786,8 @@ Ext.define('Ext.container.Viewport', {
         me.allowDomMove = false;
         Ext.EventManager.onWindowResize(me.fireResize, me);
         me.renderTo = me.el;
-        me.width = Ext.core.Element.getViewportWidth();
-        me.height = Ext.core.Element.getViewportHeight();
+        me.width = Ext.Element.getViewportWidth();
+        me.height = Ext.Element.getViewportHeight();
     },
 
     fireResize : function(w, h){
@@ -66572,7 +69820,7 @@ Ext.define('Ext.dd.DDTarget', {
      * Creates new DDTarget.
      * @param {String} id the id of the element that is a drop target
      * @param {String} sGroup the group of related DragDrop objects
-     * @param {object} config an object containing configurable attributes.
+     * @param {Object} config an object containing configurable attributes.
      * Valid properties for DDTarget in addition to those in DragDrop: none.
      */
     constructor: function(id, sGroup, config) {
@@ -66766,16 +70014,14 @@ Ext.define('Ext.dd.DragTracker', {
     },
 
     /**
-     * @property active
-     * @type Boolean
+     * @property {Boolean} active
      * Read-only property indicated whether the user is currently dragging this
      * tracker.
      */
     active: false,
 
     /**
-     * @property dragTarget
-     * @type HtmlElement
+     * @property {HTMLElement} dragTarget
      * <p><b>Only valid during drag operations. Read-only.</b></p>
      * <p>The element being dragged.</p>
      * <p>If the {@link #delegate} option is used, this will be the delegate element which was mousedowned.</p>
@@ -66797,7 +70043,7 @@ Ext.define('Ext.dd.DragTracker', {
      */
 
     /**
-     * @cfg {Ext.util.Region/Element} constrainTo
+     * @cfg {Ext.util.Region/Ext.Element} constrainTo
      * <p>A {@link Ext.util.Region Region} (Or an element from which a Region measurement will be read) which is used to constrain
      * the result of the {@link #getOffset} call.</p>
      * <p>This may be set any time during the DragTracker's lifecycle to set a dynamic constraining region.</p>
@@ -66843,7 +70089,7 @@ Ext.define('Ext.dd.DragTracker', {
              * used, when the mouse enters a delegate element).</p>
              * @param {Object} this
              * @param {Object} e event object
-             * @param {HtmlElement} target The element mouseovered.
+             * @param {HTMLElement} target The element mouseovered.
              */
             'mouseover',
 
@@ -66925,7 +70171,7 @@ Ext.define('Ext.dd.DragTracker', {
 
     /**
      * Initializes the DragTracker on a given element.
-     * @param {Ext.core.Element/HTMLElement} el The element
+     * @param {Ext.Element/HTMLElement} el The element
      */
     initEl: function(el) {
         this.el = Ext.get(el);
@@ -67062,7 +70308,7 @@ Ext.define('Ext.dd.DragTracker', {
             }
         }
 
-        // Returning false from a mousemove listener deactivates 
+        // Returning false from a mousemove listener deactivates
         if (this.fireEvent('mousemove', this, e) === false) {
             this.onMouseUp(e);
         } else {
@@ -67133,6 +70379,7 @@ Ext.define('Ext.dd.DragTracker', {
      * Template method which should be overridden by each DragTracker instance. Called when the user first clicks and
      * holds the mouse button down. Return false to disallow the drag
      * @param {Ext.EventObject} e The event object
+     * @template
      */
     onBeforeStart : function(e) {
 
@@ -67142,6 +70389,7 @@ Ext.define('Ext.dd.DragTracker', {
      * Template method which should be overridden by each DragTracker instance. Called when a drag operation starts
      * (e.g. the user has moved the tracked element beyond the specified tolerance)
      * @param {Ext.EventObject} e The event object
+     * @template
      */
     onStart : function(xy) {
 
@@ -67150,6 +70398,7 @@ Ext.define('Ext.dd.DragTracker', {
     /**
      * Template method which should be overridden by each DragTracker instance. Called whenever a drag has been detected.
      * @param {Ext.EventObject} e The event object
+     * @template
      */
     onDrag : function(e) {
 
@@ -67159,6 +70408,7 @@ Ext.define('Ext.dd.DragTracker', {
      * Template method which should be overridden by each DragTracker instance. Called when a drag operation has been completed
      * (e.g. the user clicked and held the mouse down, dragged the element and then released the mouse button)
      * @param {Ext.EventObject} e The event object
+     * @template
      */
     onEnd : function(e) {
 
@@ -67168,7 +70418,7 @@ Ext.define('Ext.dd.DragTracker', {
      * </p>Returns the drag target. This is usually the DragTracker's encapsulating element.</p>
      * <p>If the {@link #delegate} option is being used, this may be a child element which matches the
      * {@link #delegate} selector.</p>
-     * @return {Ext.core.Element} The element currently being tracked.
+     * @return {Ext.Element} The element currently being tracked.
      */
     getDragTarget : function(){
         return this.dragTarget;
@@ -67176,7 +70426,7 @@ Ext.define('Ext.dd.DragTracker', {
 
     /**
      * @private
-     * @returns {Element} The DragTracker's encapsulating element.
+     * @returns {Ext.Element} The DragTracker's encapsulating element.
      */
     getDragCt : function(){
         return this.el;
@@ -67209,19 +70459,21 @@ Ext.define('Ext.dd.DragTracker', {
     },
 
     /**
-     * <p>Returns the X, Y offset of the current mouse position from the mousedown point.</p>
-     * <p>This method may optionally constrain the real offset values, and returns a point coerced in one
-     * of two modes:</p><ul>
-     * <li><code>point</code><div class="sub-desc">The current mouse position is coerced into the
-     * {@link #constrainRegion}, and the resulting position is returned.</div></li>
-     * <li><code>dragTarget</code><div class="sub-desc">The new {@link Ext.util.Region Region} of the
-     * {@link #getDragTarget dragTarget} is calculated based upon the current mouse position, and then
-     * coerced into the {@link #constrainRegion}. The returned mouse position is then adjusted by the
-     * same delta as was used to coerce the region.</div></li>
-     * </ul>
-     * @param constrainMode {String} Optional. If omitted the true mouse position is returned. May be passed
-     * as <code>'point'</code> or <code>'dragTarget'. See above.</code>.
-     * @returns {Array} The <code>X, Y</code> offset from the mousedown point, optionally constrained.
+     * Returns the X, Y offset of the current mouse position from the mousedown point.
+     *
+     * This method may optionally constrain the real offset values, and returns a point coerced in one
+     * of two modes:
+     *
+     *  - `point`
+     *    The current mouse position is coerced into the constrainRegion and the resulting position is returned.
+     *  - `dragTarget`
+     *    The new {@link Ext.util.Region Region} of the {@link #getDragTarget dragTarget} is calculated
+     *    based upon the current mouse position, and then coerced into the constrainRegion. The returned
+     *    mouse position is then adjusted by the same delta as was used to coerce the region.\
+     *
+     * @param constrainMode {String} (Optional) If omitted the true mouse position is returned. May be passed
+     * as `point` or `dragTarget`. See above.
+     * @returns {Number[]} The `X, Y` offset from the mousedown point, optionally constrained.
      */
     getOffset : function(constrain){
         var xy = this.getXY(constrain),
@@ -67347,7 +70599,7 @@ Ext.define('Ext.dd.DragZone', {
 
     /**
      * Creates new DragZone.
-     * @param {Mixed} el The container element
+     * @param {String/HTMLElement/Ext.Element} el The container element or ID of it.
      * @param {Object} config
      */
     constructor : function(el, config){
@@ -67375,7 +70627,7 @@ Ext.define('Ext.dd.DragZone', {
      * for a valid target to drag based on the mouse down. Override this method
      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
-     * @param {EventObject} e The mouse down event
+     * @param {Event} e The mouse down event
      * @return {Object} The dragData
      */
     getDragData : function(e){
@@ -67409,11 +70661,11 @@ Ext.define('Ext.dd.DragZone', {
     /**
      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
      * the XY of this.dragData.ddel
-     * @param {EventObject} e The mouse up event
-     * @return {Array} The xy location (e.g. [100, 200])
+     * @param {Event} e The mouse up event
+     * @return {Number[]} The xy location (e.g. [100, 200])
      */
     getRepairXY : function(e){
-        return Ext.core.Element.fly(this.dragData.ddel).getXY();
+        return Ext.Element.fly(this.dragData.ddel).getXY();
     },
 
     destroy : function(){
@@ -67441,7 +70693,7 @@ el.ddScrollConfig = {
 };
 Ext.dd.ScrollManager.register(el);
 </code></pre>
- * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
+ * Note: This class is designed to be used in "Point Mode
  * @singleton
  */
 Ext.define('Ext.dd.ScrollManager', {
@@ -67561,7 +70813,8 @@ Ext.define('Ext.dd.ScrollManager', {
 
     /**
      * Registers new overflow element(s) to auto scroll
-     * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either
+     * @param {String/HTMLElement/Ext.Element/String[]/HTMLElement[]/Ext.Element[]} el
+     * The id of or the element to be scrolled or an array of either
      */
     register : function(el){
         if (Ext.isArray(el)) {
@@ -67576,7 +70829,8 @@ Ext.define('Ext.dd.ScrollManager', {
 
     /**
      * Unregisters overflow element(s) so they are no longer scrolled
-     * @param {Mixed/Array} el The id of or the element to be removed or an array of either
+     * @param {String/HTMLElement/Ext.Element/String[]/HTMLElement[]/Ext.Element[]} el
+     * The id of or the element to be removed or an array of either
      */
     unregister : function(el){
         if(Ext.isArray(el)){
@@ -67591,44 +70845,43 @@ Ext.define('Ext.dd.ScrollManager', {
 
     /**
      * The number of pixels from the top or bottom edge of a container the pointer needs to be to
-     * trigger scrolling (defaults to 25)
+     * trigger scrolling
      * @type Number
      */
     vthresh : 25,
     /**
      * The number of pixels from the right or left edge of a container the pointer needs to be to
-     * trigger scrolling (defaults to 25)
+     * trigger scrolling
      * @type Number
      */
     hthresh : 25,
 
     /**
-     * The number of pixels to scroll in each scroll increment (defaults to 100)
+     * The number of pixels to scroll in each scroll increment
      * @type Number
      */
     increment : 100,
 
     /**
-     * The frequency of scrolls in milliseconds (defaults to 500)
+     * The frequency of scrolls in milliseconds
      * @type Number
      */
     frequency : 500,
 
     /**
-     * True to animate the scroll (defaults to true)
+     * True to animate the scroll
      * @type Boolean
      */
     animate: true,
 
     /**
-     * The animation duration in seconds -
-     * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4)
+     * The animation duration in seconds - MUST BE less than Ext.dd.ScrollManager.frequency!
      * @type Number
      */
     animDuration: 0.4,
 
     /**
-     * The named drag drop {@link Ext.dd.DragSource#ddGroup group} to which this container belongs (defaults to undefined).
+     * The named drag drop {@link Ext.dd.DragSource#ddGroup group} to which this container belongs.
      * If a ddGroup is specified, then container scrolling will only occur when a dragged object is in the same ddGroup.
      * @type String
      */
@@ -67660,7 +70913,7 @@ Ext.define('Ext.dd.DropTarget', {
 
     /**
      * Creates new DropTarget.
-     * @param {Mixed} el The container element
+     * @param {String/HTMLElement/Ext.Element} el The container element or ID of it.
      * @param {Object} config
      */
     constructor : function(el, config){
@@ -67679,20 +70932,20 @@ Ext.define('Ext.dd.DropTarget', {
     /**
      * @cfg {String} ddGroup
      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only
-     * interact with other drag drop objects in the same group (defaults to undefined).
+     * interact with other drag drop objects in the same group.
      */
     /**
-     * @cfg {String} overClass
-     * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
+     * @cfg {String} [overClass=""]
+     * The CSS class applied to the drop target element while the drag source is over it.
      */
     /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+     * @cfg {String} [dropAllowed="x-dd-drop-ok"]
+     * The CSS class returned to the drag source when drop is allowed.
      */
     dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',
     /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
+     * @cfg {String} [dropNotAllowed="x-dd-drop-nodrop"]
+     * The CSS class returned to the drag source when drop is not allowed.
      */
     dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',
 
@@ -68270,7 +71523,7 @@ Ext.define('Ext.flash.Component', {
 
     /**
      * @property swf
-     * @type {Ext.core.Element}
+     * @type {Ext.Element}
      * A reference to the object or embed element into which the SWF file is loaded. Only
      * populated after the component is rendered and the SWF has been successfully embedded.
      */
@@ -68441,7 +71694,7 @@ Ext.define('Ext.form.action.Action', {
 
     /**
      * @cfg {Object} headers <p>Extra headers to be sent in the AJAX request for submit and load actions. See
-     * {@link Ext.data.Connection#headers}.</p>
+     * {@link Ext.data.proxy.Ajax#headers}.</p>
      */
 
     /**
@@ -68490,7 +71743,7 @@ Ext.define('Ext.form.action.Action', {
      * @cfg {Boolean} submitEmptyText If set to <tt>true</tt>, the emptyText value will be sent with the form
      * when it is submitted. Defaults to <tt>true</tt>.
      */
-
+    submitEmptyText : true,
     /**
      * @property type
      * The type of action this Action instance performs.
@@ -68737,7 +71990,7 @@ buttons: [{
  * <p>Other data may be placed into the response for processing by the {@link Ext.form.Basic}'s callback
  * or event handler methods. The object decoded from this JSON is available in the
  * {@link Ext.form.action.Action#result result} property.</p>
- * <p>Alternatively, if an {@link #errorReader} is specified as an {@link Ext.data.reader.Xml XmlReader}:</p><pre><code>
+ * <p>Alternatively, if an {@link Ext.form.Basic#errorReader errorReader} is specified as an {@link Ext.data.reader.Xml XmlReader}:</p><pre><code>
     errorReader: new Ext.data.reader.Xml({
             record : 'field',
             success: '@success'
@@ -68762,7 +72015,8 @@ buttons: [{
 &lt;/message&gt;
 </code></pre>
  * <p>Other elements may be placed into the response XML for processing by the {@link Ext.form.Basic}'s callback
- * or event handler methods. The XML document is available in the {@link #errorReader}'s {@link Ext.data.reader.Xml#xmlData xmlData} property.</p>
+ * or event handler methods. The XML document is available in the {@link Ext.form.Basic#errorReader errorReader}'s
+ * {@link Ext.data.reader.Xml#xmlData xmlData} property.</p>
  */
 Ext.define('Ext.form.action.Submit', {
     extend:'Ext.form.action.Action',
@@ -68772,7 +72026,7 @@ Ext.define('Ext.form.action.Submit', {
     type: 'submit',
 
     /**
-     * @cfg {boolean} clientValidation Determines whether a Form's fields are validated
+     * @cfg {Boolean} clientValidation Determines whether a Form's fields are validated
      * in a final call to {@link Ext.form.Basic#isValid isValid} prior to submission.
      * Pass <tt>false</tt> in the Form's submit options to prevent this. Defaults to true.
      */
@@ -68885,7 +72139,7 @@ Ext.define('Ext.form.action.Submit', {
         }
 
         // Create the form
-        formEl = Ext.core.DomHelper.append(Ext.getBody(), formSpec);
+        formEl = Ext.DomHelper.append(Ext.getBody(), formSpec);
 
         // Special handling for file upload fields: since browser security measures prevent setting
         // their values programatically, and prevent carrying their selected values over when cloning,
@@ -68952,7 +72206,7 @@ Ext.define('Ext.form.action.Submit', {
  * <p>A subclass of Ext.dd.DragTracker which handles dragging any Component.</p>
  * <p>This is configured with a Component to be made draggable, and a config object for the
  * {@link Ext.dd.DragTracker} class.</p>
- * <p>A {@link #} delegate may be provided which may be either the element to use as the mousedown target
+ * <p>A {@link #delegate} may be provided which may be either the element to use as the mousedown target
  * or a {@link Ext.DomQuery} selector to activate multiple mousedown targets.</p>
  */
 Ext.define('Ext.util.ComponentDragger', {
@@ -68963,7 +72217,7 @@ Ext.define('Ext.util.ComponentDragger', {
      */
 
     /**
-     * @cfg {String/Element} delegate
+     * @cfg {String/Ext.Element} delegate
      * Optional. <p>A {@link Ext.DomQuery DomQuery} selector which identifies child elements within the Component's encapsulating
      * Element which are the drag handles. This limits dragging to only begin when the matching elements are mousedowned.</p>
      * <p>This may also be a specific child element within the Component's encapsulating element to use as the drag handle.</p>
@@ -68980,8 +72234,8 @@ Ext.define('Ext.util.ComponentDragger', {
 
     /**
      * Creates new ComponentDragger.
-     * @param {object} comp The Component to provide dragging for.
-     * @param {object} config (optional) Config object
+     * @param {Object} comp The Component to provide dragging for.
+     * @param {Object} config (optional) Config object
      */
     constructor: function(comp, config) {
         this.comp = comp;
@@ -69060,47 +72314,45 @@ Ext.define('Ext.util.ComponentDragger', {
     }
 });
 /**
- * @class Ext.form.Labelable
-
-A mixin which allows a component to be configured and decorated with a label and/or error message as is
-common for form fields. This is used by e.g. {@link Ext.form.field.Base} and {@link Ext.form.FieldContainer}
-to let them be managed by the Field layout.
-
-**NOTE**: This mixin is mainly for internal library use and most users should not need to use it directly. It
-is more likely you will want to use one of the component classes that import this mixin, such as
-{@link Ext.form.field.Base} or {@link Ext.form.FieldContainer}.
-
-Use of this mixin does not make a component a field in the logical sense, meaning it does not provide any
-logic or state related to values or validation; that is handled by the related {@link Ext.form.field.Field}
-mixin. These two mixins may be used separately (for example {@link Ext.form.FieldContainer} is Labelable but not a
-Field), or in combination (for example {@link Ext.form.field.Base} implements both and has logic for connecting the
-two.)
-
-Component classes which use this mixin should use the Field layout
-or a derivation thereof to properly size and position the label and message according to the component config.
-They must also call the {@link #initLabelable} method during component initialization to ensure the mixin gets
-set up correctly.
-
- * @markdown
+ * A mixin which allows a component to be configured and decorated with a label and/or error message as is
+ * common for form fields. This is used by e.g. Ext.form.field.Base and Ext.form.FieldContainer
+ * to let them be managed by the Field layout.
+ *
+ * NOTE: This mixin is mainly for internal library use and most users should not need to use it directly. It
+ * is more likely you will want to use one of the component classes that import this mixin, such as
+ * Ext.form.field.Base or Ext.form.FieldContainer.
+ *
+ * Use of this mixin does not make a component a field in the logical sense, meaning it does not provide any
+ * logic or state related to values or validation; that is handled by the related Ext.form.field.Field
+ * mixin. These two mixins may be used separately (for example Ext.form.FieldContainer is Labelable but not a
+ * Field), or in combination (for example Ext.form.field.Base implements both and has logic for connecting the
+ * two.)
+ *
+ * Component classes which use this mixin should use the Field layout
+ * or a derivation thereof to properly size and position the label and message according to the component config.
+ * They must also call the {@link #initLabelable} method during component initialization to ensure the mixin gets
+ * set up correctly.
+ *
  * @docauthor Jason Johnston <jason@sencha.com>
  */
 Ext.define("Ext.form.Labelable", {
     requires: ['Ext.XTemplate'],
 
     /**
-     * @cfg {Array/String/Ext.XTemplate} labelableRenderTpl
+     * @cfg {String/String[]/Ext.XTemplate} labelableRenderTpl
      * The rendering template for the field decorations. Component classes using this mixin should include
      * logic to use this as their {@link Ext.AbstractComponent#renderTpl renderTpl}, and implement the
      * {@link #getSubTplMarkup} method to generate the field body content.
      */
     labelableRenderTpl: [
         '<tpl if="!hideLabel && !(!fieldLabel && hideEmptyLabel)">',
-            '<label<tpl if="inputId"> for="{inputId}"</tpl> class="{labelCls}"<tpl if="labelStyle"> style="{labelStyle}"</tpl>>',
+            '<label id="{id}-labelEl"<tpl if="inputId"> for="{inputId}"</tpl> class="{labelCls}"',
+                '<tpl if="labelStyle"> style="{labelStyle}"</tpl>>',
                 '<tpl if="fieldLabel">{fieldLabel}{labelSeparator}</tpl>',
             '</label>',
         '</tpl>',
-        '<div class="{baseBodyCls} {fieldBodyCls}"<tpl if="inputId"> id="{baseBodyCls}-{inputId}"</tpl> role="presentation">{subTplMarkup}</div>',
-        '<div class="{errorMsgCls}" style="display:none"></div>',
+        '<div class="{baseBodyCls} {fieldBodyCls}" id="{id}-bodyEl" role="presentation">{subTplMarkup}</div>',
+        '<div id="{id}-errorEl" class="{errorMsgCls}" style="display:none"></div>',
         '<div class="{clearCls}" role="presentation"><!-- --></div>',
         {
             compiled: true,
@@ -69127,47 +72379,55 @@ Ext.define("Ext.form.Labelable", {
     isFieldLabelable: true,
 
     /**
-     * @cfg {String} formItemCls
+     * @cfg {String} [formItemCls='x-form-item']
      * A CSS class to be applied to the outermost element to denote that it is participating in the form
-     * field layout. Defaults to 'x-form-item'.
+     * field layout.
      */
     formItemCls: Ext.baseCSSPrefix + 'form-item',
 
     /**
-     * @cfg {String} labelCls
-     * The CSS class to be applied to the label element. Defaults to 'x-form-item-label'.
+     * @cfg {String} [labelCls='x-form-item-label']
+     * The CSS class to be applied to the label element.
+     * This (single) CSS class is used to formulate the renderSelector and drives the field
+     * layout where it is concatenated with a hyphen ('-') and {@link #labelAlign}. To add
+     * additional classes, use {@link #labelClsExtra}.
      */
     labelCls: Ext.baseCSSPrefix + 'form-item-label',
 
     /**
-     * @cfg {String} errorMsgCls
-     * The CSS class to be applied to the error message element. Defaults to 'x-form-error-msg'.
+     * @cfg {String} labelClsExtra
+     * An optional string of one or more additional CSS classes to add to the label element.
+     * Defaults to empty.
+     */
+
+    /**
+     * @cfg {String} [errorMsgCls='x-form-error-msg']
+     * The CSS class to be applied to the error message element.
      */
     errorMsgCls: Ext.baseCSSPrefix + 'form-error-msg',
 
     /**
-     * @cfg {String} baseBodyCls
-     * The CSS class to be applied to the body content element. Defaults to 'x-form-item-body'.
+     * @cfg {String} [baseBodyCls='x-form-item-body']
+     * The CSS class to be applied to the body content element.
      */
     baseBodyCls: Ext.baseCSSPrefix + 'form-item-body',
 
     /**
      * @cfg {String} fieldBodyCls
      * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
-     * Defaults to empty.
      */
     fieldBodyCls: '',
 
     /**
-     * @cfg {String} clearCls
+     * @cfg {String} [clearCls='x-clear']
      * The CSS class to be applied to the special clearing div rendered directly after the field
-     * contents wrapper to provide field clearing (defaults to <tt>'x-clear'</tt>).
+     * contents wrapper to provide field clearing.
      */
     clearCls: Ext.baseCSSPrefix + 'clear',
 
     /**
-     * @cfg {String} invalidCls
-     * The CSS class to use when marking the component invalid (defaults to 'x-form-invalid')
+     * @cfg {String} [invalidCls='x-form-invalid']
+     * The CSS class to use when marking the component invalid.
      */
     invalidCls : Ext.baseCSSPrefix + 'form-invalid',
 
@@ -69175,7 +72435,7 @@ Ext.define("Ext.form.Labelable", {
      * @cfg {String} fieldLabel
      * The label for the field. It gets appended with the {@link #labelSeparator}, and its position
      * and sizing is determined by the {@link #labelAlign}, {@link #labelWidth}, and {@link #labelPad}
-     * configs. Defaults to undefined.
+     * configs.
      */
     fieldLabel: undefined,
 
@@ -69195,13 +72455,13 @@ Ext.define("Ext.form.Labelable", {
     /**
      * @cfg {Number} labelWidth
      * The width of the {@link #fieldLabel} in pixels. Only applicable if the {@link #labelAlign} is set
-     * to "left" or "right". Defaults to <tt>100</tt>.
+     * to "left" or "right".
      */
     labelWidth: 100,
 
     /**
      * @cfg {Number} labelPad
-     * The amount of space in pixels between the {@link #fieldLabel} and the input field. Defaults to <tt>5</tt>.
+     * The amount of space in pixels between the {@link #fieldLabel} and the input field.
      */
     labelPad : 5,
 
@@ -69213,14 +72473,13 @@ Ext.define("Ext.form.Labelable", {
 
     /**
      * @cfg {String} labelStyle
-     * <p>A CSS style specification string to apply directly to this field's label. Defaults to undefined.</p>
+     * A CSS style specification string to apply directly to this field's label.
      */
 
     /**
      * @cfg {Boolean} hideLabel
-     * <p>Set to <tt>true</tt> to completely hide the label element ({@link #fieldLabel} and {@link #labelSeparator}).
-     * Defaults to <tt>false</tt>.</p>
-     * <p>Also see {@link #hideEmptyLabel}, which controls whether space will be reserved for an empty fieldLabel.</p>
+     * Set to true to completely hide the label element ({@link #fieldLabel} and {@link #labelSeparator}).
+     * Also see {@link #hideEmptyLabel}, which controls whether space will be reserved for an empty fieldLabel.
      */
     hideLabel: false,
 
@@ -69229,7 +72488,7 @@ Ext.define("Ext.form.Labelable", {
      * <p>When set to <tt>true</tt>, the label element ({@link #fieldLabel} and {@link #labelSeparator}) will be
      * automatically hidden if the {@link #fieldLabel} is empty. Setting this to <tt>false</tt> will cause the empty
      * label element to be rendered and space to be reserved for it; this is useful if you want a field without a label
-     * to line up with other labeled fields in the same form. Defaults to <tt>true</tt>.</p>
+     * to line up with other labeled fields in the same form.</p>
      * <p>If you wish to unconditionall hide the label even if a non-empty fieldLabel is configured, then set
      * the {@link #hideLabel} config to <tt>true</tt>.</p>
      */
@@ -69238,14 +72497,13 @@ Ext.define("Ext.form.Labelable", {
     /**
      * @cfg {Boolean} preventMark
      * <tt>true</tt> to disable displaying any {@link #setActiveError error message} set on this object.
-     * Defaults to <tt>false</tt>.
      */
     preventMark: false,
 
     /**
      * @cfg {Boolean} autoFitErrors
      * Whether to adjust the component's body area to make room for 'side' or 'under'
-     * {@link #msgTarget error messages}. Defaults to <tt>true</tt>.
+     * {@link #msgTarget error messages}.
      */
     autoFitErrors: true,
 
@@ -69267,7 +72525,7 @@ Ext.define("Ext.form.Labelable", {
     /**
      * @cfg {String} activeError
      * If specified, then the component will be displayed with this value as its active error when
-     * first rendered. Defaults to undefined. Use {@link #setActiveError} or {@link #unsetActiveError} to
+     * first rendered. Use {@link #setActiveError} or {@link #unsetActiveError} to
      * change it after component creation.
      */
 
@@ -69307,6 +72565,8 @@ Ext.define("Ext.form.Labelable", {
     getLabelableRenderData: function() {
         var me = this,
             labelAlign = me.labelAlign,
+            labelCls = me.labelCls,
+            labelClsExtra = me.labelClsExtra,
             labelPad = me.labelPad,
             labelStyle;
 
@@ -69326,47 +72586,41 @@ Ext.define("Ext.form.Labelable", {
             {
                 inputId: me.getInputId(),
                 fieldLabel: me.getFieldLabel(),
+                labelCls: labelClsExtra ? labelCls + ' ' + labelClsExtra : labelCls,
                 labelStyle: labelStyle + (me.labelStyle || ''),
                 subTplMarkup: me.getSubTplMarkup()
             },
             me,
-            'hideLabel,hideEmptyLabel,labelCls,fieldBodyCls,baseBodyCls,errorMsgCls,clearCls,labelSeparator',
+            'hideLabel,hideEmptyLabel,fieldBodyCls,baseBodyCls,errorMsgCls,clearCls,labelSeparator',
             true
         );
     },
 
-    /**
-     * @protected
-     * Returns the additional {@link Ext.AbstractComponent#renderSelectors} for selecting the field
-     * decoration elements from the rendered {@link #labelableRenderTpl}. Component classes using this mixin should
-     * be sure and merge this method's result into the component's {@link Ext.AbstractComponent#renderSelectors}
-     * before rendering.
-     */
-    getLabelableSelectors: function() {
-        return {
+    onLabelableRender: function () {
+        this.addChildEls(
             /**
              * @property labelEl
-             * @type Ext.core.Element
+             * @type Ext.Element
              * The label Element for this component. Only available after the component has been rendered.
              */
-            labelEl: 'label.' + this.labelCls,
+            'labelEl',
 
             /**
              * @property bodyEl
-             * @type Ext.core.Element
+             * @type Ext.Element
              * The div Element wrapping the component's contents. Only available after the component has been rendered.
              */
-            bodyEl: '.' + this.baseBodyCls,
+            'bodyEl',
 
             /**
              * @property errorEl
-             * @type Ext.core.Element
+             * @type Ext.Element
              * The div Element that will contain the component's error message(s). Note that depending on the
              * configured {@link #msgTarget}, this element may be hidden in favor of some other form of
              * presentation, but will always be present in the DOM for use by assistive technologies.
              */
-            errorEl: '.' + this.errorMsgCls
-        };
+            'errorEl'
+        );
     },
 
     /**
@@ -69426,7 +72680,7 @@ Ext.define("Ext.form.Labelable", {
     /**
      * Gets an Array of any active error messages currently applied to the field. This does not trigger
      * validation on its own, it merely returns any messages that the component may already hold.
-     * @return {Array} The active error messages on the component; if there are no errors, an empty Array is returned.
+     * @return {String[]} The active error messages on the component; if there are no errors, an empty Array is returned.
      */
     getActiveErrors: function() {
         return this.activeErrors || [];
@@ -69441,7 +72695,7 @@ Ext.define("Ext.form.Labelable", {
      * to call doComponentLayout to actually update the field's layout to match. If the field extends
      * {@link Ext.form.field.Base} you should call {@link Ext.form.field.Base#markInvalid markInvalid} instead.
      *
-     * @param {Array} errors The error messages
+     * @param {String[]} errors The error messages
      */
     setActiveErrors: function(errors) {
         this.activeErrors = errors;
@@ -69516,69 +72770,70 @@ Ext.define("Ext.form.Labelable", {
 });
 
 /**
- * @class Ext.form.field.Field
-
-This mixin provides a common interface for the logical behavior and state of form fields, including:
-
-- Getter and setter methods for field values
-- Events and methods for tracking value and validity changes
-- Methods for triggering validation
-
-**NOTE**: When implementing custom fields, it is most likely that you will want to extend the {@link Ext.form.field.Base}
-component class rather than using this mixin directly, as BaseField contains additional logic for generating an
-actual DOM complete with {@link Ext.form.Labelable label and error message} display and a form input field,
-plus methods that bind the Field value getters and setters to the input field's value.
-
-If you do want to implement this mixin directly and don't want to extend {@link Ext.form.field.Base}, then
-you will most likely want to override the following methods with custom implementations: {@link #getValue},
-{@link #setValue}, and {@link #getErrors}. Other methods may be overridden as needed but their base
-implementations should be sufficient for common cases. You will also need to make sure that {@link #initField}
-is called during the component's initialization.
-
- * @markdown
  * @docauthor Jason Johnston <jason@sencha.com>
+ *
+ * This mixin provides a common interface for the logical behavior and state of form fields, including:
+ *
+ * - Getter and setter methods for field values
+ * - Events and methods for tracking value and validity changes
+ * - Methods for triggering validation
+ *
+ * **NOTE**: When implementing custom fields, it is most likely that you will want to extend the {@link Ext.form.field.Base}
+ * component class rather than using this mixin directly, as BaseField contains additional logic for generating an
+ * actual DOM complete with {@link Ext.form.Labelable label and error message} display and a form input field,
+ * plus methods that bind the Field value getters and setters to the input field's value.
+ *
+ * If you do want to implement this mixin directly and don't want to extend {@link Ext.form.field.Base}, then
+ * you will most likely want to override the following methods with custom implementations: {@link #getValue},
+ * {@link #setValue}, and {@link #getErrors}. Other methods may be overridden as needed but their base
+ * implementations should be sufficient for common cases. You will also need to make sure that {@link #initField}
+ * is called during the component's initialization.
  */
 Ext.define('Ext.form.field.Field', {
-
     /**
-     * @property isFormField
-     * @type {Boolean}
+     * @property {Boolean} isFormField
      * Flag denoting that this component is a Field. Always true.
      */
     isFormField : true,
 
     /**
-     * @cfg {Mixed} value A value to initialize this field with (defaults to undefined).
+     * @cfg {Object} value
+     * A value to initialize this field with.
      */
-    
+
     /**
-     * @cfg {String} name The name of the field (defaults to undefined). By default this is used as the parameter
-     * name when including the {@link #getSubmitData field value} in a {@link Ext.form.Basic#submit form submit()}.
-     * To prevent the field from being included in the form submit, set {@link #submitValue} to <tt>false</tt>.
+     * @cfg {String} name
+     * The name of the field. By default this is used as the parameter name when including the
+     * {@link #getSubmitData field value} in a {@link Ext.form.Basic#submit form submit()}. To prevent the field from
+     * being included in the form submit, set {@link #submitValue} to false.
      */
 
     /**
-     * @cfg {Boolean} disabled True to disable the field (defaults to false). Disabled Fields will not be
-     * {@link Ext.form.Basic#submit submitted}.</p>
+     * @cfg {Boolean} disabled
+     * True to disable the field. Disabled Fields will not be {@link Ext.form.Basic#submit submitted}.
      */
     disabled : false,
 
     /**
-     * @cfg {Boolean} submitValue Setting this to <tt>false</tt> will prevent the field from being
-     * {@link Ext.form.Basic#submit submitted} even when it is not disabled. Defaults to <tt>true</tt>.
+     * @cfg {Boolean} submitValue
+     * Setting this to false will prevent the field from being {@link Ext.form.Basic#submit submitted} even when it is
+     * not disabled.
      */
     submitValue: true,
 
     /**
      * @cfg {Boolean} validateOnChange
-     * <p>Specifies whether this field should be validated immediately whenever a change in its value is detected.
-     * Defaults to <tt>true</tt>. If the validation results in a change in the field's validity, a
-     * {@link #validitychange} event will be fired. This allows the field to show feedback about the
-     * validity of its contents immediately as the user is typing.</p>
-     * <p>When set to <tt>false</tt>, feedback will not be immediate. However the form will still be validated
-     * before submitting if the <tt>clientValidation</tt> option to {@link Ext.form.Basic#doAction} is
-     * enabled, or if the field or form are validated manually.</p>
-     * <p>See also {@link Ext.form.field.Base#checkChangeEvents}for controlling how changes to the field's value are detected.</p>
+     * Specifies whether this field should be validated immediately whenever a change in its value is detected.
+     * If the validation results in a change in the field's validity, a {@link #validitychange} event will be
+     * fired. This allows the field to show feedback about the validity of its contents immediately as the user is
+     * typing.
+     *
+     * When set to false, feedback will not be immediate. However the form will still be validated before submitting if
+     * the clientValidation option to {@link Ext.form.Basic#doAction} is enabled, or if the field or form are validated
+     * manually.
+     *
+     * See also {@link Ext.form.field.Base#checkChangeEvents} for controlling how changes to the field's value are
+     * detected.
      */
     validateOnChange: true,
 
@@ -69588,8 +72843,8 @@ Ext.define('Ext.form.field.Field', {
     suspendCheckChange: 0,
 
     /**
-     * Initializes this Field mixin on the current instance. Components using this mixin should call
-     * this method during their own initialization process.
+     * Initializes this Field mixin on the current instance. Components using this mixin should call this method during
+     * their own initialization process.
      */
     initField: function() {
         this.addEvents(
@@ -69597,8 +72852,8 @@ Ext.define('Ext.form.field.Field', {
              * @event change
              * Fires when a user-initiated change is detected in the value of the field.
              * @param {Ext.form.field.Field} this
-             * @param {Mixed} newValue The new value
-             * @param {Mixed} oldValue The original value
+             * @param {Object} newValue The new value
+             * @param {Object} oldValue The original value
              */
             'change',
             /**
@@ -69621,18 +72876,15 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * @protected
      * Initializes the field's value based on the initial config.
      */
     initValue: function() {
         var me = this;
 
         /**
-         * @property originalValue
-         * @type Mixed
-         * The original value of the field as configured in the {@link #value} configuration, or as loaded by
-         * the last form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
-         * setting is <code>true</code>.
+         * @property {Object} originalValue
+         * The original value of the field as configured in the {@link #value} configuration, or as loaded by the last
+         * form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} setting is `true`.
          */
         me.originalValue = me.lastValue = me.value;
 
@@ -69643,8 +72895,8 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * Returns the {@link Ext.form.field.Field#name name} attribute of the field. This is used as the parameter
-     * name when including the field value in a {@link Ext.form.Basic#submit form submit()}.
+     * Returns the {@link Ext.form.field.Field#name name} attribute of the field. This is used as the parameter name
+     * when including the field value in a {@link Ext.form.Basic#submit form submit()}.
      * @return {String} name The field {@link Ext.form.field.Field#name name}
      */
     getName: function() {
@@ -69654,15 +72906,15 @@ Ext.define('Ext.form.field.Field', {
     /**
      * Returns the current data value of the field. The type of value returned is particular to the type of the
      * particular field (e.g. a Date object for {@link Ext.form.field.Date}).
-     * @return {Mixed} value The field value
+     * @return {Object} value The field value
      */
     getValue: function() {
         return this.value;
     },
-    
+
     /**
      * Sets a data value into the field and runs the change detection and validation.
-     * @param {Mixed} value The value to set
+     * @param {Object} value The value to set
      * @return {Ext.form.field.Field} this
      */
     setValue: function(value) {
@@ -69673,26 +72925,39 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * Returns whether two field {@link #getValue values} are logically equal. Field implementations may override
-     * this to provide custom comparison logic appropriate for the particular field's data type.
-     * @param {Mixed} value1 The first value to compare
-     * @param {Mixed} value2 The second value to compare
+     * Returns whether two field {@link #getValue values} are logically equal. Field implementations may override this
+     * to provide custom comparison logic appropriate for the particular field's data type.
+     * @param {Object} value1 The first value to compare
+     * @param {Object} value2 The second value to compare
      * @return {Boolean} True if the values are equal, false if inequal.
      */
     isEqual: function(value1, value2) {
         return String(value1) === String(value2);
     },
+    
+    /**
+     * Returns whether two values are logically equal.
+     * Similar to {@link #isEqual}, however null or undefined values will be treated as empty strings.
+     * @private
+     * @param {Object} value1 The first value to compare
+     * @param {Object} value2 The second value to compare
+     * @return {Boolean} True if the values are equal, false if inequal.
+     */
+    isEqualAsString: function(value1, value2){
+        return String(Ext.value(value1, '')) === String(Ext.value(value2, ''));    
+    },
 
     /**
-     * <p>Returns the parameter(s) that would be included in a standard form submit for this field. Typically this
-     * will be an object with a single name-value pair, the name being this field's {@link #getName name} and the
-     * value being its current stringified value. More advanced field implementations may return more than one
-     * name-value pair.</p>
-     * <p>Note that the values returned from this method are not guaranteed to have been successfully
-     * {@link #validate validated}.</p>
-     * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array
-     * of strings if that particular name has multiple values. It can also return <tt>null</tt> if there are no
-     * parameters to be submitted.
+     * Returns the parameter(s) that would be included in a standard form submit for this field. Typically this will be
+     * an object with a single name-value pair, the name being this field's {@link #getName name} and the value being
+     * its current stringified value. More advanced field implementations may return more than one name-value pair.
+     *
+     * Note that the values returned from this method are not guaranteed to have been successfully {@link #validate
+     * validated}.
+     *
+     * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array of
+     * strings if that particular name has multiple values. It can also return null if there are no parameters to be
+     * submitted.
      */
     getSubmitData: function() {
         var me = this,
@@ -69705,16 +72970,18 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * <p>Returns the value(s) that should be saved to the {@link Ext.data.Model} instance for this field, when
-     * {@link Ext.form.Basic#updateRecord} is called. Typically this will be an object with a single name-value
-     * pair, the name being this field's {@link #getName name} and the value being its current data value. More
-     * advanced field implementations may return more than one name-value pair. The returned values will be
-     * saved to the corresponding field names in the Model.</p>
-     * <p>Note that the values returned from this method are not guaranteed to have been successfully
-     * {@link #validate validated}.</p>
-     * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array
-     * of strings if that particular name has multiple values. It can also return <tt>null</tt> if there are no
-     * parameters to be submitted.
+     * Returns the value(s) that should be saved to the {@link Ext.data.Model} instance for this field, when {@link
+     * Ext.form.Basic#updateRecord} is called. Typically this will be an object with a single name-value pair, the name
+     * being this field's {@link #getName name} and the value being its current data value. More advanced field
+     * implementations may return more than one name-value pair. The returned values will be saved to the corresponding
+     * field names in the Model.
+     *
+     * Note that the values returned from this method are not guaranteed to have been successfully {@link #validate
+     * validated}.
+     *
+     * @return {Object} A mapping of submit parameter names to values; each value should be a string, or an array of
+     * strings if that particular name has multiple values. It can also return null if there are no parameters to be
+     * submitted.
      */
     getModelData: function() {
         var me = this,
@@ -69727,12 +72994,12 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * Resets the current field value to the originally loaded value and clears any validation messages.
-     * See {@link Ext.form.Basic}.{@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
+     * Resets the current field value to the originally loaded value and clears any validation messages. See {@link
+     * Ext.form.Basic}.{@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
      */
     reset : function(){
         var me = this;
-        
+
         me.setValue(me.originalValue);
         me.clearInvalid();
         // delete here so we reset back to the original state
@@ -69740,8 +73007,8 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * Resets the field's {@link #originalValue} property so it matches the current {@link #getValue value}.
-     * This is called by {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues} if the form's
+     * Resets the field's {@link #originalValue} property so it matches the current {@link #getValue value}. This is
+     * called by {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues} if the form's
      * {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} property is set to true.
      */
     resetOriginalValue: function() {
@@ -69750,15 +73017,14 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * <p>Checks whether the value of the field has changed since the last time it was checked. If the value
-     * has changed, it:</p>
-     * <ol>
-     * <li>Fires the {@link #change change event},</li>
-     * <li>Performs validation if the {@link #validateOnChange} config is enabled, firing the
-     * {@link #validationchange validationchange event} if the validity has changed, and</li>
-     * <li>Checks the {@link #isDirty dirty state} of the field and fires the {@link #dirtychange dirtychange event}
-     * if it has changed.</li>
-     * </ol>
+     * Checks whether the value of the field has changed since the last time it was checked.
+     * If the value has changed, it:
+     *
+     * 1. Fires the {@link #change change event},
+     * 2. Performs validation if the {@link #validateOnChange} config is enabled, firing the
+     *    {@link #validitychange validitychange event} if the validity has changed, and
+     * 3. Checks the {@link #isDirty dirty state} of the field and fires the {@link #dirtychange dirtychange event}
+     *    if it has changed.
      */
     checkChange: function() {
         if (!this.suspendCheckChange) {
@@ -69786,14 +73052,14 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * <p>Returns true if the value of this Field has been changed from its {@link #originalValue}.
-     * Will always return false if the field is disabled.</p>
-     * <p>Note that if the owning {@link Ext.form.Basic form} was configured with
-     * {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
-     * then the {@link #originalValue} is updated when the values are loaded by
-     * {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues}.</p>
-     * @return {Boolean} True if this field has been changed from its original value (and
-     * is not disabled), false otherwise.
+     * Returns true if the value of this Field has been changed from its {@link #originalValue}.
+     * Will always return false if the field is disabled.
+     *
+     * Note that if the owning {@link Ext.form.Basic form} was configured with
+     * {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} then the {@link #originalValue} is updated when
+     * the values are loaded by {@link Ext.form.Basic}.{@link Ext.form.Basic#setValues setValues}.
+     * @return {Boolean} True if this field has been changed from its original value (and is not disabled),
+     * false otherwise.
      */
     isDirty : function() {
         var me = this;
@@ -69801,8 +73067,8 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * Checks the {@link #isDirty} state of the field and if it has changed since the last time
-     * it was checked, fires the {@link #dirtychange} event.
+     * Checks the {@link #isDirty} state of the field and if it has changed since the last time it was checked,
+     * fires the {@link #dirtychange} event.
      */
     checkDirty: function() {
         var me = this,
@@ -69821,22 +73087,26 @@ Ext.define('Ext.form.field.Field', {
     onDirtyChange: Ext.emptyFn,
 
     /**
-     * <p>Runs this field's validators and returns an array of error messages for any validation failures.
-     * This is called internally during validation and would not usually need to be used manually.</p>
-     * <p>Each subclass should override or augment the return value to provide their own errors.</p>
-     * @param {Mixed} value The value to get errors for (defaults to the current field value)
-     * @return {Array} All error messages for this field; an empty Array if none.
+     * Runs this field's validators and returns an array of error messages for any validation failures. This is called
+     * internally during validation and would not usually need to be used manually.
+     *
+     * Each subclass should override or augment the return value to provide their own errors.
+     *
+     * @param {Object} value The value to get errors for (defaults to the current field value)
+     * @return {String[]} All error messages for this field; an empty Array if none.
      */
     getErrors: function(value) {
         return [];
     },
 
     /**
-     * <p>Returns whether or not the field value is currently valid by {@link #getErrors validating} the
-     * field's current value. The {@link #validitychange} event will not be fired; use {@link #validate}
-     * instead if you want the event to fire. <b>Note</b>: {@link #disabled} fields are always treated as valid.</p>
-     * <p>Implementations are encouraged to ensure that this method does not have side-effects such as
-     * triggering error message display.</p>
+     * Returns whether or not the field value is currently valid by {@link #getErrors validating} the field's current
+     * value. The {@link #validitychange} event will not be fired; use {@link #validate} instead if you want the event
+     * to fire. **Note**: {@link #disabled} fields are always treated as valid.
+     *
+     * Implementations are encouraged to ensure that this method does not have side-effects such as triggering error
+     * message display.
+     *
      * @return {Boolean} True if the value is valid, else false
      */
     isValid : function() {
@@ -69845,11 +73115,13 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * <p>Returns whether or not the field value is currently valid by {@link #getErrors validating} the
-     * field's current value, and fires the {@link #validitychange} event if the field's validity has
-     * changed since the last validation. <b>Note</b>: {@link #disabled} fields are always treated as valid.</p>
-     * <p>Custom implementations of this method are allowed to have side-effects such as triggering error
-     * message display. To validate without side-effects, use {@link #isValid}.</p>
+     * Returns whether or not the field value is currently valid by {@link #getErrors validating} the field's current
+     * value, and fires the {@link #validitychange} event if the field's validity has changed since the last validation.
+     * **Note**: {@link #disabled} fields are always treated as valid.
+     *
+     * Custom implementations of this method are allowed to have side-effects such as triggering error message display.
+     * To validate without side-effects, use {@link #isValid}.
+     *
      * @return {Boolean} True if the value is valid, else false
      */
     validate : function() {
@@ -69863,24 +73135,29 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * A utility for grouping a set of modifications which may trigger value changes into a single
-     * transaction, to prevent excessive firing of {@link #change} events. This is useful for instance
-     * if the field has sub-fields which are being updated as a group; you don't want the container
-     * field to check its own changed state for each subfield change.
-     * @param fn A function containing the transaction code
+     * A utility for grouping a set of modifications which may trigger value changes into a single transaction, to
+     * prevent excessive firing of {@link #change} events. This is useful for instance if the field has sub-fields which
+     * are being updated as a group; you don't want the container field to check its own changed state for each subfield
+     * change.
+     * @param {Object} fn A function containing the transaction code
      */
     batchChanges: function(fn) {
-        this.suspendCheckChange++;
-        fn();
-        this.suspendCheckChange--;
+        try {
+            this.suspendCheckChange++;
+            fn();
+        } catch(e){
+            throw e;
+        } finally {
+            this.suspendCheckChange--;
+        }
         this.checkChange();
     },
 
     /**
-     * Returns whether this Field is a file upload field; if it returns true, forms will use
-     * special techniques for {@link Ext.form.Basic#submit submitting the form} via AJAX. See
-     * {@link Ext.form.Basic#hasUpload} for details. If this returns true, the {@link #extractFileInput}
-     * method must also be implemented to return the corresponding file input element.
+     * Returns whether this Field is a file upload field; if it returns true, forms will use special techniques for
+     * {@link Ext.form.Basic#submit submitting the form} via AJAX. See {@link Ext.form.Basic#hasUpload} for details. If
+     * this returns true, the {@link #extractFileInput} method must also be implemented to return the corresponding file
+     * input element.
      * @return {Boolean}
      */
     isFileUpload: function() {
@@ -69888,35 +73165,36 @@ Ext.define('Ext.form.field.Field', {
     },
 
     /**
-     * Only relevant if the instance's {@link #isFileUpload} method returns true. Returns a reference
-     * to the file input DOM element holding the user's selected file. The input will be appended into
-     * the submission form and will not be returned, so this method should also create a replacement.
-     * @return {HTMLInputElement}
+     * Only relevant if the instance's {@link #isFileUpload} method returns true. Returns a reference to the file input
+     * DOM element holding the user's selected file. The input will be appended into the submission form and will not be
+     * returned, so this method should also create a replacement.
+     * @return {HTMLElement}
      */
     extractFileInput: function() {
         return null;
     },
 
     /**
-     * <p>Associate one or more error messages with this field. Components using this mixin should implement
-     * this method to update the component's rendering to display the messages.</p>
-     * <p><b>Note</b>: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to
-     * return <code>false</code> if the value does <i>pass</i> validation. So simply marking a Field as invalid
-     * will not prevent submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation}
-     * option set.</p>
-     * @param {String/Array} errors The error message(s) for the field.
-     * @method
+     * @method markInvalid
+     * Associate one or more error messages with this field. Components using this mixin should implement this method to
+     * update the component's rendering to display the messages.
+     *
+     * **Note**: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to return `false`
+     * if the value does _pass_ validation. So simply marking a Field as invalid will not prevent submission of forms
+     * submitted with the {@link Ext.form.action.Submit#clientValidation} option set.
+     *
+     * @param {String/String[]} errors The error message(s) for the field.
      */
     markInvalid: Ext.emptyFn,
 
     /**
-     * <p>Clear any invalid styles/messages for this field. Components using this mixin should implement
-     * this method to update the components rendering to clear any existing messages.</p>
-     * <p><b>Note</b>: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to
-     * return <code>true</code> if the value does not <i>pass</i> validation. So simply clearing a field's errors
-     * will not necessarily allow submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation}
-     * option set.</p>
-     * @method
+     * @method clearInvalid
+     * Clear any invalid styles/messages for this field. Components using this mixin should implement this method to
+     * update the components rendering to clear any existing messages.
+     *
+     * **Note**: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to return `true`
+     * if the value does not _pass_ validation. So simply clearing a field's errors will not necessarily allow
+     * submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation} option set.
      */
     clearInvalid: Ext.emptyFn
 
@@ -70024,6 +73302,10 @@ Ext.define('Ext.layout.component.field.Field', {
 
         me.activeError = owner.getActiveError();
     },
+    
+    onFocus: function(){
+        this.getErrorStrategy().onFocus(this.owner);    
+    },
 
 
     /**
@@ -70178,6 +73460,18 @@ Ext.define('Ext.layout.component.field.Field', {
                 el.setStyle(name, value);
             }
         }
+        
+        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,
@@ -70188,7 +73482,8 @@ Ext.define('Ext.layout.component.field.Field', {
                 adjustHorizInsets: emptyFn,
                 adjustVertInsets: emptyFn,
                 layoutHoriz: emptyFn,
-                layoutVert: emptyFn
+                layoutVert: emptyFn,
+                onFocus: emptyFn
             };
 
         return {
@@ -70219,7 +73514,8 @@ Ext.define('Ext.layout.component.field.Field', {
                     if (owner.hasActiveError()) {
                         setStyle(owner.errorEl, 'top', info.insets.top + 'px');
                     }
-                }
+                },
+                onFocus: showTip
             }, base),
 
             /**
@@ -70256,7 +73552,8 @@ Ext.define('Ext.layout.component.field.Field', {
                     setDisplayed(owner.errorEl, false);
                     Ext.layout.component.field.Field.initTip();
                     owner.getActionEl().dom.setAttribute('data-errorqtip', owner.getActiveError() || '');
-                }
+                },
+                onFocus: showTip
             }, base),
 
             /**
@@ -70316,38 +73613,67 @@ Ext.define('Ext.layout.component.field.Field', {
 });
 
 /**
- * @class Ext.form.field.VTypes
- * <p>This is a singleton object which contains a set of commonly used field validation functions.
- * The validations provided are basic and intended to be easily customizable and extended.</p>
- * <p>To add custom VTypes specify the <code>{@link Ext.form.field.Text#vtype vtype}</code> validation
- * test function, and optionally specify any corresponding error text to display and any keystroke
- * filtering mask to apply. For example:</p>
- * <pre><code>
-// custom Vtype for vtype:'time'
-var timeTest = /^([1-9]|1[0-9]):([0-5][0-9])(\s[a|p]m)$/i;
-Ext.apply(Ext.form.field.VTypes, {
-    //  vtype validation function
-    time: function(val, field) {
-        return timeTest.test(val);
-    },
-    // vtype Text property: The error text to display when the validation function returns false
-    timeText: 'Not a valid time.  Must be in the format "12:34 PM".',
-    // vtype Mask property: The keystroke filter mask
-    timeMask: /[\d\s:amp]/i
-});
- * </code></pre>
- * Another example:
- * <pre><code>
-// custom Vtype for vtype:'IPAddress'
-Ext.apply(Ext.form.field.VTypes, {
-    IPAddress:  function(v) {
-        return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
-    },
-    IPAddressText: 'Must be a numeric IP address',
-    IPAddressMask: /[\d\.]/i
-});
- * </code></pre>
  * @singleton
+ * @alternateClassName Ext.form.VTypes
+ *
+ * This is a singleton object which contains a set of commonly used field validation functions
+ * and provides a mechanism for creating reusable custom field validations.
+ * The following field validation functions are provided out of the box:
+ *
+ * - {@link #alpha}
+ * - {@link #alphanum}
+ * - {@link #email}
+ * - {@link #url}
+ *
+ * VTypes can be applied to a {@link Ext.form.field.Text Text Field} using the `{@link Ext.form.field.Text#vtype vtype}` configuration:
+ *
+ *     Ext.create('Ext.form.field.Text', {
+ *         fieldLabel: 'Email Address',
+ *         name: 'email',
+ *         vtype: 'email' // applies email validation rules to this field
+ *     });
+ *
+ * To create custom VTypes:
+ *
+ *     // custom Vtype for vtype:'time'
+ *     var timeTest = /^([1-9]|1[0-9]):([0-5][0-9])(\s[a|p]m)$/i;
+ *     Ext.apply(Ext.form.field.VTypes, {
+ *         //  vtype validation function
+ *         time: function(val, field) {
+ *             return timeTest.test(val);
+ *         },
+ *         // vtype Text property: The error text to display when the validation function returns false
+ *         timeText: 'Not a valid time.  Must be in the format "12:34 PM".',
+ *         // vtype Mask property: The keystroke filter mask
+ *         timeMask: /[\d\s:amp]/i
+ *     });
+ *
+ * In the above example the `time` function is the validator that will run when field validation occurs,
+ * `timeText` is the error message, and `timeMask` limits what characters can be typed into the field.
+ * Note that the `Text` and `Mask` functions must begin with the same name as the validator function.
+ *
+ * Using a custom validator is the same as using one of the build-in validators - just use the name of the validator function
+ * as the `{@link Ext.form.field.Text#vtype vtype}` configuration on a {@link Ext.form.field.Text Text Field}:
+ *
+ *     Ext.create('Ext.form.field.Text', {
+ *         fieldLabel: 'Departure Time',
+ *         name: 'departureTime',
+ *         vtype: 'time' // applies custom time validation rules to this field
+ *     });
+ *
+ * Another example of a custom validator:
+ *
+ *     // custom Vtype for vtype:'IPAddress'
+ *     Ext.apply(Ext.form.field.VTypes, {
+ *         IPAddress:  function(v) {
+ *             return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(v);
+ *         },
+ *         IPAddressText: 'Must be a numeric IP address',
+ *         IPAddressMask: /[\d\.]/i
+ *     });
+ *
+ * It's important to note that using {@link Ext#apply Ext.apply()} means that the custom validator function
+ * as well as `Text` and `Mask` fields are added as properties of the `Ext.form.field.VTypes` singleton.
  */
 Ext.define('Ext.form.field.VTypes', (function(){
     // closure these in so they are only created once.
@@ -70362,13 +73688,19 @@ Ext.define('Ext.form.field.VTypes', (function(){
         alternateClassName: 'Ext.form.VTypes',
 
         /**
-         * The function used to validate email addresses.  Note that this is a very basic validation -- complete
-         * validation per the email RFC specifications is very complex and beyond the scope of this class, although
-         * this function can be overridden if a more comprehensive validation scheme is desired.  See the validation
-         * section of the <a href="http://en.wikipedia.org/wiki/E-mail_address">Wikipedia article on email addresses</a>
-         * for additional information.  This implementation is intended to validate the following emails:<tt>
-         * 'barney@example.de', 'barney.rubble@example.com', 'barney-rubble@example.coop', 'barney+rubble@example.com'
-         * </tt>.
+         * The function used to validate email addresses. Note that this is a very basic validation - complete
+         * validation per the email RFC specifications is very complex and beyond the scope of this class, although this
+         * function can be overridden if a more comprehensive validation scheme is desired. See the validation section
+         * of the [Wikipedia article on email addresses][1] for additional information. This implementation is intended
+         * to validate the following emails:
+         *
+         * - `barney@example.de`
+         * - `barney.rubble@example.com`
+         * - `barney-rubble@example.coop`
+         * - `barney+rubble@example.com`
+         *
+         * [1]: http://en.wikipedia.org/wiki/E-mail_address
+         *
          * @param {String} value The email address
          * @return {Boolean} true if the RegExp test passed, and false if not.
          */
@@ -70376,16 +73708,15 @@ Ext.define('Ext.form.field.VTypes', (function(){
             return email.test(v);
         },
         /**
-         * The error text to display when the email validation function returns false.  Defaults to:
-         * <tt>'This field should be an e-mail address in the format "user@example.com"'</tt>
-         * @type String
+         * @property {String} emailText
+         * The error text to display when the email validation function returns false.
+         * Defaults to: 'This field should be an e-mail address in the format "user@example.com"'
          */
         'emailText' : 'This field should be an e-mail address in the format "user@example.com"',
         /**
-         * The keystroke filter mask to be applied on email input.  See the {@link #email} method for
-         * information about more complex email validation. Defaults to:
-         * <tt>/[a-z0-9_\.\-@]/i</tt>
-         * @type RegExp
+         * @property {RegExp} emailMask
+         * The keystroke filter mask to be applied on email input. See the {@link #email} method for information about
+         * more complex email validation. Defaults to: /[a-z0-9_\.\-@]/i
          */
         'emailMask' : /[a-z0-9_\.\-@\+]/i,
 
@@ -70398,9 +73729,9 @@ Ext.define('Ext.form.field.VTypes', (function(){
             return url.test(v);
         },
         /**
-         * The error text to display when the url validation function returns false.  Defaults to:
-         * <tt>'This field should be a URL in the format "http:/'+'/www.example.com"'</tt>
-         * @type String
+         * @property {String} urlText
+         * The error text to display when the url validation function returns false.
+         * Defaults to: 'This field should be a URL in the format "http:/'+'/www.example.com"'
          */
         'urlText' : 'This field should be a URL in the format "http:/'+'/www.example.com"',
 
@@ -70413,15 +73744,14 @@ Ext.define('Ext.form.field.VTypes', (function(){
             return alpha.test(v);
         },
         /**
-         * The error text to display when the alpha validation function returns false.  Defaults to:
-         * <tt>'This field should only contain letters and _'</tt>
-         * @type String
+         * @property {String} alphaText
+         * The error text to display when the alpha validation function returns false.
+         * Defaults to: 'This field should only contain letters and _'
          */
         'alphaText' : 'This field should only contain letters and _',
         /**
-         * The keystroke filter mask to be applied on alpha input.  Defaults to:
-         * <tt>/[a-z_]/i</tt>
-         * @type RegExp
+         * @property {RegExp} alphaMask
+         * The keystroke filter mask to be applied on alpha input. Defaults to: /[a-z_]/i
          */
         'alphaMask' : /[a-z_]/i,
 
@@ -70434,15 +73764,14 @@ Ext.define('Ext.form.field.VTypes', (function(){
             return alphanum.test(v);
         },
         /**
-         * The error text to display when the alphanumeric validation function returns false.  Defaults to:
-         * <tt>'This field should only contain letters, numbers and _'</tt>
-         * @type String
+         * @property {String} alphanumText
+         * The error text to display when the alphanumeric validation function returns false.
+         * Defaults to: 'This field should only contain letters, numbers and _'
          */
         'alphanumText' : 'This field should only contain letters, numbers and _',
         /**
-         * The keystroke filter mask to be applied on alphanumeric input.  Defaults to:
-         * <tt>/[a-z0-9_]/i</tt>
-         * @type RegExp
+         * @property {RegExp} alphanumMask
+         * The keystroke filter mask to be applied on alphanumeric input. Defaults to: /[a-z0-9_]/i
          */
         'alphanumMask' : /[a-z0-9_]/i
     };
@@ -70493,7 +73822,7 @@ Ext.define('Ext.layout.component.field.Text', {
      * size based on the text field's {@link Ext.form.field.Text#grow grow config}.
      * @param {Number} width The bodyEl width
      * @param {Number} height The bodyEl height
-     * @return {Array} [inputElWidth, inputElHeight]
+     * @return {Number[]} [inputElWidth, inputElHeight]
      */
     adjustForGrow: function(width, height) {
         var me = this,
@@ -70537,7 +73866,7 @@ Ext.define('Ext.layout.component.field.TextArea', {
      * textfield layout's implementation to handle height rather than width.
      * @param {Number} width The bodyEl width
      * @param {Number} height The bodyEl height
-     * @return {Array} [inputElWidth, inputElHeight]
+     * @return {Number[]} [inputElWidth, inputElHeight]
      */
     adjustForGrow: function(width, height) {
         var me = this,
@@ -70580,43 +73909,45 @@ Ext.define('Ext.layout.component.field.TextArea', {
  * 
  * This is a layout that enables anchoring of contained elements relative to the container's dimensions.
  * If the container is resized, all anchored items are automatically rerendered according to their
- * <b><tt>{@link #anchor}</tt></b> rules.
+ * `{@link #anchor}` rules.
  *
- * This class is intended to be extended or created via the layout: 'anchor' {@link Ext.layout.container.AbstractContainer#layout}
- * config, and should generally not need to be created directly via the new keyword.</p>
+ * This class is intended to be extended or created via the {@link Ext.container.AbstractContainer#layout layout}: 'anchor' 
+ * config, and should generally not need to be created directly via the new keyword.
  * 
  * AnchorLayout does not have any direct config options (other than inherited ones). By default,
  * AnchorLayout will calculate anchor measurements based on the size of the container itself. However, the
- * container using the AnchorLayout can supply an anchoring-specific config property of <b>anchorSize</b>.
+ * container using the AnchorLayout can supply an anchoring-specific config property of `anchorSize`.
+ *
  * If anchorSize is specifed, the layout will use it as a virtual container for the purposes of calculating
  * anchor measurements based on it instead, allowing the container to be sized independently of the anchoring
  * logic if necessary.  
  *
- * {@img Ext.layout.container.Anchor/Ext.layout.container.Anchor.png Ext.layout.container.Anchor container layout}
- *
- * For example:
+ *     @example
  *     Ext.create('Ext.Panel', {
  *         width: 500,
  *         height: 400,
  *         title: "AnchorLayout Panel",
  *         layout: 'anchor',
  *         renderTo: Ext.getBody(),
- *         items: [{
- *             xtype: 'panel',
- *             title: '75% Width and 20% Height',
- *             anchor: '75% 20%'
- *         },{
- *             xtype: 'panel',
- *             title: 'Offset -300 Width & -200 Height',
- *             anchor: '-300 -200'             
- *         },{
- *             xtype: 'panel',
- *             title: 'Mixed Offset and Percent',
- *             anchor: '-250 20%'
- *         }]
+ *         items: [
+ *             {
+ *                 xtype: 'panel',
+ *                 title: '75% Width and 20% Height',
+ *                 anchor: '75% 20%'
+ *             },
+ *             {
+ *                 xtype: 'panel',
+ *                 title: 'Offset -300 Width & -200 Height',
+ *                 anchor: '-300 -200'         
+ *             },
+ *             {
+ *                 xtype: 'panel',
+ *                 title: 'Mixed Offset and Percent',
+ *                 anchor: '-250 20%'
+ *             }
+ *         ]
  *     });
  */
-
 Ext.define('Ext.layout.container.Anchor', {
 
     /* Begin Definitions */
@@ -70629,52 +73960,51 @@ Ext.define('Ext.layout.container.Anchor', {
 
     /**
      * @cfg {String} anchor
-     * <p>This configuation option is to be applied to <b>child <tt>items</tt></b> of a container managed by
-     * this layout (ie. configured with <tt>layout:'anchor'</tt>).</p><br/>
      *
-     * <p>This value is what tells the layout how an item should be anchored to the container. <tt>items</tt>
-     * added to an AnchorLayout accept an anchoring-specific config property of <b>anchor</b> which is a string
+     * This configuation option is to be applied to **child `items`** of a container managed by
+     * this layout (ie. configured with `layout:'anchor'`).
+     *
+     * This value is what tells the layout how an item should be anchored to the container. `items`
+     * added to an AnchorLayout accept an anchoring-specific config property of **anchor** which is a string
      * containing two values: the horizontal anchor value and the vertical anchor value (for example, '100% 50%').
-     * The following types of anchor values are supported:<div class="mdetail-params"><ul>
-     *
-     * <li><b>Percentage</b> : Any value between 1 and 100, expressed as a percentage.<div class="sub-desc">
-     * The first anchor is the percentage width that the item should take up within the container, and the
-     * second is the percentage height.  For example:<pre><code>
-// two values specified
-anchor: '100% 50%' // render item complete width of the container and
-                   // 1/2 height of the container
-// one value specified
-anchor: '100%'     // the width value; the height will default to auto
-     * </code></pre></div></li>
-     *
-     * <li><b>Offsets</b> : Any positive or negative integer value.<div class="sub-desc">
-     * This is a raw adjustment where the first anchor is the offset from the right edge of the container,
-     * and the second is the offset from the bottom edge. For example:<pre><code>
-// two values specified
-anchor: '-50 -100' // render item the complete width of the container
-                   // minus 50 pixels and
-                   // the complete height minus 100 pixels.
-// one value specified
-anchor: '-50'      // anchor value is assumed to be the right offset value
-                   // bottom offset will default to 0
-     * </code></pre></div></li>
-     *
-     * <li><b>Sides</b> : Valid values are <tt>'right'</tt> (or <tt>'r'</tt>) and <tt>'bottom'</tt>
-     * (or <tt>'b'</tt>).<div class="sub-desc">
-     * Either the container must have a fixed size or an anchorSize config value defined at render time in
-     * order for these to have any effect.</div></li>
-     *
-     * <li><b>Mixed</b> : <div class="sub-desc">
-     * Anchor values can also be mixed as needed.  For example, to render the width offset from the container
-     * right edge by 50 pixels and 75% of the container's height use:
-     * <pre><code>
-anchor: '-50 75%'
-     * </code></pre></div></li>
+     * The following types of anchor values are supported:
      *
+     * - **Percentage** : Any value between 1 and 100, expressed as a percentage.
      *
-     * </ul></div>
+     *   The first anchor is the percentage width that the item should take up within the container, and the
+     *   second is the percentage height.  For example:
+     *
+     *       // two values specified
+     *       anchor: '100% 50%' // render item complete width of the container and
+     *                          // 1/2 height of the container
+     *       // one value specified
+     *       anchor: '100%'     // the width value; the height will default to auto
+     *
+     * - **Offsets** : Any positive or negative integer value.
+     *
+     *   This is a raw adjustment where the first anchor is the offset from the right edge of the container,
+     *   and the second is the offset from the bottom edge. For example:
+     *
+     *       // two values specified
+     *       anchor: '-50 -100' // render item the complete width of the container
+     *                          // minus 50 pixels and
+     *                          // the complete height minus 100 pixels.
+     *       // one value specified
+     *       anchor: '-50'      // anchor value is assumed to be the right offset value
+     *                          // bottom offset will default to 0
+     *
+     * - **Sides** : Valid values are `right` (or `r`) and `bottom` (or `b`).
+     *
+     *   Either the container must have a fixed size or an anchorSize config value defined at render time in
+     *   order for these to have any effect.
+     *   
+     * - **Mixed** :
+     *
+     *   Anchor values can also be mixed as needed.  For example, to render the width offset from the container
+     *   right edge by 50 pixels and 75% of the container's height use:
+     *   
+     *       anchor:   '-50 75%'
      */
-
     type: 'anchor',
 
     /**
@@ -70718,7 +74048,7 @@ anchor: '-50 75%'
 
         // Work around WebKit RightMargin bug. We're going to inline-block all the children only ONCE and remove it when we're done
         if (!Ext.supports.RightMargin) {
-            cleaner = Ext.core.Element.getRightMarginFixCleaner(target);
+            cleaner = Ext.Element.getRightMarginFixCleaner(target);
             target.addCls(Ext.baseCSSPrefix + 'inline-children');
         }
 
@@ -70988,33 +74318,33 @@ Ext.define('Ext.form.action.Load', {
 
 
 /**
- * @class Ext.window.Window
- * @extends Ext.panel.Panel
- * <p>A specialized panel intended for use as an application window.  Windows are floated, {@link #resizable}, and
- * {@link #draggable} by default.  Windows can be {@link #maximizable maximized} to fill the viewport,
- * restored to their prior size, and can be {@link #minimize}d.</p>
- * <p>Windows can also be linked to a {@link Ext.ZIndexManager} or managed by the {@link Ext.WindowManager} to provide
- * grouping, activation, to front, to back and other application-specific behavior.</p>
- * <p>By default, Windows will be rendered to document.body. To {@link #constrain} a Window to another element
- * specify {@link Ext.Component#renderTo renderTo}.</p>
- * <p><b>As with all {@link Ext.container.Container Container}s, it is important to consider how you want the Window
- * to size and arrange any child Components. Choose an appropriate {@link #layout} configuration which lays out
- * child Components in the required manner.</b></p>
- * {@img Ext.window.Window/Ext.window.Window.png Window component}
- * Example:<code><pre>
-Ext.create('Ext.window.Window', {
-    title: 'Hello',
   height: 200,
   width: 400,
   layout: 'fit',
-    items: {  // Let's put an empty grid in just to illustrate fit layout
-        xtype: 'grid',
       border: false,
       columns: [{header: 'World'}],                 // One header just for show. There's no data,
-        store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
-    }
-}).show();
-</pre></code>
+ * A specialized panel intended for use as an application window. Windows are floated, {@link #resizable}, and
+ * {@link #draggable} by default. Windows can be {@link #maximizable maximized} to fill the viewport, restored to
+ * their prior size, and can be {@link #minimize}d.
+ *
+ * Windows can also be linked to a {@link Ext.ZIndexManager} or managed by the {@link Ext.WindowManager} to provide
+ * grouping, activation, to front, to back and other application-specific behavior.
+ *
+ * By default, Windows will be rendered to document.body. To {@link #constrain} a Window to another element specify
+ * {@link Ext.Component#renderTo renderTo}.
+ *
+ * **As with all {@link Ext.container.Container Container}s, it is important to consider how you want the Window to size
+ * and arrange any child Components. Choose an appropriate {@link #layout} configuration which lays out child Components
+ * in the required manner.**
+ *
+ *     @example
+ *     Ext.create('Ext.window.Window', {
*         title: 'Hello',
*         height: 200,
*         width: 400,
+ *         layout: 'fit',
+ *         items: {  // Let's put an empty grid in just to illustrate fit layout
*             xtype: 'grid',
*             border: false,
+ *             columns: [{header: 'World'}],                 // One header just for show. There's no data,
+ *             store: Ext.create('Ext.data.ArrayStore', {}) // A dummy empty data store
+ *         }
+ *     }).show();
  */
 Ext.define('Ext.window.Window', {
     extend: 'Ext.panel.Panel',
@@ -71027,112 +74357,119 @@ Ext.define('Ext.window.Window', {
 
     /**
      * @cfg {Number} x
-     * The X position of the left edge of the window on initial showing. Defaults to centering the Window within
-     * the width of the Window's container {@link Ext.core.Element Element) (The Element that the Window is rendered to).
+     * The X position of the left edge of the window on initial showing. Defaults to centering the Window within the
+     * width of the Window's container {@link Ext.Element Element} (The Element that the Window is rendered to).
      */
+
     /**
      * @cfg {Number} y
-     * The Y position of the top edge of the window on initial showing. Defaults to centering the Window within
-     * the height of the Window's container {@link Ext.core.Element Element) (The Element that the Window is rendered to).
+     * The Y position of the top edge of the window on initial showing. Defaults to centering the Window within the
+     * height of the Window's container {@link Ext.Element Element} (The Element that the Window is rendered to).
      */
+
     /**
-     * @cfg {Boolean} modal
+     * @cfg {Boolean} [modal=false]
      * True to make the window modal and mask everything behind it when displayed, false to display it without
-     * restricting access to other UI elements (defaults to false).
+     * restricting access to other UI elements.
      */
+
     /**
-     * @cfg {String/Element} animateTarget
-     * Id or element from which the window should animate while opening (defaults to null with no animation).
+     * @cfg {String/Ext.Element} [animateTarget=null]
+     * Id or element from which the window should animate while opening.
      */
+
     /**
-     * @cfg {String/Number/Component} defaultFocus
-     * <p>Specifies a Component to receive focus when this Window is focused.</p>
-     * <p>This may be one of:</p><div class="mdetail-params"><ul>
-     * <li>The index of a footer Button.</li>
-     * <li>The id or {@link Ext.AbstractComponent#itemId} of a descendant Component.</li>
-     * <li>A Component.</li>
-     * </ul></div>
+     * @cfg {String/Number/Ext.Component} defaultFocus
+     * Specifies a Component to receive focus when this Window is focused.
+     *
+     * This may be one of:
+     *
+     *   - The index of a footer Button.
+     *   - The id or {@link Ext.AbstractComponent#itemId} of a descendant Component.
+     *   - A Component.
      */
+
     /**
      * @cfg {Function} onEsc
-     * Allows override of the built-in processing for the escape key. Default action
-     * is to close the Window (performing whatever action is specified in {@link #closeAction}.
-     * To prevent the Window closing when the escape key is pressed, specify this as
-     * Ext.emptyFn (See {@link Ext#emptyFn Ext.emptyFn}).
+     * Allows override of the built-in processing for the escape key. Default action is to close the Window (performing
+     * whatever action is specified in {@link #closeAction}. To prevent the Window closing when the escape key is
+     * pressed, specify this as {@link Ext#emptyFn Ext.emptyFn}.
      */
+
     /**
-     * @cfg {Boolean} collapsed
-     * True to render the window collapsed, false to render it expanded (defaults to false). Note that if
-     * {@link #expandOnShow} is true (the default) it will override the <code>collapsed</code> config and the window
-     * will always be expanded when shown.
+     * @cfg {Boolean} [collapsed=false]
+     * True to render the window collapsed, false to render it expanded. Note that if {@link #expandOnShow}
+     * is true (the default) it will override the `collapsed` config and the window will always be
+     * expanded when shown.
      */
+
     /**
-     * @cfg {Boolean} maximized
-     * True to initially display the window in a maximized state. (Defaults to false).
+     * @cfg {Boolean} [maximized=false]
+     * True to initially display the window in a maximized state.
      */
 
     /**
-    * @cfg {String} baseCls
-    * The base CSS class to apply to this panel's element (defaults to 'x-window').
+    * @cfg {String} [baseCls='x-window']
+    * The base CSS class to apply to this panel's element.
     */
     baseCls: Ext.baseCSSPrefix + 'window',
 
     /**
-     * @cfg {Mixed} resizable
-     * <p>Specify as <code>true</code> to allow user resizing at each edge and corner of the window, false to disable
-     * resizing (defaults to true).</p>
-     * <p>This may also be specified as a config object to </p>
+     * @cfg {Boolean/Object} resizable
+     * Specify as `true` to allow user resizing at each edge and corner of the window, false to disable resizing.
+     *
+     * This may also be specified as a config object to Ext.resizer.Resizer
      */
     resizable: true,
 
     /**
      * @cfg {Boolean} draggable
-     * <p>True to allow the window to be dragged by the header bar, false to disable dragging (defaults to true).  Note
-     * that by default the window will be centered in the viewport, so if dragging is disabled the window may need
-     * to be positioned programmatically after render (e.g., myWindow.setPosition(100, 100);).<p>
+     * True to allow the window to be dragged by the header bar, false to disable dragging. Note that
+     * by default the window will be centered in the viewport, so if dragging is disabled the window may need to be
+     * positioned programmatically after render (e.g., myWindow.setPosition(100, 100);).
      */
     draggable: true,
 
     /**
      * @cfg {Boolean} constrain
-     * True to constrain the window within its containing element, false to allow it to fall outside of its
-     * containing element. By default the window will be rendered to document.body.  To render and constrain the
-     * window within another element specify {@link #renderTo}.
-     * (defaults to false).  Optionally the header only can be constrained using {@link #constrainHeader}.
+     * True to constrain the window within its containing element, false to allow it to fall outside of its containing
+     * element. By default the window will be rendered to document.body. To render and constrain the window within
+     * another element specify {@link #renderTo}. Optionally the header only can be constrained
+     * using {@link #constrainHeader}.
      */
     constrain: false,
 
     /**
      * @cfg {Boolean} constrainHeader
-     * True to constrain the window header within its containing element (allowing the window body to fall outside
-     * of its containing element) or false to allow the header to fall outside its containing element (defaults to
-     * false). Optionally the entire window can be constrained using {@link #constrain}.
+     * True to constrain the window header within its containing element (allowing the window body to fall outside of
+     * its containing element) or false to allow the header to fall outside its containing element.
+     * Optionally the entire window can be constrained using {@link #constrain}.
      */
     constrainHeader: false,
 
     /**
      * @cfg {Boolean} plain
-     * True to render the window body with a transparent background so that it will blend into the framing
-     * elements, false to add a lighter background color to visually highlight the body element and separate it
-     * more distinctly from the surrounding frame (defaults to false).
+     * True to render the window body with a transparent background so that it will blend into the framing elements,
+     * false to add a lighter background color to visually highlight the body element and separate it more distinctly
+     * from the surrounding frame.
      */
     plain: false,
 
     /**
      * @cfg {Boolean} minimizable
      * True to display the 'minimize' tool button and allow the user to minimize the window, false to hide the button
-     * and disallow minimizing the window (defaults to false).  Note that this button provides no implementation --
-     * the behavior of minimizing a window is implementation-specific, so the minimize event must be handled and a
-     * custom minimize behavior implemented for this option to be useful.
+     * and disallow minimizing the window. Note that this button provides no implementation -- the
+     * behavior of minimizing a window is implementation-specific, so the minimize event must be handled and a custom
+     * minimize behavior implemented for this option to be useful.
      */
     minimizable: false,
 
     /**
      * @cfg {Boolean} maximizable
      * True to display the 'maximize' tool button and allow the user to maximize the window, false to hide the button
-     * and disallow maximizing the window (defaults to false).  Note that when a window is maximized, the tool button
-     * will automatically change to a 'restore' button with the appropriate behavior already built-in that will
-     * restore the window to its previous size.
+     * and disallow maximizing the window. Note that when a window is maximized, the tool button
+     * will automatically change to a 'restore' button with the appropriate behavior already built-in that will restore
+     * the window to its previous size.
      */
     maximizable: false,
 
@@ -71145,7 +74482,7 @@ Ext.define('Ext.window.Window', {
     /**
      * @cfg {Boolean} expandOnShow
      * True to always expand the window when it is displayed, false to keep it in its current state (which may be
-     * {@link #collapsed}) when displayed (defaults to true).
+     * {@link #collapsed}) when displayed.
      */
     expandOnShow: true,
 
@@ -71154,21 +74491,20 @@ Ext.define('Ext.window.Window', {
 
     /**
      * @cfg {Boolean} closable
-     * <p>True to display the 'close' tool button and allow the user to close the window, false to
-     * hide the button and disallow closing the window (defaults to <code>true</code>).</p>
-     * <p>By default, when close is requested by either clicking the close button in the header
-     * or pressing ESC when the Window has focus, the {@link #close} method will be called. This
-     * will <i>{@link Ext.Component#destroy destroy}</i> the Window and its content meaning that
-     * it may not be reused.</p>
-     * <p>To make closing a Window <i>hide</i> the Window so that it may be reused, set
-     * {@link #closeAction} to 'hide'.</p>
+     * True to display the 'close' tool button and allow the user to close the window, false to hide the button and
+     * disallow closing the window.
+     *
+     * By default, when close is requested by either clicking the close button in the header or pressing ESC when the
+     * Window has focus, the {@link #close} method will be called. This will _{@link Ext.Component#destroy destroy}_ the
+     * Window and its content meaning that it may not be reused.
+     *
+     * To make closing a Window _hide_ the Window so that it may be reused, set {@link #closeAction} to 'hide'.
      */
     closable: true,
 
     /**
      * @cfg {Boolean} hidden
-     * Render this Window hidden (default is <code>true</code>). If <code>true</code>, the
-     * {@link #hide} method will be called internally.
+     * Render this Window hidden. If `true`, the {@link #hide} method will be called internally.
      */
     hidden: true,
 
@@ -71182,11 +74518,11 @@ Ext.define('Ext.window.Window', {
     floating: true,
 
     ariaRole: 'alertdialog',
-    
+
     itemCls: 'x-window-item',
 
     overlapHeader: true,
-    
+
     ignoreHeaderBorderManagement: true,
 
     // private
@@ -71199,11 +74535,13 @@ Ext.define('Ext.window.Window', {
              * Fires after the window has been visually activated via {@link #setActive}.
              * @param {Ext.window.Window} this
              */
+
             /**
              * @event deactivate
              * Fires after the window has been visually deactivated via {@link #setActive}.
              * @param {Ext.window.Window} this
              */
+
             /**
              * @event resize
              * Fires after the window has been resized.
@@ -71212,18 +74550,21 @@ Ext.define('Ext.window.Window', {
              * @param {Number} height The window's new height
              */
             'resize',
+
             /**
              * @event maximize
              * Fires after the window has been maximized.
              * @param {Ext.window.Window} this
              */
             'maximize',
+
             /**
              * @event minimize
              * Fires after the window has been minimized.
              * @param {Ext.window.Window} this
              */
             'minimize',
+
             /**
              * @event restore
              * Fires after the window has been restored to its original size after being maximized.
@@ -71289,9 +74630,14 @@ Ext.define('Ext.window.Window', {
     },
 
     // private
-    onMouseDown: function () {
+    onMouseDown: function (e) {
+        var preventFocus;
+            
         if (this.floating) {
-            this.toFront();
+            if (Ext.fly(e.getTarget()).focusable()) {
+                preventFocus = true;
+            }
+            this.toFront(preventFocus);
         }
     },
 
@@ -71329,6 +74675,11 @@ Ext.define('Ext.window.Window', {
 
         // clickToRaise
         me.mon(me.el, 'mousedown', me.onMouseDown, me);
+        
+        // allow the element to be focusable
+        me.el.set({
+            tabIndex: -1
+        });
 
         // Initialize
         if (me.maximized) {
@@ -71364,7 +74715,7 @@ Ext.define('Ext.window.Window', {
         if (!me.header) {
             me.updateHeader(true);
         }
-        
+
         /*
          * Check the header here again. If for whatever reason it wasn't created in
          * updateHeader (preventHeader) then we'll just ignore the rest since the
@@ -71384,16 +74735,14 @@ Ext.define('Ext.window.Window', {
             }
 
             /**
-             * <p>If this Window is configured {@link #draggable}, this property will contain
-             * an instance of {@link Ext.util.ComponentDragger} (A subclass of {@link Ext.dd.DragTracker DragTracker})
-             * which handles dragging the Window's DOM Element, and constraining according to the {@link #constrain}
-             * and {@link #constrainHeader} .</p>
-             * <p>This has implementations of <code>onBeforeStart</code>, <code>onDrag</code> and <code>onEnd</code>
-             * which perform the dragging action. If extra logic is needed at these points, use
-             * {@link Ext.Function#createInterceptor createInterceptor} or {@link Ext.Function#createSequence createSequence} to
-             * augment the existing implementations.</p>
-             * @type Ext.util.ComponentDragger
-             * @property dd
+             * @property {Ext.util.ComponentDragger} dd
+             * If this Window is configured {@link #draggable}, this property will contain an instance of
+             * {@link Ext.util.ComponentDragger} (A subclass of {@link Ext.dd.DragTracker DragTracker}) which handles dragging
+             * the Window's DOM Element, and constraining according to the {@link #constrain} and {@link #constrainHeader} .
+             *
+             * This has implementations of `onBeforeStart`, `onDrag` and `onEnd` which perform the dragging action. If
+             * extra logic is needed at these points, use {@link Ext.Function#createInterceptor createInterceptor} or
+             * {@link Ext.Function#createSequence createSequence} to augment the existing implementations.
              */
             me.dd = Ext.create('Ext.util.ComponentDragger', this, ddConfig);
             me.relayEvents(me.dd, ['dragstart', 'drag', 'dragend']);
@@ -71451,7 +74800,7 @@ Ext.define('Ext.window.Window', {
     },
 
     /**
-     * Gets the configured default focus item.  If a {@link #defaultFocus} is set, it will receive focus, otherwise the
+     * Gets the configured default focus item. If a {@link #defaultFocus} is set, it will receive focus, otherwise the
      * Container itself will receive focus.
      */
     getFocusEl: function() {
@@ -71488,17 +74837,12 @@ Ext.define('Ext.window.Window', {
         var me = this,
             animating = animateTarget || me.animateTarget;
 
-        
-        if (animating) {
-            /*
-             * If we're animating, constrain the positioning before calling the
-             * superclass, otherwise we'll be animating to the unconstrained
-             * window position.
-             */
-            me.doConstrain();
-        }
+
+        // No constraining code needs to go here.
+        // Component.onShow constrains the Component. *If the constrain config is true*
+
         // Perform superclass's afterShow tasks
-        // Which might include animating a proxy from an animTarget
+        // Which might include animating a proxy from an animateTarget
         me.callParent(arguments);
 
         if (me.maximized) {
@@ -71519,13 +74863,15 @@ Ext.define('Ext.window.Window', {
     doClose: function() {
         var me = this;
 
-        // immediate close
+        // Being called as callback after going through the hide call below
         if (me.hidden) {
             me.fireEvent('close', me);
-            me[me.closeAction]();
+            if (me.closeAction == 'destroy') {
+                this.destroy();
+            }
         } else {
             // close after hiding
-            me.hide(me.animTarget, me.doClose, me);
+            me.hide(me.animateTarget, me.doClose, me);
         }
     },
 
@@ -71554,9 +74900,9 @@ Ext.define('Ext.window.Window', {
     },
 
     /**
-     * Placeholder method for minimizing the window.  By default, this method simply fires the {@link #minimize} event
-     * since the behavior of minimizing a window is application-specific.  To implement custom minimize behavior,
-     * either the minimize event can be handled or this method can be overridden.
+     * Placeholder method for minimizing the window. By default, this method simply fires the {@link #minimize} event
+     * since the behavior of minimizing a window is application-specific. To implement custom minimize behavior, either
+     * the minimize event can be handled or this method can be overridden.
      * @return {Ext.window.Window} this
      */
     minimize: function() {
@@ -71592,9 +74938,8 @@ Ext.define('Ext.window.Window', {
     },
 
     /**
-     * Fits the window within its current container and automatically replaces
-     * the {@link #maximizable 'maximize' tool button} with the 'restore' tool button.
-     * Also see {@link #toggleMaximize}.
+     * Fits the window within its current container and automatically replaces the {@link #maximizable 'maximize' tool
+     * button} with the 'restore' tool button. Also see {@link #toggleMaximize}.
      * @return {Ext.window.Window} this
      */
     maximize: function() {
@@ -71631,10 +74976,8 @@ Ext.define('Ext.window.Window', {
     },
 
     /**
-     * Restores a {@link #maximizable maximized}  window back to its original
-     * size and position prior to being maximized and also replaces
-     * the 'restore' tool button with the 'maximize' tool button.
-     * Also see {@link #toggleMaximize}.
+     * Restores a {@link #maximizable maximized} window back to its original size and position prior to being maximized
+     * and also replaces the 'restore' tool button with the 'maximize' tool button. Also see {@link #toggleMaximize}.
      * @return {Ext.window.Window} this
      */
     restore: function() {
@@ -71724,89 +75067,86 @@ Ext.define('Ext.window.Window', {
      * A width is a required configuration.
      **/
 });
-/**
- * @class Ext.form.field.Base
- * @extends Ext.Component
-
-Base class for form fields that provides default event handling, rendering, and other common functionality
-needed by all form field types. Utilizes the {@link Ext.form.field.Field} mixin for value handling and validation,
-and the {@link Ext.form.Labelable} mixin to provide label and error message display.
-
-In most cases you will want to use a subclass, such as {@link Ext.form.field.Text} or {@link Ext.form.field.Checkbox},
-rather than creating instances of this class directly. However if you are implementing a custom form field,
-using this as the parent class is recommended.
-
-__Values and Conversions__
-
-Because BaseField implements the Field mixin, it has a main value that can be initialized with the
-{@link #value} config and manipulated via the {@link #getValue} and {@link #setValue} methods. This main
-value can be one of many data types appropriate to the current field, for instance a {@link Ext.form.field.Date Date}
-field would use a JavaScript Date object as its value type. However, because the field is rendered as a HTML
-input, this value data type can not always be directly used in the rendered field.
-
-Therefore BaseField introduces the concept of a "raw value". This is the value of the rendered HTML input field,
-and is normally a String. The {@link #getRawValue} and {@link #setRawValue} methods can be used to directly
-work with the raw value, though it is recommended to use getValue and setValue in most cases.
-
-Conversion back and forth between the main value and the raw value is handled by the {@link #valueToRaw} and
-{@link #rawToValue} methods. If you are implementing a subclass that uses a non-String value data type, you
-should override these methods to handle the conversion.
-
-__Rendering__
-
-The content of the field body is defined by the {@link #fieldSubTpl} XTemplate, with its argument data
-created by the {@link #getSubTplData} method. Override this template and/or method to create custom
-field renderings.
-{@img Ext.form.BaseField/Ext.form.BaseField.png Ext.form.BaseField BaseField component}
-__Example usage:__
-
-    // A simple subclass of BaseField that creates a HTML5 search field. Redirects to the
-    // searchUrl when the Enter key is pressed.
-    Ext.define('Ext.form.SearchField', {
-        extend: 'Ext.form.field.Base',
-        alias: 'widget.searchfield',
-    
-        inputType: 'search',
-    
-        // Config defining the search URL
-        searchUrl: 'http://www.google.com/search?q={0}',
-    
-        // Add specialkey listener
-        initComponent: function() {
-            this.callParent();
-            this.on('specialkey', this.checkEnterKey, this);
-        },
-    
-        // Handle enter key presses, execute the search if the field has a value
-        checkEnterKey: function(field, e) {
-            var value = this.getValue();
-            if (e.getKey() === e.ENTER && !Ext.isEmpty(value)) {
-                location.href = Ext.String.format(this.searchUrl, value);
-            }
-        }
-    });
-
-    Ext.create('Ext.form.Panel', {
-        title: 'BaseField Example',
-        bodyPadding: 5,
-        width: 250,
-                
-        // Fields will be arranged vertically, stretched to full width
-        layout: 'anchor',
-        defaults: {
-            anchor: '100%'
-        },
-        items: [{
-            xtype: 'searchfield',
-            fieldLabel: 'Search',
-            name: 'query'
-        }]
-        renderTo: Ext.getBody()
-    });
 
- *
- * @markdown
+/**
  * @docauthor Jason Johnston <jason@sencha.com>
+ *
+ * Base class for form fields that provides default event handling, rendering, and other common functionality
+ * needed by all form field types. Utilizes the {@link Ext.form.field.Field} mixin for value handling and validation,
+ * and the {@link Ext.form.Labelable} mixin to provide label and error message display.
+ *
+ * In most cases you will want to use a subclass, such as {@link Ext.form.field.Text} or {@link Ext.form.field.Checkbox},
+ * rather than creating instances of this class directly. However if you are implementing a custom form field,
+ * using this as the parent class is recommended.
+ *
+ * # Values and Conversions
+ *
+ * Because BaseField implements the Field mixin, it has a main value that can be initialized with the
+ * {@link #value} config and manipulated via the {@link #getValue} and {@link #setValue} methods. This main
+ * value can be one of many data types appropriate to the current field, for instance a {@link Ext.form.field.Date Date}
+ * field would use a JavaScript Date object as its value type. However, because the field is rendered as a HTML
+ * input, this value data type can not always be directly used in the rendered field.
+ *
+ * Therefore BaseField introduces the concept of a "raw value". This is the value of the rendered HTML input field,
+ * and is normally a String. The {@link #getRawValue} and {@link #setRawValue} methods can be used to directly
+ * work with the raw value, though it is recommended to use getValue and setValue in most cases.
+ *
+ * Conversion back and forth between the main value and the raw value is handled by the {@link #valueToRaw} and
+ * {@link #rawToValue} methods. If you are implementing a subclass that uses a non-String value data type, you
+ * should override these methods to handle the conversion.
+ *
+ * # Rendering
+ *
+ * The content of the field body is defined by the {@link #fieldSubTpl} XTemplate, with its argument data
+ * created by the {@link #getSubTplData} method. Override this template and/or method to create custom
+ * field renderings.
+ *
+ * # Example usage:
+ *
+ *     @example
+ *     // A simple subclass of BaseField that creates a HTML5 search field. Redirects to the
+ *     // searchUrl when the Enter key is pressed.222
+ *     Ext.define('Ext.form.SearchField', {
+ *         extend: 'Ext.form.field.Base',
+ *         alias: 'widget.searchfield',
+ *     
+ *         inputType: 'search',
+ *     
+ *         // Config defining the search URL
+ *         searchUrl: 'http://www.google.com/search?q={0}',
+ *     
+ *         // Add specialkey listener
+ *         initComponent: function() {
+ *             this.callParent();
+ *             this.on('specialkey', this.checkEnterKey, this);
+ *         },
+ *     
+ *         // Handle enter key presses, execute the search if the field has a value
+ *         checkEnterKey: function(field, e) {
+ *             var value = this.getValue();
+ *             if (e.getKey() === e.ENTER && !Ext.isEmpty(value)) {
+ *                 location.href = Ext.String.format(this.searchUrl, value);
+ *             }
+ *         }
+ *     });
+ *     
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'BaseField Example',
+ *         bodyPadding: 5,
+ *         width: 250,
+ *     
+ *         // Fields will be arranged vertically, stretched to full width
+ *         layout: 'anchor',
+ *         defaults: {
+ *             anchor: '100%'
+ *         },
+ *         items: [{
+ *             xtype: 'searchfield',
+ *             fieldLabel: 'Search',
+ *             name: 'query'
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.form.field.Base', {
     extend: 'Ext.Component',
@@ -71818,7 +75158,11 @@ Ext.define('Ext.form.field.Base', {
     alternateClassName: ['Ext.form.Field', 'Ext.form.BaseField'],
     requires: ['Ext.util.DelayedTask', 'Ext.XTemplate', 'Ext.layout.component.field.Field'],
 
-    fieldSubTpl: [
+    /**
+     * @cfg {Ext.XTemplate} fieldSubTpl
+     * The content of the field body is defined by this config option.
+     */
+    fieldSubTpl: [ // note: {id} here is really {inputId}, but {cmpId} is available
         '<input id="{id}" type="{type}" ',
         '<tpl if="name">name="{name}" </tpl>',
         '<tpl if="size">size="{size}" </tpl>',
@@ -71831,74 +75175,80 @@ Ext.define('Ext.form.field.Base', {
     ],
 
     /**
-     * @cfg {String} name The name of the field (defaults to undefined). This is used as the parameter
-     * name when including the field value in a {@link Ext.form.Basic#submit form submit()}. If no name is
-     * configured, it falls back to the {@link #inputId}. To prevent the field from being included in the
-     * form submit, set {@link #submitValue} to <tt>false</tt>.
+     * @cfg {String} name
+     * The name of the field. This is used as the parameter name when including the field value
+     * in a {@link Ext.form.Basic#submit form submit()}. If no name is configured, it falls back to the {@link #inputId}.
+     * To prevent the field from being included in the form submit, set {@link #submitValue} to false.
      */
 
     /**
      * @cfg {String} inputType
-     * <p>The type attribute for input fields -- e.g. radio, text, password, file (defaults to <tt>'text'</tt>).
-     * The extended types supported by HTML5 inputs (url, email, etc.) may also be used, though using them
-     * will cause older browsers to fall back to 'text'.</p>
-     * <p>The type 'password' must be used to render that field type currently -- there is no separate Ext
-     * component for that. You can use {@link Ext.form.field.File} which creates a custom-rendered file upload
-     * field, but if you want a plain unstyled file input you can use a BaseField with inputType:'file'.</p>
+     * The type attribute for input fields -- e.g. radio, text, password, file. The extended types
+     * supported by HTML5 inputs (url, email, etc.) may also be used, though using them will cause older browsers to
+     * fall back to 'text'.
+     *
+     * The type 'password' must be used to render that field type currently -- there is no separate Ext component for
+     * that. You can use {@link Ext.form.field.File} which creates a custom-rendered file upload field, but if you want
+     * a plain unstyled file input you can use a BaseField with inputType:'file'.
      */
     inputType: 'text',
 
     /**
-     * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered,
-     * not those which are built via applyTo (defaults to undefined).
+     * @cfg {Number} tabIndex
+     * The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via
+     * applyTo
      */
 
     /**
-     * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided
-     * (defaults to 'The value in this field is invalid')
+     * @cfg {String} invalidText
+     * The error text to use when marking a field invalid and no message is provided
      */
     invalidText : 'The value in this field is invalid',
 
     /**
-     * @cfg {String} fieldCls The default CSS class for the field input (defaults to 'x-form-field')
+     * @cfg {String} [fieldCls='x-form-field']
+     * The default CSS class for the field input
      */
     fieldCls : Ext.baseCSSPrefix + 'form-field',
 
     /**
-     * @cfg {String} fieldStyle Optional CSS style(s) to be applied to the {@link #inputEl field input element}.
-     * Should be a valid argument to {@link Ext.core.Element#applyStyles}. Defaults to undefined. See also the
-     * {@link #setFieldStyle} method for changing the style after initialization.
+     * @cfg {String} fieldStyle
+     * Optional CSS style(s) to be applied to the {@link #inputEl field input element}. Should be a valid argument to
+     * {@link Ext.Element#applyStyles}. Defaults to undefined. See also the {@link #setFieldStyle} method for changing
+     * the style after initialization.
      */
 
     /**
-     * @cfg {String} focusCls The CSS class to use when the field receives focus (defaults to 'x-form-focus')
+     * @cfg {String} [focusCls='x-form-focus']
+     * The CSS class to use when the field receives focus
      */
     focusCls : Ext.baseCSSPrefix + 'form-focus',
 
     /**
-     * @cfg {String} dirtyCls The CSS class to use when the field value {@link #isDirty is dirty}.
+     * @cfg {String} dirtyCls
+     * The CSS class to use when the field value {@link #isDirty is dirty}.
      */
     dirtyCls : Ext.baseCSSPrefix + 'form-dirty',
 
     /**
-     * @cfg {Array} checkChangeEvents
-     * <p>A list of event names that will be listened for on the field's {@link #inputEl input element}, which
-     * will cause the field's value to be checked for changes. If a change is detected, the
-     * {@link #change change event} will be fired, followed by validation if the {@link #validateOnChange}
-     * option is enabled.</p>
-     * <p>Defaults to <tt>['change', 'propertychange']</tt> in Internet Explorer, and <tt>['change', 'input',
-     * 'textInput', 'keyup', 'dragdrop']</tt> in other browsers. This catches all the ways that field values
-     * can be changed in most supported browsers; the only known exceptions at the time of writing are:</p>
-     * <ul>
-     * <li>Safari 3.2 and older: cut/paste in textareas via the context menu, and dragging text into textareas</li>
-     * <li>Opera 10 and 11: dragging text into text fields and textareas, and cut via the context menu in text
-     * fields and textareas</li>
-     * <li>Opera 9: Same as Opera 10 and 11, plus paste from context menu in text fields and textareas</li>
-     * </ul>
-     * <p>If you need to guarantee on-the-fly change notifications including these edge cases, you can call the
-     * {@link #checkChange} method on a repeating interval, e.g. using {@link Ext.TaskManager}, or if the field is
-     * within a {@link Ext.form.Panel}, you can use the FormPanel's {@link Ext.form.Panel#pollForChanges}
-     * configuration to set up such a task automatically.</p>
+     * @cfg {String[]} checkChangeEvents
+     * A list of event names that will be listened for on the field's {@link #inputEl input element}, which will cause
+     * the field's value to be checked for changes. If a change is detected, the {@link #change change event} will be
+     * fired, followed by validation if the {@link #validateOnChange} option is enabled.
+     *
+     * Defaults to ['change', 'propertychange'] in Internet Explorer, and ['change', 'input', 'textInput', 'keyup',
+     * 'dragdrop'] in other browsers. This catches all the ways that field values can be changed in most supported
+     * browsers; the only known exceptions at the time of writing are:
+     *
+     *   - Safari 3.2 and older: cut/paste in textareas via the context menu, and dragging text into textareas
+     *   - Opera 10 and 11: dragging text into text fields and textareas, and cut via the context menu in text fields
+     *     and textareas
+     *   - Opera 9: Same as Opera 10 and 11, plus paste from context menu in text fields and textareas
+     *
+     * If you need to guarantee on-the-fly change notifications including these edge cases, you can call the
+     * {@link #checkChange} method on a repeating interval, e.g. using {@link Ext.TaskManager}, or if the field is within
+     * a {@link Ext.form.Panel}, you can use the FormPanel's {@link Ext.form.Panel#pollForChanges} configuration to set up
+     * such a task automatically.
      */
     checkChangeEvents: Ext.isIE && (!document.documentMode || document.documentMode < 9) ?
                         ['change', 'propertychange'] :
@@ -71914,40 +75264,40 @@ Ext.define('Ext.form.field.Base', {
     componentLayout: 'field',
 
     /**
-     * @cfg {Boolean} readOnly <tt>true</tt> to mark the field as readOnly in HTML
-     * (defaults to <tt>false</tt>).
-     * <br><p><b>Note</b>: this only sets the element's readOnly DOM attribute.
-     * Setting <code>readOnly=true</code>, for example, will not disable triggering a
-     * ComboBox or Date; it gives you the option of forcing the user to choose
-     * via the trigger without typing in the text box. To hide the trigger use
-     * <code>{@link Ext.form.field.Trigger#hideTrigger hideTrigger}</code>.</p>
+     * @cfg {Boolean} readOnly
+     * true to mark the field as readOnly in HTML.
+     *
+     * **Note**: this only sets the element's readOnly DOM attribute. Setting `readOnly=true`, for example, will not
+     * disable triggering a ComboBox or Date; it gives you the option of forcing the user to choose via the trigger
+     * without typing in the text box. To hide the trigger use `{@link Ext.form.field.Trigger#hideTrigger hideTrigger}`.
      */
     readOnly : false,
 
     /**
-     * @cfg {String} readOnlyCls The CSS class applied to the component's main element when it is {@link #readOnly}.
+     * @cfg {String} readOnlyCls
+     * The CSS class applied to the component's main element when it is {@link #readOnly}.
      */
     readOnlyCls: Ext.baseCSSPrefix + 'form-readonly',
 
     /**
      * @cfg {String} inputId
-     * The id that will be given to the generated input DOM element. Defaults to an automatically generated id.
-     * If you configure this manually, you must make sure it is unique in the document.
+     * The id that will be given to the generated input DOM element. Defaults to an automatically generated id. If you
+     * configure this manually, you must make sure it is unique in the document.
      */
 
     /**
      * @cfg {Boolean} validateOnBlur
-     * Whether the field should validate when it loses focus (defaults to <tt>true</tt>). This will cause fields
-     * to be validated as the user steps through the fields in the form regardless of whether they are making
-     * changes to those fields along the way. See also {@link #validateOnChange}.
+     * Whether the field should validate when it loses focus. This will cause fields to be validated
+     * as the user steps through the fields in the form regardless of whether they are making changes to those fields
+     * along the way. See also {@link #validateOnChange}.
      */
     validateOnBlur: true,
 
     // private
     hasFocus : false,
-    
+
     baseCls: Ext.baseCSSPrefix + 'field',
-    
+
     maskOnDisable: false,
 
     // private
@@ -71973,34 +75323,34 @@ Ext.define('Ext.form.field.Base', {
             'blur',
             /**
              * @event specialkey
-             * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.
-             * To handle other keys see {@link Ext.panel.Panel#keys} or {@link Ext.util.KeyMap}.
-             * You can check {@link Ext.EventObject#getKey} to determine which key was pressed.
-             * For example: <pre><code>
-var form = new Ext.form.Panel({
-    ...
-    items: [{
-            fieldLabel: 'Field 1',
-            name: 'field1',
-            allowBlank: false
-        },{
-            fieldLabel: 'Field 2',
-            name: 'field2',
-            listeners: {
-                specialkey: function(field, e){
-                    // e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,
-                    // e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN
-                    if (e.{@link Ext.EventObject#getKey getKey()} == e.ENTER) {
-                        var form = field.up('form').getForm();
-                        form.submit();
-                    }
-                }
-            }
-        }
-    ],
-    ...
-});
-             * </code></pre>
+             * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. To handle other keys
+             * see {@link Ext.util.KeyMap}. You can check {@link Ext.EventObject#getKey} to determine which key was
+             * pressed. For example:
+             *
+             *     var form = new Ext.form.Panel({
+             *         ...
+             *         items: [{
+             *                 fieldLabel: 'Field 1',
+             *                 name: 'field1',
+             *                 allowBlank: false
+             *             },{
+             *                 fieldLabel: 'Field 2',
+             *                 name: 'field2',
+             *                 listeners: {
+             *                     specialkey: function(field, e){
+             *                         // e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,
+             *                         // e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN
+             *                         if (e.{@link Ext.EventObject#getKey getKey()} == e.ENTER) {
+             *                             var form = field.up('form').getForm();
+             *                             form.submit();
+             *                         }
+             *                     }
+             *                 }
+             *             }
+             *         ],
+             *         ...
+             *     });
+             *
              * @param {Ext.form.field.Base} this
              * @param {Ext.EventObject} e The event object
              */
@@ -72018,16 +75368,17 @@ var form = new Ext.form.Panel({
     },
 
     /**
-     * Returns the input id for this field. If none was specified via the {@link #inputId} config,
-     * then an id will be automatically generated.
+     * Returns the input id for this field. If none was specified via the {@link #inputId} config, then an id will be
+     * automatically generated.
      */
     getInputId: function() {
         return this.inputId || (this.inputId = Ext.id());
     },
 
     /**
-     * @protected Creates and returns the data object to be used when rendering the {@link #fieldSubTpl}.
+     * Creates and returns the data object to be used when rendering the {@link #fieldSubTpl}.
      * @return {Object} The template data
+     * @template
      */
     getSubTplData: function() {
         var me = this,
@@ -72036,6 +75387,7 @@ var form = new Ext.form.Panel({
 
         return Ext.applyIf(me.subTplData, {
             id: inputId,
+            cmpId: me.id,
             name: me.name || inputId,
             type: type,
             size: me.size || 20,
@@ -72046,10 +75398,16 @@ var form = new Ext.form.Panel({
         });
     },
 
+    afterRender: function() {
+        this.callParent();
+        
+        if (this.inputEl) {
+            this.inputEl.selectable();
+        }
+    },
+
     /**
-     * @protected
-     * Gets the markup to be inserted into the outer template's bodyEl. For fields this is the
-     * actual input element.
+     * Gets the markup to be inserted into the outer template's bodyEl. For fields this is the actual input element.
      */
     getSubTplMarkup: function() {
         return this.getTpl('fieldSubTpl').apply(this.getSubTplData());
@@ -72069,8 +75427,8 @@ var form = new Ext.form.Panel({
 
     /**
      * Set the {@link #fieldStyle CSS style} of the {@link #inputEl field input element}.
-     * @param {String/Object/Function} style The style(s) to apply. Should be a valid argument to
-     * {@link Ext.core.Element#applyStyles}.
+     * @param {String/Object/Function} style The style(s) to apply. Should be a valid argument to {@link
+     * Ext.Element#applyStyles}.
      */
     setFieldStyle: function(style) {
         var me = this,
@@ -72084,19 +75442,15 @@ var form = new Ext.form.Panel({
     // private
     onRender : function() {
         var me = this,
-            fieldStyle = me.fieldStyle,
-            renderSelectors = me.renderSelectors;
+            fieldStyle = me.fieldStyle;
 
-        Ext.applyIf(renderSelectors, me.getLabelableSelectors());
+        me.onLabelableRender();
 
-        Ext.applyIf(renderSelectors, {
-            /**
-             * @property inputEl
-             * @type Ext.core.Element
-             * The input Element for this Field. Only available after the field has been rendered.
-             */
-            inputEl: '.' + me.fieldCls
-        });
+        /**
+         * @property {Ext.Element} inputEl
+         * The input Element for this Field. Only available after the field has been rendered.
+         */
+        me.addChildEls({ name: 'inputEl', id: me.getInputId() });
 
         me.callParent(arguments);
 
@@ -72160,21 +75514,22 @@ var form = new Ext.form.Panel({
     },
 
     /**
-     * <p>Returns the value that would be included in a standard form submit for this field. This will be combined
-     * with the field's name to form a <tt>name=value</tt> pair in the {@link #getSubmitData submitted parameters}.
-     * If an empty string is returned then just the <tt>name=</tt> will be submitted; if <tt>null</tt> is returned
-     * then nothing will be submitted.</p>
-     * <p>Note that the value returned will have been {@link #processRawValue processed} but may or may not have
-     * been successfully {@link #validate validated}.</p>
-     * @return {String} The value to be submitted, or <tt>null</tt>.
+     * Returns the value that would be included in a standard form submit for this field. This will be combined with the
+     * field's name to form a name=value pair in the {@link #getSubmitData submitted parameters}. If an empty string is
+     * returned then just the name= will be submitted; if null is returned then nothing will be submitted.
+     *
+     * Note that the value returned will have been {@link #processRawValue processed} but may or may not have been
+     * successfully {@link #validate validated}.
+     *
+     * @return {String} The value to be submitted, or null.
      */
     getSubmitValue: function() {
         return this.processRawValue(this.getRawValue());
     },
 
     /**
-     * Returns the raw value of the field, without performing any normalization, conversion, or validation.
-     * To get a normalized and converted value see {@link #getValue}.
+     * Returns the raw value of the field, without performing any normalization, conversion, or validation. To get a
+     * normalized and converted value see {@link #getValue}.
      * @return {String} value The raw String value of the field
      */
     getRawValue: function() {
@@ -72187,8 +75542,8 @@ var form = new Ext.form.Panel({
     /**
      * Sets the field's raw value directly, bypassing {@link #valueToRaw value conversion}, change detection, and
      * validation. To set the value with these additional inspections see {@link #setValue}.
-     * @param {Mixed} value The value to set
-     * @return {Mixed} value The field value that is set
+     * @param {Object} value The value to set
+     * @return {Object} value The field value that is set
      */
     setRawValue: function(value) {
         var me = this;
@@ -72203,41 +75558,49 @@ var form = new Ext.form.Panel({
     },
 
     /**
-     * <p>Converts a mixed-type value to a raw representation suitable for displaying in the field. This allows
-     * controlling how value objects passed to {@link #setValue} are shown to the user, including localization.
-     * For instance, for a {@link Ext.form.field.Date}, this would control how a Date object passed to {@link #setValue}
-     * would be converted to a String for display in the field.</p>
-     * <p>See {@link #rawToValue} for the opposite conversion.</p>
-     * <p>The base implementation simply does a standard toString conversion, and converts
-     * {@link Ext#isEmpty empty values} to an empty string.</p>
-     * @param {Mixed} value The mixed-type value to convert to the raw representation.
-     * @return {Mixed} The converted raw value.
+     * Converts a mixed-type value to a raw representation suitable for displaying in the field. This allows controlling
+     * how value objects passed to {@link #setValue} are shown to the user, including localization. For instance, for a
+     * {@link Ext.form.field.Date}, this would control how a Date object passed to {@link #setValue} would be converted
+     * to a String for display in the field.
+     *
+     * See {@link #rawToValue} for the opposite conversion.
+     *
+     * The base implementation simply does a standard toString conversion, and converts {@link Ext#isEmpty empty values}
+     * to an empty string.
+     *
+     * @param {Object} value The mixed-type value to convert to the raw representation.
+     * @return {Object} The converted raw value.
      */
     valueToRaw: function(value) {
         return '' + Ext.value(value, '');
     },
 
     /**
-     * <p>Converts a raw input field value into a mixed-type value that is suitable for this particular field type.
-     * This allows controlling the normalization and conversion of user-entered values into field-type-appropriate
-     * values, e.g. a Date object for {@link Ext.form.field.Date}, and is invoked by {@link #getValue}.</p>
-     * <p>It is up to individual implementations to decide how to handle raw values that cannot be successfully
-     * converted to the desired object type.</p>
-     * <p>See {@link #valueToRaw} for the opposite conversion.</p>
-     * <p>The base implementation does no conversion, returning the raw value untouched.</p>
-     * @param {Mixed} rawValue
-     * @return {Mixed} The converted value.
+     * Converts a raw input field value into a mixed-type value that is suitable for this particular field type. This
+     * allows controlling the normalization and conversion of user-entered values into field-type-appropriate values,
+     * e.g. a Date object for {@link Ext.form.field.Date}, and is invoked by {@link #getValue}.
+     *
+     * It is up to individual implementations to decide how to handle raw values that cannot be successfully converted
+     * to the desired object type.
+     *
+     * See {@link #valueToRaw} for the opposite conversion.
+     *
+     * The base implementation does no conversion, returning the raw value untouched.
+     *
+     * @param {Object} rawValue
+     * @return {Object} The converted value.
      */
     rawToValue: function(rawValue) {
         return rawValue;
     },
 
     /**
-     * Performs any necessary manipulation of a raw field value to prepare it for {@link #rawToValue conversion}
-     * and/or {@link #validate validation}, for instance stripping out ignored characters. In the base implementation
-     * it does nothing; individual subclasses may override this as needed.
-     * @param {Mixed} value The unprocessed string value
-     * @return {Mixed} The processed string value
+     * Performs any necessary manipulation of a raw field value to prepare it for {@link #rawToValue conversion} and/or
+     * {@link #validate validation}, for instance stripping out ignored characters. In the base implementation it does
+     * nothing; individual subclasses may override this as needed.
+     *
+     * @param {Object} value The unprocessed string value
+     * @return {Object} The processed string value
      */
     processRawValue: function(value) {
         return value;
@@ -72247,7 +75610,7 @@ var form = new Ext.form.Panel({
      * Returns the current data value of the field. The type of value returned is particular to the type of the
      * particular field (e.g. a Date object for {@link Ext.form.field.Date}), as the result of calling {@link #rawToValue} on
      * the field's {@link #processRawValue processed} String value. To return the raw String value, see {@link #getRawValue}.
-     * @return {Mixed} value The field value
+     * @return {Object} value The field value
      */
     getValue: function() {
         var me = this,
@@ -72259,7 +75622,7 @@ var form = new Ext.form.Panel({
     /**
      * Sets a data value into the field and runs the change detection and validation. To set the value directly
      * without these inspections see {@link #setRawValue}.
-     * @param {Mixed} value The value to set
+     * @param {Object} value The value to set
      * @return {Ext.form.field.Field} this
      */
     setValue: function(value) {
@@ -72373,6 +75736,7 @@ var form = new Ext.form.Panel({
         }
         if (!me.hasFocus) {
             me.hasFocus = true;
+            me.componentLayout.onFocus();
             me.fireEvent('focus', me);
         }
     },
@@ -72385,6 +75749,11 @@ var form = new Ext.form.Panel({
         var me = this,
             focusCls = me.focusCls,
             inputEl = me.inputEl;
+
+        if (me.destroying) {
+            return;
+        }
+
         me.beforeBlur();
         if (focusCls && inputEl) {
             inputEl.removeCls(focusCls);
@@ -72411,9 +75780,10 @@ var form = new Ext.form.Panel({
 
 
     /**
-     * Returns whether or not the field value is currently valid by
-     * {@link #getErrors validating} the {@link #processRawValue processed raw value}
-     * of the field. <b>Note</b>: {@link #disabled} fields are always treated as valid.
+     * Returns whether or not the field value is currently valid by {@link #getErrors validating} the
+     * {@link #processRawValue processed raw value} of the field. **Note**: {@link #disabled} fields are
+     * always treated as valid.
+     *
      * @return {Boolean} True if the value is valid, else false
      */
     isValid : function() {
@@ -72423,11 +75793,13 @@ var form = new Ext.form.Panel({
 
 
     /**
-     * <p>Uses {@link #getErrors} to build an array of validation errors. If any errors are found, they are passed
-     * to {@link #markInvalid} and false is returned, otherwise true is returned.</p>
-     * <p>Previously, subclasses were invited to provide an implementation of this to process validations - from 3.2
-     * onwards {@link #getErrors} should be overridden instead.</p>
-     * @param {Mixed} value The value to validate
+     * Uses {@link #getErrors} to build an array of validation errors. If any errors are found, they are passed to
+     * {@link #markInvalid} and false is returned, otherwise true is returned.
+     *
+     * Previously, subclasses were invited to provide an implementation of this to process validations - from 3.2
+     * onwards {@link #getErrors} should be overridden instead.
+     *
+     * @param {Object} value The value to validate
      * @return {Boolean} True if all validations passed, false if one or more failed
      */
     validateValue: function(value) {
@@ -72446,13 +75818,14 @@ var form = new Ext.form.Panel({
     },
 
     /**
-     * <p>Display one or more error messages associated with this field, using {@link #msgTarget} to determine how to
-     * display the messages and applying {@link #invalidCls} to the field's UI element.</p>
-     * <p><b>Note</b>: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to
-     * return <code>false</code> if the value does <i>pass</i> validation. So simply marking a Field as invalid
-     * will not prevent submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation}
-     * option set.</p>
-     * @param {String/Array} errors The validation message(s) to display.
+     * Display one or more error messages associated with this field, using {@link #msgTarget} to determine how to
+     * display the messages and applying {@link #invalidCls} to the field's UI element.
+     *
+     * **Note**: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to return `false`
+     * if the value does _pass_ validation. So simply marking a Field as invalid will not prevent submission of forms
+     * submitted with the {@link Ext.form.action.Submit#clientValidation} option set.
+     *
+     * @param {String/String[]} errors The validation message(s) to display.
      */
     markInvalid : function(errors) {
         // Save the message and fire the 'invalid' event
@@ -72465,11 +75838,11 @@ var form = new Ext.form.Panel({
     },
 
     /**
-     * <p>Clear any invalid styles/messages for this field.</p>
-     * <p><b>Note</b>: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to
-     * return <code>true</code> if the value does not <i>pass</i> validation. So simply clearing a field's errors
-     * will not necessarily allow submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation}
-     * option set.</p>
+     * Clear any invalid styles/messages for this field.
+     *
+     * **Note**: this method does not cause the Field's {@link #validate} or {@link #isValid} methods to return `true`
+     * if the value does not _pass_ validation. So simply clearing a field's errors will not necessarily allow
+     * submission of forms submitted with the {@link Ext.form.action.Submit#clientValidation} option set.
      */
     clearInvalid : function() {
         // Clear the message and fire the 'valid' event
@@ -72503,65 +75876,61 @@ var form = new Ext.form.Panel({
 });
 
 /**
- * @class Ext.form.field.Text
- * @extends Ext.form.field.Base
-A basic text field.  Can be used as a direct replacement for traditional text inputs,
-or as the base class for more sophisticated input controls (like {@link Ext.form.field.TextArea}
-and {@link Ext.form.field.ComboBox}). Has support for empty-field placeholder values (see {@link #emptyText}).
-
-#Validation#
-
-The Text field has a useful set of validations built in:
-
-- {@link #allowBlank} for making the field required
-- {@link #minLength} for requiring a minimum value length
-- {@link #maxLength} for setting a maximum value length (with {@link #enforceMaxLength} to add it
-  as the `maxlength` attribute on the input element)
-- {@link #regex} to specify a custom regular expression for validation
-
-In addition, custom validations may be added:
-- {@link #vtype} specifies a virtual type implementation from {@link Ext.form.field.VTypes} which can contain
-  custom validation logic
-- {@link #validator} allows a custom arbitrary function to be called during validation
-
-The details around how and when each of these validation options get used are described in the
-documentation for {@link #getErrors}.
-
-By default, the field value is checked for validity immediately while the user is typing in the
-field. This can be controlled with the {@link #validateOnChange}, {@link #checkChangeEvents}, and
-{@link #checkChangeBugger} configurations. Also see the details on Form Validation in the
-{@link Ext.form.Panel} class documentation.
-
-#Masking and Character Stripping#
-
-Text fields can be configured with custom regular expressions to be applied to entered values before
-validation: see {@link #maskRe} and {@link #stripCharsRe} for details.
-{@img Ext.form.Text/Ext.form.Text.png Ext.form.Text component}
-#Example usage:#
-
-    Ext.create('Ext.form.Panel', {
-        title: 'Contact Info',
-        width: 300,
-        bodyPadding: 10,
-        renderTo: Ext.getBody(),        
-        items: [{
-            xtype: 'textfield',
-            name: 'name',
-            fieldLabel: 'Name',
-            allowBlank: false  // requires a non-empty value
-        }, {
-            xtype: 'textfield',
-            name: 'email',
-            fieldLabel: 'Email Address',
-            vtype: 'email'  // requires value to be a valid email address format
-        }]
-    }); 
-
- *
- * @markdown
  * @docauthor Jason Johnston <jason@sencha.com>
+ *
+ * A basic text field.  Can be used as a direct replacement for traditional text inputs,
+ * or as the base class for more sophisticated input controls (like {@link Ext.form.field.TextArea}
+ * and {@link Ext.form.field.ComboBox}). Has support for empty-field placeholder values (see {@link #emptyText}).
+ *
+ * # Validation
+ *
+ * The Text field has a useful set of validations built in:
+ *
+ * - {@link #allowBlank} for making the field required
+ * - {@link #minLength} for requiring a minimum value length
+ * - {@link #maxLength} for setting a maximum value length (with {@link #enforceMaxLength} to add it
+ *   as the `maxlength` attribute on the input element)
+ * - {@link #regex} to specify a custom regular expression for validation
+ *
+ * In addition, custom validations may be added:
+ *
+ * - {@link #vtype} specifies a virtual type implementation from {@link Ext.form.field.VTypes} which can contain
+ *   custom validation logic
+ * - {@link #validator} allows a custom arbitrary function to be called during validation
+ *
+ * The details around how and when each of these validation options get used are described in the
+ * documentation for {@link #getErrors}.
+ *
+ * By default, the field value is checked for validity immediately while the user is typing in the
+ * field. This can be controlled with the {@link #validateOnChange}, {@link #checkChangeEvents}, and
+ * {@link #checkChangeBuffer} configurations. Also see the details on Form Validation in the
+ * {@link Ext.form.Panel} class documentation.
+ *
+ * # Masking and Character Stripping
+ *
+ * Text fields can be configured with custom regular expressions to be applied to entered values before
+ * validation: see {@link #maskRe} and {@link #stripCharsRe} for details.
+ *
+ * # Example usage
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'Contact Info',
+ *         width: 300,
+ *         bodyPadding: 10,
+ *         renderTo: Ext.getBody(),
+ *         items: [{
+ *             xtype: 'textfield',
+ *             name: 'name',
+ *             fieldLabel: 'Name',
+ *             allowBlank: false  // requires a non-empty value
+ *         }, {
+ *             xtype: 'textfield',
+ *             name: 'email',
+ *             fieldLabel: 'Email Address',
+ *             vtype: 'email'  // requires value to be a valid email address format
+ *         }]
+ *     });
  */
 Ext.define('Ext.form.field.Text', {
     extend:'Ext.form.field.Base',
@@ -72570,161 +75939,168 @@ Ext.define('Ext.form.field.Text', {
     alternateClassName: ['Ext.form.TextField', 'Ext.form.Text'],
 
     /**
-     * @cfg {String} vtypeText A custom error message to display in place of the default message provided
-     * for the <b><code>{@link #vtype}</code></b> currently set for this field (defaults to <tt>undefined</tt>).
-     * <b>Note</b>: only applies if <b><code>{@link #vtype}</code></b> is set, else ignored.
+     * @cfg {String} vtypeText
+     * A custom error message to display in place of the default message provided for the **`{@link #vtype}`** currently
+     * set for this field. **Note**: only applies if **`{@link #vtype}`** is set, else ignored.
      */
-    
+
     /**
-     * @cfg {RegExp} stripCharsRe A JavaScript RegExp object used to strip unwanted content from the value
-     * before validation (defaults to <tt>undefined</tt>).
+     * @cfg {RegExp} stripCharsRe
+     * A JavaScript RegExp object used to strip unwanted content from the value
+     * before validation. If <tt>stripCharsRe</tt> is specified,
+     * every character matching <tt>stripCharsRe</tt> will be removed before fed to validation.
+     * This does not change the value of the field.
      */
 
     /**
-     * @cfg {Number} size An initial value for the 'size' attribute on the text input element. This is only
-     * used if the field has no configured {@link #width} and is not given a width by its container's layout.
-     * Defaults to <tt>20</tt>.
+     * @cfg {Number} size
+     * An initial value for the 'size' attribute on the text input element. This is only used if the field has no
+     * configured {@link #width} and is not given a width by its container's layout. Defaults to 20.
      */
     size: 20,
 
     /**
-     * @cfg {Boolean} grow <tt>true</tt> if this field should automatically grow and shrink to its content
-     * (defaults to <tt>false</tt>)
+     * @cfg {Boolean} [grow=false]
+     * true if this field should automatically grow and shrink to its content
      */
 
     /**
-     * @cfg {Number} growMin The minimum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
-     * to <tt>30</tt>)
+     * @cfg {Number} growMin
+     * The minimum width to allow when `{@link #grow} = true`
      */
     growMin : 30,
-    
+
     /**
-     * @cfg {Number} growMax The maximum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
-     * to <tt>800</tt>)
+     * @cfg {Number} growMax
+     * The maximum width to allow when `{@link #grow} = true`
      */
     growMax : 800,
 
     /**
      * @cfg {String} growAppend
-     * A string that will be appended to the field's current value for the purposes of calculating the target
-     * field size. Only used when the {@link #grow} config is <tt>true</tt>. Defaults to a single capital "W"
-     * (the widest character in common fonts) to leave enough space for the next typed character and avoid the
-     * field value shifting before the width is adjusted.
+     * A string that will be appended to the field's current value for the purposes of calculating the target field
+     * size. Only used when the {@link #grow} config is true. Defaults to a single capital "W" (the widest character in
+     * common fonts) to leave enough space for the next typed character and avoid the field value shifting before the
+     * width is adjusted.
      */
     growAppend: 'W',
-    
+
     /**
-     * @cfg {String} vtype A validation type name as defined in {@link Ext.form.field.VTypes} (defaults to <tt>undefined</tt>)
+     * @cfg {String} vtype
+     * A validation type name as defined in {@link Ext.form.field.VTypes}
      */
 
     /**
-     * @cfg {RegExp} maskRe An input mask regular expression that will be used to filter keystrokes that do
-     * not match (defaults to <tt>undefined</tt>)
+     * @cfg {RegExp} maskRe An input mask regular expression that will be used to filter keystrokes (character being
+     * typed) that do not match.
+     * Note: It dose not filter characters already in the input.
      */
 
     /**
-     * @cfg {Boolean} disableKeyFilter Specify <tt>true</tt> to disable input keystroke filtering (defaults
-     * to <tt>false</tt>)
+     * @cfg {Boolean} [disableKeyFilter=false]
+     * Specify true to disable input keystroke filtering
      */
 
     /**
-     * @cfg {Boolean} allowBlank Specify <tt>false</tt> to validate that the value's length is > 0 (defaults to
-     * <tt>true</tt>)
+     * @cfg {Boolean} allowBlank
+     * Specify false to validate that the value's length is > 0
      */
     allowBlank : true,
-    
+
     /**
-     * @cfg {Number} minLength Minimum input field length required (defaults to <tt>0</tt>)
+     * @cfg {Number} minLength
+     * Minimum input field length required
      */
     minLength : 0,
-    
+
     /**
-     * @cfg {Number} maxLength Maximum input field length allowed by validation (defaults to Number.MAX_VALUE).
-     * This behavior is intended to provide instant feedback to the user by improving usability to allow pasting
-     * and editing or overtyping and back tracking. To restrict the maximum number of characters that can be
-     * entered into the field use the <tt><b>{@link Ext.form.field.Text#enforceMaxLength enforceMaxLength}</b></tt> option.
+     * @cfg {Number} maxLength
+     * Maximum input field length allowed by validation (defaults to Number.MAX_VALUE). This behavior is intended to
+     * provide instant feedback to the user by improving usability to allow pasting and editing or overtyping and back
+     * tracking. To restrict the maximum number of characters that can be entered into the field use the **{@link
+     * Ext.form.field.Text#enforceMaxLength enforceMaxLength}** option.
      */
     maxLength : Number.MAX_VALUE,
-    
+
     /**
-     * @cfg {Boolean} enforceMaxLength True to set the maxLength property on the underlying input field. Defaults to <tt>false</tt>
+     * @cfg {Boolean} enforceMaxLength
+     * True to set the maxLength property on the underlying input field. Defaults to false
      */
 
     /**
-     * @cfg {String} minLengthText Error text to display if the <b><tt>{@link #minLength minimum length}</tt></b>
-     * validation fails (defaults to <tt>'The minimum length for this field is {minLength}'</tt>)
+     * @cfg {String} minLengthText
+     * Error text to display if the **{@link #minLength minimum length}** validation fails.
      */
     minLengthText : 'The minimum length for this field is {0}',
-    
+
     /**
-     * @cfg {String} maxLengthText Error text to display if the <b><tt>{@link #maxLength maximum length}</tt></b>
-     * validation fails (defaults to <tt>'The maximum length for this field is {maxLength}'</tt>)
+     * @cfg {String} maxLengthText
+     * Error text to display if the **{@link #maxLength maximum length}** validation fails
      */
     maxLengthText : 'The maximum length for this field is {0}',
-    
+
     /**
-     * @cfg {Boolean} selectOnFocus <tt>true</tt> to automatically select any existing field text when the field
-     * receives input focus (defaults to <tt>false</tt>)
+     * @cfg {Boolean} [selectOnFocus=false]
+     * true to automatically select any existing field text when the field receives input focus
      */
-    
+
     /**
-     * @cfg {String} blankText The error text to display if the <b><tt>{@link #allowBlank}</tt></b> validation
-     * fails (defaults to <tt>'This field is required'</tt>)
+     * @cfg {String} blankText
+     * The error text to display if the **{@link #allowBlank}** validation fails
      */
     blankText : 'This field is required',
-    
+
     /**
      * @cfg {Function} validator
-     * <p>A custom validation function to be called during field validation ({@link #getErrors})
-     * (defaults to <tt>undefined</tt>). If specified, this function will be called first, allowing the
-     * developer to override the default validation process.</p>
-     * <br><p>This function will be passed the following Parameters:</p>
-     * <div class="mdetail-params"><ul>
-     * <li><code>value</code>: <i>Mixed</i>
-     * <div class="sub-desc">The current field value</div></li>
-     * </ul></div>
-     * <br><p>This function is to Return:</p>
-     * <div class="mdetail-params"><ul>
-     * <li><code>true</code>: <i>Boolean</i>
-     * <div class="sub-desc"><code>true</code> if the value is valid</div></li>
-     * <li><code>msg</code>: <i>String</i>
-     * <div class="sub-desc">An error message if the value is invalid</div></li>
-     * </ul></div>
+     * A custom validation function to be called during field validation ({@link #getErrors}).
+     * If specified, this function will be called first, allowing the developer to override the default validation
+     * process.
+     *
+     * This function will be passed the following parameters:
+     *
+     * @cfg {Object} validator.value The current field value
+     * @cfg {Boolean/String} validator.return
+     *
+     * - True if the value is valid
+     * - An error message if the value is invalid
      */
 
     /**
-     * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation
-     * (defaults to <tt>undefined</tt>). If the test fails, the field will be marked invalid using
-     * <b><tt>{@link #regexText}</tt></b>.
+     * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation.
+     * If the test fails, the field will be marked invalid using
+     * either <b><tt>{@link #regexText}</tt></b> or <b><tt>{@link #invalidText}</tt></b>.
      */
 
     /**
-     * @cfg {String} regexText The error text to display if <b><tt>{@link #regex}</tt></b> is used and the
-     * test fails during validation (defaults to <tt>''</tt>)
+     * @cfg {String} regexText
+     * The error text to display if **{@link #regex}** is used and the test fails during validation
      */
     regexText : '',
-    
+
     /**
      * @cfg {String} emptyText
-     * <p>The default text to place into an empty field (defaults to <tt>undefined</tt>).</p>
-     * <p>Note that normally this value will be submitted to the server if this field is enabled; to prevent this
-     * you can set the {@link Ext.form.action.Action#submitEmptyText submitEmptyText} option of
-     * {@link Ext.form.Basic#submit} to <tt>false</tt>.</p>
-     * <p>Also note that if you use <tt>{@link #inputType inputType}:'file'</tt>, {@link #emptyText} is not
-     * supported and should be avoided.</p>
+     * The default text to place into an empty field.
+     *
+     * Note that normally this value will be submitted to the server if this field is enabled; to prevent this you can
+     * set the {@link Ext.form.action.Action#submitEmptyText submitEmptyText} option of {@link Ext.form.Basic#submit} to
+     * false.
+     *
+     * Also note that if you use {@link #inputType inputType}:'file', {@link #emptyText} is not supported and should be
+     * avoided.
      */
 
     /**
-     * @cfg {String} emptyCls The CSS class to apply to an empty field to style the <b><tt>{@link #emptyText}</tt></b>
-     * (defaults to <tt>'x-form-empty-field'</tt>).  This class is automatically added and removed as needed
-     * depending on the current field value.
+     * @cfg {String} [emptyCls='x-form-empty-field']
+     * The CSS class to apply to an empty field to style the **{@link #emptyText}**.
+     * This class is automatically added and removed as needed depending on the current field value.
      */
     emptyCls : Ext.baseCSSPrefix + 'form-empty-field',
 
     ariaRole: 'textbox',
 
     /**
-     * @cfg {Boolean} enableKeyEvents <tt>true</tt> to enable the proxying of key events for the HTML input field (defaults to <tt>false</tt>)
+     * @cfg {Boolean} [enableKeyEvents=false]
+     * true to enable the proxying of key events for the HTML input field
      */
 
     componentLayout: 'textfield',
@@ -72734,10 +76110,9 @@ Ext.define('Ext.form.field.Text', {
         this.addEvents(
             /**
              * @event autosize
-             * Fires when the <tt><b>{@link #autoSize}</b></tt> function is triggered and the field is
-             * resized according to the {@link #grow}/{@link #growMin}/{@link #growMax} configs as a result.
-             * This event provides a hook for the developer to apply additional logic at runtime to resize the
-             * field if needed.
+             * Fires when the **{@link #autoSize}** function is triggered and the field is resized according to the
+             * {@link #grow}/{@link #growMin}/{@link #growMax} configs as a result. This event provides a hook for the
+             * developer to apply additional logic at runtime to resize the field if needed.
              * @param {Ext.form.field.Text} this This text field
              * @param {Number} width The new field width
              */
@@ -72745,24 +76120,21 @@ Ext.define('Ext.form.field.Text', {
 
             /**
              * @event keydown
-             * Keydown input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
-             * is set to true.
+             * Keydown input field event. This event only fires if **{@link #enableKeyEvents}** is set to true.
              * @param {Ext.form.field.Text} this This text field
              * @param {Ext.EventObject} e
              */
             'keydown',
             /**
              * @event keyup
-             * Keyup input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
-             * is set to true.
+             * Keyup input field event. This event only fires if **{@link #enableKeyEvents}** is set to true.
              * @param {Ext.form.field.Text} this This text field
              * @param {Ext.EventObject} e
              */
             'keyup',
             /**
              * @event keypress
-             * Keypress input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
-             * is set to true.
+             * Keypress input field event. This event only fires if **{@link #enableKeyEvents}** is set to true.
              * @param {Ext.form.field.Text} this This text field
              * @param {Ext.EventObject} e
              */
@@ -72774,7 +76146,7 @@ Ext.define('Ext.form.field.Text', {
     initEvents : function(){
         var me = this,
             el = me.inputEl;
-        
+
         me.callParent();
         if(me.selectOnFocus || me.emptyText){
             me.mon(el, 'mousedown', me.onMouseDown, me);
@@ -72794,10 +76166,11 @@ Ext.define('Ext.form.field.Text', {
     },
 
     /**
-     * @private override - treat undefined and null values as equal to an empty string value
+     * @private
+     * Override. Treat undefined and null values as equal to an empty string value.
      */
     isEqual: function(value1, value2) {
-        return String(Ext.value(value1, '')) === String(Ext.value(value2, ''));
+        return this.isEqualAsString(value1, value2);
     },
 
     /**
@@ -72808,7 +76181,7 @@ Ext.define('Ext.form.field.Text', {
         this.callParent();
         this.autoSize();
     },
-    
+
     afterRender: function(){
         var me = this;
         if (me.enforceMaxLength) {
@@ -72827,9 +76200,9 @@ Ext.define('Ext.form.field.Text', {
     },
 
     /**
-     * Performs any necessary manipulation of a raw String value to prepare it for {@link #stringToValue conversion}
-     * and/or {@link #validate validation}. For text fields this applies the configured {@link #stripCharsRe} to the
-     * raw value.
+     * Performs any necessary manipulation of a raw String value to prepare it for conversion and/or
+     * {@link #validate validation}. For text fields this applies the configured {@link #stripCharsRe}
+     * to the raw value.
      * @param {String} value The unprocessed string value
      * @return {String} The processed string value
      */
@@ -72837,7 +76210,7 @@ Ext.define('Ext.form.field.Text', {
         var me = this,
             stripRe = me.stripCharsRe,
             newValue;
-            
+
         if (stripRe) {
             newValue = value.replace(stripRe, '');
             if (newValue !== value) {
@@ -72878,8 +76251,7 @@ Ext.define('Ext.form.field.Text', {
 
     /**
      * Resets the current field value to the originally-loaded value and clears any validation messages.
-     * Also adds <tt><b>{@link #emptyText}</b></tt> and <tt><b>{@link #emptyCls}</b></tt> if the
-     * original value was blank.
+     * Also adds **{@link #emptyText}** and **{@link #emptyCls}** if the original value was blank.
      */
     reset : function(){
         this.callParent();
@@ -72893,13 +76265,13 @@ Ext.define('Ext.form.field.Text', {
 
         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);
             }
-            
+
             //all browsers need this because of a styling issue with chrome + placeholders.
             //the text isnt vertically aligned when empty (and using the placeholder)
             if (isEmpty) {
@@ -72944,16 +76316,21 @@ Ext.define('Ext.form.field.Text', {
 
     // private
     filterKeys : function(e){
-        if(e.ctrlKey){
+        /*
+         * On European keyboards, the right alt key, Alt Gr, is used to type certain special characters.
+         * JS detects a keypress of this as ctrlKey & altKey. As such, we check that alt isn't pressed
+         * so we can still process these special characters.
+         */
+        if (e.ctrlKey && !e.altKey) {
             return;
         }
         var key = e.getKey(),
             charCode = String.fromCharCode(e.getCharCode());
-            
+
         if(Ext.isGecko && (e.isNavKeyPress() || key === e.BACKSPACE || (key === e.DELETE && e.button === -1))){
             return;
         }
-        
+
         if(!Ext.isGecko && e.isSpecialKey() && !charCode){
             return;
         }
@@ -72963,10 +76340,10 @@ Ext.define('Ext.form.field.Text', {
     },
 
     /**
-     * Returns the raw String value of the field, without performing any normalization, conversion, or validation.
-     * Gets the current value of the input element if the field has been rendered, ignoring the value if it is the
+     * Returns the raw String value of the field, without performing any normalization, conversion, or validation. Gets
+     * the current value of the input element if the field has been rendered, ignoring the value if it is the
      * {@link #emptyText}. To get a normalized and converted value see {@link #getValue}.
-     * @return {String} value The raw String value of the field
+     * @return {String} The raw String value of the field
      */
     getRawValue: function() {
         var me = this,
@@ -72980,17 +76357,17 @@ Ext.define('Ext.form.field.Text', {
     /**
      * Sets a data value into the field and runs the change detection and validation. Also applies any configured
      * {@link #emptyText} for text fields. To set the value directly without these inspections see {@link #setRawValue}.
-     * @param {Mixed} value The value to set
+     * @param {Object} value The value to set
      * @return {Ext.form.field.Text} this
      */
     setValue: function(value) {
         var me = this,
             inputEl = me.inputEl;
-        
+
         if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
             inputEl.removeCls(me.emptyCls);
         }
-        
+
         me.callParent(arguments);
 
         me.applyEmptyText();
@@ -72998,59 +76375,58 @@ Ext.define('Ext.form.field.Text', {
     },
 
     /**
-Validates a value according to the field's validation rules and returns an array of errors
-for any failing validations. Validation rules are processed in the following order:
-
-1. **Field specific validator**
-    
-    A validator offers a way to customize and reuse a validation specification.
-    If a field is configured with a `{@link #validator}`
-    function, it will be passed the current field value.  The `{@link #validator}`
-    function is expected to return either:
-    
-    - Boolean `true`  if the value is valid (validation continues).
-    - a String to represent the invalid message if invalid (validation halts).
-
-2. **Basic Validation**
-
-    If the `{@link #validator}` has not halted validation,
-    basic validation proceeds as follows:
-    
-    - `{@link #allowBlank}` : (Invalid message = `{@link #emptyText}`)
-    
-        Depending on the configuration of <code>{@link #allowBlank}</code>, a
-        blank field will cause validation to halt at this step and return
-        Boolean true or false accordingly.
-    
-    - `{@link #minLength}` : (Invalid message = `{@link #minLengthText}`)
-
-        If the passed value does not satisfy the `{@link #minLength}`
-        specified, validation halts.
-
-    -  `{@link #maxLength}` : (Invalid message = `{@link #maxLengthText}`)
-
-        If the passed value does not satisfy the `{@link #maxLength}`
-        specified, validation halts.
-
-3. **Preconfigured Validation Types (VTypes)**
-
-    If none of the prior validation steps halts validation, a field
-    configured with a `{@link #vtype}` will utilize the
-    corresponding {@link Ext.form.field.VTypes VTypes} validation function.
-    If invalid, either the field's `{@link #vtypeText}` or
-    the VTypes vtype Text property will be used for the invalid message.
-    Keystrokes on the field will be filtered according to the VTypes
-    vtype Mask property.
-
-4. **Field specific regex test**
-
-    If none of the prior validation steps halts validation, a field's
-    configured <code>{@link #regex}</code> test will be processed.
-    The invalid message for this test is configured with `{@link #regexText}`
-
-     * @param {Mixed} value The value to validate. The processed raw value will be used if nothing is passed
-     * @return {Array} Array of any validation errors
-     * @markdown
+     * Validates a value according to the field's validation rules and returns an array of errors
+     * for any failing validations. Validation rules are processed in the following order:
+     *
+     * 1. **Field specific validator**
+     *
+     *     A validator offers a way to customize and reuse a validation specification.
+     *     If a field is configured with a `{@link #validator}`
+     *     function, it will be passed the current field value.  The `{@link #validator}`
+     *     function is expected to return either:
+     *
+     *     - Boolean `true`  if the value is valid (validation continues).
+     *     - a String to represent the invalid message if invalid (validation halts).
+     *
+     * 2. **Basic Validation**
+     *
+     *     If the `{@link #validator}` has not halted validation,
+     *     basic validation proceeds as follows:
+     *
+     *     - `{@link #allowBlank}` : (Invalid message = `{@link #emptyText}`)
+     *
+     *         Depending on the configuration of `{@link #allowBlank}`, a
+     *         blank field will cause validation to halt at this step and return
+     *         Boolean true or false accordingly.
+     *
+     *     - `{@link #minLength}` : (Invalid message = `{@link #minLengthText}`)
+     *
+     *         If the passed value does not satisfy the `{@link #minLength}`
+     *         specified, validation halts.
+     *
+     *     -  `{@link #maxLength}` : (Invalid message = `{@link #maxLengthText}`)
+     *
+     *         If the passed value does not satisfy the `{@link #maxLength}`
+     *         specified, validation halts.
+     *
+     * 3. **Preconfigured Validation Types (VTypes)**
+     *
+     *     If none of the prior validation steps halts validation, a field
+     *     configured with a `{@link #vtype}` will utilize the
+     *     corresponding {@link Ext.form.field.VTypes VTypes} validation function.
+     *     If invalid, either the field's `{@link #vtypeText}` or
+     *     the VTypes vtype Text property will be used for the invalid message.
+     *     Keystrokes on the field will be filtered according to the VTypes
+     *     vtype Mask property.
+     *
+     * 4. **Field specific regex test**
+     *
+     *     If none of the prior validation steps halts validation, a field's
+     *     configured <code>{@link #regex}</code> test will be processed.
+     *     The invalid message for this test is configured with `{@link #regexText}`
+     *
+     * @param {Object} value The value to validate. The processed raw value will be used if nothing is passed.
+     * @return {String[]} Array of any validation errors
      */
     getErrors: function(value) {
         var me = this,
@@ -73104,8 +76480,8 @@ for any failing validations. Validation rules are processed in the following ord
 
     /**
      * Selects text in this field
-     * @param {Number} start (optional) The index where the selection should start (defaults to 0)
-     * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
+     * @param {Number} [start=0] The index where the selection should start
+     * @param {Number} [end] The index where the selection should end (defaults to the text length)
      */
     selectText : function(start, end){
         var me = this,
@@ -73114,7 +76490,7 @@ for any failing validations. Validation rules are processed in the following ord
             el = me.inputEl.dom,
             undef,
             range;
-            
+
         if (v.length > 0) {
             start = start === undef ? 0 : start;
             end = end === undef ? v.length : end;
@@ -73135,9 +76511,8 @@ for any failing validations. Validation rules are processed in the following ord
     },
 
     /**
-     * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
-     * This only takes effect if <tt>{@link #grow} = true</tt>, and fires the {@link #autosize} event if the
-     * width changes.
+     * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed. This
+     * only takes effect if {@link #grow} = true, and fires the {@link #autosize} event if the width changes.
      */
     autoSize: function() {
         var me = this,
@@ -73158,10 +76533,10 @@ for any failing validations. Validation rules are processed in the following ord
     },
 
     /**
-     * @protected override
-     * To get the natural width of the inputEl, we do a simple calculation based on the
-     * 'size' config. We use hard-coded numbers to approximate what browsers do natively,
-     * to avoid having to read any styles which would hurt performance.
+     * To get the natural width of the inputEl, we do a simple calculation based on the 'size' config. We use
+     * hard-coded numbers to approximate what browsers do natively, to avoid having to read any styles which would hurt
+     * performance. Overrides Labelable method.
+     * @protected
      */
     getBodyNaturalWidth: function() {
         return Math.round(this.size * 6.5) + 20;
@@ -73170,35 +76545,33 @@ for any failing validations. Validation rules are processed in the following ord
 });
 
 /**
- * @class Ext.form.field.TextArea
- * @extends Ext.form.field.Text
-
-This class creates a multiline text field, which can be used as a direct replacement for traditional 
-textarea fields. In addition, it supports automatically {@link #grow growing} the height of the textarea to 
-fit its content.
-
-All of the configuration options from {@link Ext.form.field.Text} can be used on TextArea.
-{@img Ext.form.TextArea/Ext.form.TextArea.png Ext.form.TextArea component}
-Example usage:
-
-    Ext.create('Ext.form.FormPanel', {
-        title      : 'Sample TextArea',
-        width      : 400,
-        bodyPadding: 10,
-        renderTo   : Ext.getBody(),
-        items: [{
-            xtype     : 'textareafield',
-            grow      : true,
-            name      : 'message',
-            fieldLabel: 'Message',
-            anchor    : '100%'
-        }]
-    }); 
-
-Some other useful configuration options when using {@link #grow} are {@link #growMin} and {@link #growMax}. These 
-allow you to set the minimum and maximum grow heights for the textarea.
-
  * @docauthor Robert Dougan <rob@sencha.com>
+ *
+ * This class creates a multiline text field, which can be used as a direct replacement for traditional
+ * textarea fields. In addition, it supports automatically {@link #grow growing} the height of the textarea to
+ * fit its content.
+ *
+ * All of the configuration options from {@link Ext.form.field.Text} can be used on TextArea.
+ *
+ * Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.form.FormPanel', {
+ *         title      : 'Sample TextArea',
+ *         width      : 400,
+ *         bodyPadding: 10,
+ *         renderTo   : Ext.getBody(),
+ *         items: [{
+ *             xtype     : 'textareafield',
+ *             grow      : true,
+ *             name      : 'message',
+ *             fieldLabel: 'Message',
+ *             anchor    : '100%'
+ *         }]
+ *     });
+ *
+ * Some other useful configuration options when using {@link #grow} are {@link #growMin} and {@link #growMax}.
+ * These allow you to set the minimum and maximum grow heights for the textarea.
  */
 Ext.define('Ext.form.field.TextArea', {
     extend:'Ext.form.field.Text',
@@ -73222,52 +76595,51 @@ Ext.define('Ext.form.field.TextArea', {
     ],
 
     /**
-     * @cfg {Number} growMin The minimum height to allow when <tt>{@link Ext.form.field.Text#grow grow}=true</tt>
-     * (defaults to <tt>60</tt>)
+     * @cfg {Number} growMin
+     * The minimum height to allow when {@link #grow}=true
      */
     growMin: 60,
 
     /**
-     * @cfg {Number} growMax The maximum height to allow when <tt>{@link Ext.form.field.Text#grow grow}=true</tt>
-     * (defaults to <tt>1000</tt>)
+     * @cfg {Number} growMax
+     * The maximum height to allow when {@link #grow}=true
      */
     growMax: 1000,
 
     /**
      * @cfg {String} growAppend
-     * A string that will be appended to the field's current value for the purposes of calculating the target
-     * field size. Only used when the {@link #grow} config is <tt>true</tt>. Defaults to a newline for TextArea
-     * to ensure there is always a space below the current line.
+     * A string that will be appended to the field's current value for the purposes of calculating the target field
+     * size. Only used when the {@link #grow} config is true. Defaults to a newline for TextArea to ensure there is
+     * always a space below the current line.
      */
     growAppend: '\n-',
 
     /**
-     * @cfg {Number} cols An initial value for the 'cols' attribute on the textarea element. This is only
-     * used if the component has no configured {@link #width} and is not given a width by its container's
-     * layout. Defaults to <tt>20</tt>.
+     * @cfg {Number} cols
+     * An initial value for the 'cols' attribute on the textarea element. This is only used if the component has no
+     * configured {@link #width} and is not given a width by its container's layout.
      */
     cols: 20,
 
     /**
-     * @cfg {Number} cols An initial value for the 'cols' attribute on the textarea element. This is only
-     * used if the component has no configured {@link #width} and is not given a width by its container's
-     * layout. Defaults to <tt>4</tt>.
+     * @cfg {Number} cols
+     * An initial value for the 'cols' attribute on the textarea element. This is only used if the component has no
+     * configured {@link #width} and is not given a width by its container's layout.
      */
     rows: 4,
 
     /**
      * @cfg {Boolean} enterIsSpecial
-     * True if you want the enter key to be classed as a <tt>special</tt> key. Special keys are generally navigation
-     * keys (arrows, space, enter). Setting the config property to <tt>true</tt> would mean that you could not insert
-     * returns into the textarea.
-     * (defaults to <tt>false</tt>)
+     * True if you want the enter key to be classed as a special key. Special keys are generally navigation keys
+     * (arrows, space, enter). Setting the config property to true would mean that you could not insert returns into the
+     * textarea.
      */
     enterIsSpecial: false,
 
     /**
-     * @cfg {Boolean} preventScrollbars <tt>true</tt> to prevent scrollbars from appearing regardless of how much text is
-     * in the field. This option is only relevant when {@link #grow} is <tt>true</tt>. Equivalent to setting overflow: hidden, defaults to
-     * <tt>false</tt>.
+     * @cfg {Boolean} preventScrollbars
+     * true to prevent scrollbars from appearing regardless of how much text is in the field. This option is only
+     * relevant when {@link #grow} is true. Equivalent to setting overflow: hidden.
      */
     preventScrollbars: false,
 
@@ -73307,9 +76679,8 @@ Ext.define('Ext.form.field.TextArea', {
     },
 
     /**
-     * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
-     * This only takes effect if <tt>{@link #grow} = true</tt>, and fires the {@link #autosize} event if
-     * the height changes.
+     * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed. This
+     * only takes effect if {@link #grow} = true, and fires the {@link #autosize} event if the height changes.
      */
     autoSize: function() {
         var me = this,
@@ -73332,10 +76703,10 @@ Ext.define('Ext.form.field.TextArea', {
     },
 
     /**
-     * @protected override
-     * To get the natural width of the textarea element, we do a simple calculation based on the
-     * 'cols' config. We use hard-coded numbers to approximate what browsers do natively,
-     * to avoid having to read any styles which would hurt performance.
+     * To get the natural width of the textarea element, we do a simple calculation based on the 'cols' config.
+     * We use hard-coded numbers to approximate what browsers do natively, to avoid having to read any styles which
+     * would hurt performance. Overrides Labelable method.
+     * @protected
      */
     getBodyNaturalWidth: function() {
         return Math.round(this.cols * 6.5) + 20;
@@ -73345,42 +76716,37 @@ Ext.define('Ext.form.field.TextArea', {
 
 
 /**
- * @class Ext.window.MessageBox
- * @extends Ext.window.Window
-
-Utility class for generating different styles of message boxes.  The singleton instance, `Ext.Msg` can also be used.
-Note that a MessageBox is asynchronous.  Unlike a regular JavaScript `alert` (which will halt
-browser execution), showing a MessageBox will not cause the code to stop.  For this reason, if you have code
-that should only run *after* some user feedback from the MessageBox, you must use a callback function
-(see the `function` parameter for {@link #show} for more details).
-
-{@img Ext.window.MessageBox/messagebox1.png alert MessageBox}
-{@img Ext.window.MessageBox/messagebox2.png prompt MessageBox}
-{@img Ext.window.MessageBox/messagebox3.png show MessageBox}
-#Example usage:#
-
-    // Basic alert:
-    Ext.Msg.alert('Status', 'Changes saved successfully.');
-
-    // Prompt for user data and process the result using a callback:
-    Ext.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
-        if (btn == 'ok'){
-            // process text value and close...
-        }
-    });
-
-    // Show a dialog using config options:
-    Ext.Msg.show({
-         title:'Save Changes?',
-         msg: 'You are closing a tab that has unsaved changes. Would you like to save your changes?',
-         buttons: Ext.Msg.YESNOCANCEL,
-         fn: processResult,
-         animateTarget: 'elId',
-         icon: Ext.window.MessageBox.QUESTION
-    });
-
- * @markdown
- * @singleton
+ * Utility class for generating different styles of message boxes.  The singleton instance, Ext.MessageBox
+ * alias `Ext.Msg` can also be used.
+ *
+ * Note that a MessageBox is asynchronous.  Unlike a regular JavaScript `alert` (which will halt
+ * browser execution), showing a MessageBox will not cause the code to stop.  For this reason, if you have code
+ * that should only run *after* some user feedback from the MessageBox, you must use a callback function
+ * (see the `function` parameter for {@link #show} for more details).
+ *
+ * Basic alert
+ *
+ *     @example
+ *     Ext.Msg.alert('Status', 'Changes saved successfully.');
+ *
+ * Prompt for user data and process the result using a callback
+ *
+ *     @example
+ *     Ext.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
+ *         if (btn == 'ok'){
+ *             // process text value and close...
+ *         }
+ *     });
+ *
+ * Show a dialog using config options
+ *
+ *     @example
+ *     Ext.Msg.show({
+ *          title:'Save Changes?',
+ *          msg: 'You are closing a tab that has unsaved changes. Would you like to save your changes?',
+ *          buttons: Ext.Msg.YESNOCANCEL,
+ *          icon: Ext.Msg.QUESTION
+ *     });
  */
 Ext.define('Ext.window.MessageBox', {
     extend: 'Ext.window.Window',
@@ -73395,8 +76761,6 @@ Ext.define('Ext.window.MessageBox', {
         'Ext.ProgressBar'
     ],
 
-    alternateClassName: 'Ext.MessageBox',
-
     alias: 'widget.messagebox',
 
     /**
@@ -73476,19 +76840,19 @@ Ext.define('Ext.window.MessageBox', {
     },
 
     /**
-     * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
+     * The default height in pixels of the message box's multiline textarea if displayed.
      * @type Number
      */
     defaultTextHeight : 75,
     /**
      * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
-     * for setting a different minimum width than text-only dialogs may need (defaults to 250).
+     * for setting a different minimum width than text-only dialogs may need.
      * @type Number
      */
     minProgressWidth : 250,
     /**
      * The minimum width in pixels of the message box if it is a prompt dialog.  This is useful
-     * for setting a different minimum width than text-only dialogs may need (defaults to 250).
+     * for setting a different minimum width than text-only dialogs may need.
      * @type Number
      */
     minPromptWidth: 250,
@@ -73687,18 +77051,13 @@ Ext.define('Ext.window.MessageBox', {
             me.width = initialWidth;
             me.render(Ext.getBody());
         } else {
-            me.hidden = false;
             me.setSize(initialWidth, me.maxHeight);
         }
         me.setPosition(-10000, -10000);
 
         // Hide or show the close tool
         me.closable = cfg.closable && !cfg.wait;
-        if (cfg.closable === false) {
-            me.tools.close.hide();
-        } else {
-            me.tools.close.show();
-        }
+        me.header.child('[type=close]').setVisible(cfg.closable !== false);
 
         // Hide or show the header
         if (!cfg.title && !me.closable) {
@@ -73776,7 +77135,6 @@ Ext.define('Ext.window.MessageBox', {
         } else {
             me.bottomTb.show();
         }
-        me.hidden = true;
     },
 
     /**
@@ -73834,7 +77192,7 @@ Ext.define('Ext.window.MessageBox', {
      * <li><b>title</b> : String<div class="sub-desc">The title text</div></li>
      * <li><b>value</b> : String<div class="sub-desc">The string value to set into the active textbox element if displayed</div></li>
      * <li><b>wait</b> : Boolean<div class="sub-desc">True to display a progress bar (defaults to false)</div></li>
-     * <li><b>waitConfig</b> : Object<div class="sub-desc">A {@link Ext.ProgressBar#waitConfig} object (applies only if wait = true)</div></li>
+     * <li><b>waitConfig</b> : Object<div class="sub-desc">A {@link Ext.ProgressBar#wait} config object (applies only if wait = true)</div></li>
      * <li><b>width</b> : Number<div class="sub-desc">The width of the dialog in pixels</div></li>
      * </ul>
      * Example usage:
@@ -73843,7 +77201,7 @@ Ext.Msg.show({
 title: 'Address',
 msg: 'Please enter your address:',
 width: 300,
-buttons: Ext.window.MessageBox.OKCANCEL,
+buttons: Ext.Msg.OKCANCEL,
 multiline: true,
 fn: saveAddress,
 animateTarget: 'addAddressBtn',
@@ -73858,7 +77216,7 @@ icon: Ext.window.MessageBox.INFO
         me.reconfigure(cfg);
         me.addCls(cfg.cls);
         if (cfg.animateTarget) {
-            me.doAutoSize(false);
+            me.doAutoSize(true);
             me.callParent();
         } else {
             me.callParent();
@@ -73951,9 +77309,9 @@ Ext.window.MessageBox.ERROR
      * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
      * initiated via {@link Ext.window.MessageBox#progress} or {@link Ext.window.MessageBox#wait},
      * or by calling {@link Ext.window.MessageBox#show} with progress: true.
-     * @param {Number} value Any number between 0 and 1 (e.g., .5, defaults to 0)
-     * @param {String} progressText The progress text to display inside the progress bar (defaults to '')
-     * @param {String} msg The message box's body text is replaced with the specified string (defaults to undefined
+     * @param {Number} [value=0] Any number between 0 and 1 (e.g., .5)
+     * @param {String} [progressText=''] The progress text to display inside the progress bar.
+     * @param {String} [msg] The message box's body text is replaced with the specified string (defaults to undefined
      * so that any existing body text will not get overwritten by default unless a new value is passed in)
      * @return {Ext.window.MessageBox} this
      */
@@ -74003,11 +77361,11 @@ Ext.window.MessageBox.ERROR
      * close button) and the text that was entered will be passed as the two parameters to the callback.
      * @param {String} title The title bar text
      * @param {String} msg The message box body text
-     * @param {Function} fn (optional) The callback function invoked after the message box is closed
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
-     * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
-     * property, or the height in pixels to create the textbox (defaults to false / single-line)
-     * @param {String} value (optional) Default value of the text input element (defaults to '')
+     * @param {Function} [fn] The callback function invoked after the message box is closed
+     * @param {Object} [scope] The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser wnidow.
+     * @param {Boolean/Number} [multiline=false] True to create a multiline textbox using the defaultTextHeight
+     * property, or the height in pixels to create the textbox/
+     * @param {String} [value=''] Default value of the text input element
      * @return {Ext.window.MessageBox} this
      */
     prompt : function(cfg, msg, fn, scope, multiline, value){
@@ -74033,7 +77391,7 @@ Ext.window.MessageBox.ERROR
      * You are responsible for closing the message box when the process is complete.
      * @param {String} msg The message box body text
      * @param {String} title (optional) The title bar text
-     * @param {Object} config (optional) A {@link Ext.ProgressBar#waitConfig} object
+     * @param {Object} config (optional) A {@link Ext.ProgressBar#wait} config object
      * @return {Ext.window.MessageBox} this
      */
     wait : function(cfg, title, config){
@@ -74082,7 +77440,7 @@ Ext.window.MessageBox.ERROR
      * and closing the message box when the process is complete.
      * @param {String} title The title bar text
      * @param {String} msg The message box body text
-     * @param {String} progressText (optional) The text to display inside the progress bar (defaults to '')
+     * @param {String} [progressText=''] The text to display inside the progress bar
      * @return {Ext.window.MessageBox} this
      */
     progress : function(cfg, msg, progressText){
@@ -74090,56 +77448,66 @@ Ext.window.MessageBox.ERROR
             cfg = {
                 title: cfg,
                 msg: msg,
+                progress: true,
                 progressText: progressText
             };
         }
         return this.show(cfg);
     }
 }, function() {
+    /**
+     * @class Ext.MessageBox
+     * @alternateClassName Ext.Msg
+     * @extends Ext.window.MessageBox
+     * @singleton
+     * Singleton instance of {@link Ext.window.MessageBox}.
+     */
     Ext.MessageBox = Ext.Msg = new this();
 });
 /**
  * @class Ext.form.Basic
  * @extends Ext.util.Observable
- * 
+ *
  * Provides input field management, validation, submission, and form loading services for the collection
  * of {@link Ext.form.field.Field Field} instances within a {@link Ext.container.Container}. It is recommended
  * that you use a {@link Ext.form.Panel} as the form container, as that has logic to automatically
  * hook up an instance of {@link Ext.form.Basic} (plus other conveniences related to field configuration.)
- * 
+ *
  * ## Form Actions
- * 
+ *
  * The Basic class delegates the handling of form loads and submits to instances of {@link Ext.form.action.Action}.
  * See the various Action implementations for specific details of each one's functionality, as well as the
  * documentation for {@link #doAction} which details the configuration options that can be specified in
  * each action call.
- * 
+ *
  * The default submit Action is {@link Ext.form.action.Submit}, which uses an Ajax request to submit the
  * form's values to a configured URL. To enable normal browser submission of an Ext form, use the
  * {@link #standardSubmit} config option.
- * 
- * Note: File uploads are not performed using normal 'Ajax' techniques; see the description for
- * {@link #hasUpload} for details.
- * 
+ *
+ * ## File uploads
+ *
+ * File uploads are not performed using normal 'Ajax' techniques; see the description for
+ * {@link #hasUpload} for details. If you're using file uploads you should read the method description.
+ *
  * ## Example usage:
- * 
+ *
  *     Ext.create('Ext.form.Panel', {
  *         title: 'Basic Form',
  *         renderTo: Ext.getBody(),
  *         bodyPadding: 5,
  *         width: 350,
- * 
+ *
  *         // Any configuration items here will be automatically passed along to
  *         // the Ext.form.Basic instance when it gets created.
- * 
+ *
  *         // The form will submit an AJAX request to this URL when submitted
  *         url: 'save-form.php',
- * 
+ *
  *         items: [{
  *             fieldLabel: 'Field',
  *             name: 'theField'
  *         }],
- * 
+ *
  *         buttons: [{
  *             text: 'Submit',
  *             handler: function() {
@@ -74159,7 +77527,7 @@ Ext.window.MessageBox.ERROR
  *             }
  *         }]
  *     });
- * 
+ *
  * @docauthor Jason Johnston <jason@sencha.com>
  */
 Ext.define('Ext.form.Basic', {
@@ -74254,12 +77622,14 @@ Ext.define('Ext.form.Basic', {
      * @cfg {String} method
      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
      */
+
     /**
      * @cfg {Ext.data.reader.Reader} reader
      * An Ext.data.DataReader (e.g. {@link Ext.data.reader.Xml}) to be used to read
      * data when executing 'load' actions. This is optional as there is built-in
      * support for processing JSON responses.
      */
+
     /**
      * @cfg {Ext.data.reader.Reader} errorReader
      * <p>An Ext.data.DataReader (e.g. {@link Ext.data.reader.Xml}) to be used to
@@ -74287,7 +77657,7 @@ Ext.define('Ext.form.Basic', {
     /**
      * @cfg {Object} baseParams
      * <p>Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.</p>
-     * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode Ext.Object.toQueryString}.</p>
+     * <p>Parameters are encoded as standard HTTP parameters using {@link Ext.Object#toQueryString}.</p>
      */
 
     /**
@@ -74313,7 +77683,7 @@ api: {
      */
 
     /**
-     * @cfg {Array/String} paramOrder <p>A list of params to be executed server side.
+     * @cfg {String/String[]} paramOrder <p>A list of params to be executed server side.
      * Defaults to <tt>undefined</tt>. Only used for the <code>{@link #api}</code>
      * <code>load</code> configuration.</p>
      * <p>Specify the params in the order in which they must be executed on the
@@ -74328,38 +77698,38 @@ paramOrder: 'param1|param2|param'
      */
 
     /**
-     * @cfg {Boolean} paramsAsHash Only used for the <code>{@link #api}</code>
+     * @cfg {Boolean} paramsAsHash
+     * Only used for the <code>{@link #api}</code>
      * <code>load</code> configuration. If <tt>true</tt>, parameters will be sent as a
-     * single hash collection of named arguments (defaults to <tt>false</tt>). Providing a
+     * single hash collection of named arguments. Providing a
      * <tt>{@link #paramOrder}</tt> nullifies this configuration.
      */
     paramsAsHash: false,
 
     /**
      * @cfg {String} waitTitle
-     * The default title to show for the waiting message box (defaults to <tt>'Please Wait...'</tt>)
+     * The default title to show for the waiting message box
      */
     waitTitle: 'Please Wait...',
 
     /**
-     * @cfg {Boolean} trackResetOnLoad If set to <tt>true</tt>, {@link #reset}() resets to the last loaded
-     * or {@link #setValues}() data instead of when the form was first created.  Defaults to <tt>false</tt>.
+     * @cfg {Boolean} trackResetOnLoad
+     * If set to true, {@link #reset}() resets to the last loaded or {@link #setValues}() data instead of
+     * when the form was first created.
      */
     trackResetOnLoad: false,
 
     /**
      * @cfg {Boolean} standardSubmit
-     * <p>If set to <tt>true</tt>, a standard HTML form submit is used instead
-     * of a XHR (Ajax) style form submission. Defaults to <tt>false</tt>. All of
-     * the field values, plus any additional params configured via {@link #baseParams}
-     * and/or the <code>options</code> to {@link #submit}, will be included in the
-     * values submitted in the form.</p>
+     * If set to true, a standard HTML form submit is used instead of a XHR (Ajax) style form submission.
+     * All of the field values, plus any additional params configured via {@link #baseParams}
+     * and/or the `options` to {@link #submit}, will be included in the values submitted in the form.
      */
 
     /**
-     * @cfg {Mixed} waitMsgTarget
+     * @cfg {String/HTMLElement/Ext.Element} waitMsgTarget
      * By default wait messages are displayed with Ext.MessageBox.wait. You can target a specific
-     * element by passing it or its id or mask the form itself by passing in true. Defaults to <tt>undefined</tt>.
+     * element by passing it or its id or mask the form itself by passing in true.
      */
 
 
@@ -74400,10 +77770,15 @@ paramOrder: 'param1|param2|param'
 
         if (child.isFormField) {
             handleField(child);
-        }
-        else if (isContainer) {
+        } else if (isContainer) {
             // Walk down
-            Ext.Array.forEach(child.query('[isFormField]'), handleField);
+            if (child.isDestroyed) {
+                // the container is destroyed, this means we may have child fields, so here
+                // we just invalidate all the fields to be sure.
+                delete me._fields;
+            } else {
+                Ext.Array.forEach(child.query('[isFormField]'), handleField);
+            }
         }
 
         // Flush the cached list of formBind components
@@ -74429,12 +77804,19 @@ paramOrder: 'param1|param2|param'
         return fields;
     },
 
+    /**
+     * @private
+     * Finds and returns the set of all items bound to fields inside this form
+     * @return {Ext.util.MixedCollection} The set of all bound form field items
+     */
     getBoundItems: function() {
         var boundItems = this._boundItems;
-        if (!boundItems) {
+        
+        if (!boundItems || boundItems.getCount() === 0) {
             boundItems = this._boundItems = Ext.create('Ext.util.MixedCollection');
             boundItems.addAll(this.owner.query('[formBind]'));
         }
+        
         return boundItems;
     },
 
@@ -74627,7 +78009,7 @@ paramOrder: 'param1|param2|param'
 
     /**
      * Shortcut to {@link #doAction do} a {@link Ext.form.action.Submit submit action}. This will use the
-     * {@link Ext.form.action.Submit AJAX submit action} by default. If the {@link #standardsubmit} config is
+     * {@link Ext.form.action.Submit AJAX submit action} by default. If the {@link #standardSubmit} config is
      * enabled it will use a standard form element to submit, or if the {@link #api} config is present it will
      * use the {@link Ext.form.action.DirectLoad Ext.direct.Direct submit action}.
      * @param {Object} options The options to pass to the action (see {@link #doAction} for details).<br>
@@ -74684,7 +78066,7 @@ myFormPanel.getForm().submit({
 
     /**
      * Persists the values in this form into the passed {@link Ext.data.Model} object in a beginEdit/endEdit block.
-     * @param {Ext.data.Record} record The record to edit
+     * @param {Ext.data.Model} record The record to edit
      * @return {Ext.form.Basic} this
      */
     updateRecord: function(record) {
@@ -74709,7 +78091,7 @@ myFormPanel.getForm().submit({
 
     /**
      * Loads an {@link Ext.data.Model} into this form by calling {@link #setValues} with the
-     * {@link Ext.data.Model#data record data}.
+     * {@link Ext.data.Model#raw record data}.
      * See also {@link #trackResetOnLoad}.
      * @param {Ext.data.Model} record The record to load
      * @return {Ext.form.Basic} this
@@ -74718,7 +78100,7 @@ myFormPanel.getForm().submit({
         this._record = record;
         return this.setValues(record.data);
     },
-    
+
     /**
      * Returns the last Ext.data.Model instance that was loaded via {@link #loadRecord}
      * @return {Ext.data.Model} The record
@@ -74804,7 +78186,8 @@ myFormPanel.getForm().submit({
 
     /**
      * Mark fields in this form invalid in bulk.
-     * @param {Array/Object} errors Either an array in the form <code>[{id:'fieldId', msg:'The message'}, ...]</code>,
+     * @param {Object/Object[]/Ext.data.Errors} errors
+     * Either an array in the form <code>[{id:'fieldId', msg:'The message'}, ...]</code>,
      * an object hash of <code>{id: msg, id2: msg2}</code>, or a {@link Ext.data.Errors} object.
      * @return {Ext.form.Basic} this
      */
@@ -74836,7 +78219,7 @@ myFormPanel.getForm().submit({
 
     /**
      * Set values for fields in this form in bulk.
-     * @param {Array/Object} values Either an array in the form:<pre><code>
+     * @param {Object/Object[]} values Either an array in the form:<pre><code>
 [{id:'clientName', value:'Fred. Olsen Lines'},
  {id:'portOfLoading', value:'FXT'},
  {id:'portOfDischarge', value:'OSL'} ]</code></pre>
@@ -75094,7 +78477,7 @@ Ext.define('Ext.form.FieldAncestor', {
 
         me.addEvents(
             /**
-             * @event fielderrorchange
+             * @event fieldvaliditychange
              * Fires when the validity state of any one of the {@link Ext.form.field.Field} instances within this
              * container changes.
              * @param {Ext.form.FieldAncestor} this
@@ -75370,102 +78753,98 @@ Ext.define('Ext.layout.container.CheckboxGroup', {
 });
 
 /**
- * @class Ext.form.FieldContainer
- * @extends Ext.container.Container
-
-FieldContainer is a derivation of {@link Ext.container.Container Container} that implements the
-{@link Ext.form.Labelable Labelable} mixin. This allows it to be configured so that it is rendered with
-a {@link #fieldLabel field label} and optional {@link #msgTarget error message} around its sub-items.
-This is useful for arranging a group of fields or other components within a single item in a form, so
-that it lines up nicely with other fields. A common use is for grouping a set of related fields under
-a single label in a form.
-
-The container's configured {@link #items} will be layed out within the field body area according to the
-configured {@link #layout} type. The default layout is `'autocontainer'`.
-
-Like regular fields, FieldContainer can inherit its decoration configuration from the
-{@link Ext.form.Panel#fieldDefaults fieldDefaults} of an enclosing FormPanel. In addition,
-FieldContainer itself can pass {@link #fieldDefaults} to any {@link Ext.form.Labelable fields}
-it may itself contain.
-
-If you are grouping a set of {@link Ext.form.field.Checkbox Checkbox} or {@link Ext.form.field.Radio Radio}
-fields in a single labeled container, consider using a {@link Ext.form.CheckboxGroup}
-or {@link Ext.form.RadioGroup} instead as they are specialized for handling those types.
-{@img Ext.form.FieldContainer/Ext.form.FieldContainer1.png Ext.form.FieldContainer component}
-__Example usage:__
-
-    Ext.create('Ext.form.Panel', {
-        title: 'FieldContainer Example',
-        width: 550,
-        bodyPadding: 10,
-    
-        items: [{
-            xtype: 'fieldcontainer',
-            fieldLabel: 'Last Three Jobs',
-            labelWidth: 100,
-    
-            // The body area will contain three text fields, arranged
-            // horizontally, separated by draggable splitters.
-            layout: 'hbox',
-            items: [{
-                xtype: 'textfield',
-                flex: 1
-            }, {
-                xtype: 'splitter'
-            }, {
-                xtype: 'textfield',
-                flex: 1
-            }, {
-                xtype: 'splitter'
-            }, {
-                xtype: 'textfield',
-                flex: 1
-            }]
-        }],
-        renderTo: Ext.getBody()
-    });
-
-__Usage of {@link #fieldDefaults}:__
-{@img Ext.form.FieldContainer/Ext.form.FieldContainer2.png Ext.form.FieldContainer component}
-
-    Ext.create('Ext.form.Panel', {
-        title: 'FieldContainer Example',
-        width: 350,
-        bodyPadding: 10,
-    
-        items: [{
-            xtype: 'fieldcontainer',
-            fieldLabel: 'Your Name',
-            labelWidth: 75,
-            defaultType: 'textfield',
-    
-            // Arrange fields vertically, stretched to full width
-            layout: 'anchor',
-            defaults: {
-                layout: '100%'
-            },
-    
-            // These config values will be applied to both sub-fields, except
-            // for Last Name which will use its own msgTarget.
-            fieldDefaults: {
-                msgTarget: 'under',
-                labelAlign: 'top'
-            },
-    
-            items: [{
-                fieldLabel: 'First Name',
-                name: 'firstName'
-            }, {
-                fieldLabel: 'Last Name',
-                name: 'lastName',
-                msgTarget: 'under'
-            }]
-        }],
-        renderTo: Ext.getBody()
-    });
-
-
- * @markdown
+ * FieldContainer is a derivation of {@link Ext.container.Container Container} that implements the
+ * {@link Ext.form.Labelable Labelable} mixin. This allows it to be configured so that it is rendered with
+ * a {@link #fieldLabel field label} and optional {@link #msgTarget error message} around its sub-items.
+ * This is useful for arranging a group of fields or other components within a single item in a form, so
+ * that it lines up nicely with other fields. A common use is for grouping a set of related fields under
+ * a single label in a form.
+ * 
+ * The container's configured {@link #items} will be layed out within the field body area according to the
+ * configured {@link #layout} type. The default layout is `'autocontainer'`.
+ * 
+ * Like regular fields, FieldContainer can inherit its decoration configuration from the
+ * {@link Ext.form.Panel#fieldDefaults fieldDefaults} of an enclosing FormPanel. In addition,
+ * FieldContainer itself can pass {@link #fieldDefaults} to any {@link Ext.form.Labelable fields}
+ * it may itself contain.
+ * 
+ * If you are grouping a set of {@link Ext.form.field.Checkbox Checkbox} or {@link Ext.form.field.Radio Radio}
+ * fields in a single labeled container, consider using a {@link Ext.form.CheckboxGroup}
+ * or {@link Ext.form.RadioGroup} instead as they are specialized for handling those types.
+ *
+ * # Example
+ * 
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'FieldContainer Example',
+ *         width: 550,
+ *         bodyPadding: 10,
+ * 
+ *         items: [{
+ *             xtype: 'fieldcontainer',
+ *             fieldLabel: 'Last Three Jobs',
+ *             labelWidth: 100,
+ * 
+ *             // The body area will contain three text fields, arranged
+ *             // horizontally, separated by draggable splitters.
+ *             layout: 'hbox',
+ *             items: [{
+ *                 xtype: 'textfield',
+ *                 flex: 1
+ *             }, {
+ *                 xtype: 'splitter'
+ *             }, {
+ *                 xtype: 'textfield',
+ *                 flex: 1
+ *             }, {
+ *                 xtype: 'splitter'
+ *             }, {
+ *                 xtype: 'textfield',
+ *                 flex: 1
+ *             }]
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ * 
+ * # Usage of fieldDefaults
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'FieldContainer Example',
+ *         width: 350,
+ *         bodyPadding: 10,
+ * 
+ *         items: [{
+ *             xtype: 'fieldcontainer',
+ *             fieldLabel: 'Your Name',
+ *             labelWidth: 75,
+ *             defaultType: 'textfield',
+ * 
+ *             // Arrange fields vertically, stretched to full width
+ *             layout: 'anchor',
+ *             defaults: {
+ *                 layout: '100%'
+ *             },
+ * 
+ *             // These config values will be applied to both sub-fields, except
+ *             // for Last Name which will use its own msgTarget.
+ *             fieldDefaults: {
+ *                 msgTarget: 'under',
+ *                 labelAlign: 'top'
+ *             },
+ * 
+ *             items: [{
+ *                 fieldLabel: 'First Name',
+ *                 name: 'firstName'
+ *             }, {
+ *                 fieldLabel: 'Last Name',
+ *                 name: 'lastName',
+ *                 msgTarget: 'under'
+ *             }]
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ * 
  * @docauthor Jason Johnston <jason@sencha.com>
  */
 Ext.define('Ext.form.FieldContainer', {
@@ -75499,7 +78878,7 @@ Ext.define('Ext.form.FieldContainer', {
      * {@link #msgTarget}. Defaults to false.
      */
     combineErrors: false,
-    
+
     maskOnDisable: false,
 
     initComponent: function() {
@@ -75534,11 +78913,9 @@ Ext.define('Ext.form.FieldContainer', {
     },
 
     onRender: function() {
-        var me = this,
-            renderSelectors = me.renderSelectors,
-            applyIf = Ext.applyIf;
+        var me = this;
 
-        applyIf(renderSelectors, me.getLabelableSelectors());
+        me.onLabelableRender();
 
         me.callParent(arguments);
     },
@@ -75612,8 +78989,8 @@ Ext.define('Ext.form.FieldContainer', {
      * messages from them. Defaults to prepending each message by the field name and a colon. This
      * can be overridden to provide custom combined error message handling, for instance changing
      * the format of each message or sorting the array (it is sorted in order of appearance by default).
-     * @param {Array} invalidFields An Array of the sub-fields which are currently invalid.
-     * @return {Array} The combined list of error messages
+     * @param {Ext.form.field.Field[]} invalidFields An Array of the sub-fields which are currently invalid.
+     * @return {String[]} The combined list of error messages
      */
     getCombinedErrors: function(invalidFields) {
         var forEach = Ext.Array.forEach,
@@ -75634,9 +79011,9 @@ Ext.define('Ext.form.FieldContainer', {
 
 /**
  * A {@link Ext.form.FieldContainer field container} which has a specialized layout for arranging
- * {@link Ext.form.field.Checkbox} controls into columns, and provides convenience {@link Ext.form.field.Field} methods
- * for {@link #getValue getting}, {@link #setValue setting}, and {@link #validate validating} the group
- * of checkboxes as a whole.
+ * {@link Ext.form.field.Checkbox} controls into columns, and provides convenience
+ * {@link Ext.form.field.Field} methods for {@link #getValue getting}, {@link #setValue setting},
+ * and {@link #validate validating} the group of checkboxes as a whole.
  *
  * # Validation
  *
@@ -75654,33 +79031,29 @@ Ext.define('Ext.form.FieldContainer', {
  * types; for instance you may wish to use a custom arrangement of hbox and vbox containers. In that case
  * the checkbox components at any depth will still be managed by the CheckboxGroup's validation.
  *
- * {@img Ext.form.CheckboxGroup/Ext.form.CheckboxGroup.png Ext.form.CheckboxGroup component}
- *
- * # Example usage
- *
+ *     @example
  *     Ext.create('Ext.form.Panel', {
  *         title: 'Checkbox Group',
  *         width: 300,
  *         height: 125,
  *         bodyPadding: 10,
- *         renderTo: Ext.getBody(),        
- *         items:[{            
+ *         renderTo: Ext.getBody(),
+ *         items:[{
  *             xtype: 'checkboxgroup',
  *             fieldLabel: 'Two Columns',
  *             // Arrange radio buttons into two columns, distributed vertically
  *             columns: 2,
  *             vertical: true,
  *             items: [
- *                 {boxLabel: 'Item 1', name: 'rb', inputValue: '1'},
- *                 {boxLabel: 'Item 2', name: 'rb', inputValue: '2', checked: true},
- *                 {boxLabel: 'Item 3', name: 'rb', inputValue: '3'},
- *                 {boxLabel: 'Item 4', name: 'rb', inputValue: '4'},
- *                 {boxLabel: 'Item 5', name: 'rb', inputValue: '5'},
- *                 {boxLabel: 'Item 6', name: 'rb', inputValue: '6'}
+ *                 { boxLabel: 'Item 1', name: 'rb', inputValue: '1' },
+ *                 { boxLabel: 'Item 2', name: 'rb', inputValue: '2', checked: true },
+ *                 { boxLabel: 'Item 3', name: 'rb', inputValue: '3' },
+ *                 { boxLabel: 'Item 4', name: 'rb', inputValue: '4' },
+ *                 { boxLabel: 'Item 5', name: 'rb', inputValue: '5' },
+ *                 { boxLabel: 'Item 6', name: 'rb', inputValue: '6' }
  *             ]
  *         }]
  *     });
- *
  */
 Ext.define('Ext.form.CheckboxGroup', {
     extend:'Ext.form.FieldContainer',
@@ -75696,42 +79069,45 @@ Ext.define('Ext.form.CheckboxGroup', {
      */
 
     /**
-     * @cfg {Array} items An Array of {@link Ext.form.field.Checkbox Checkbox}es or Checkbox config objects
-     * to arrange in the group.
+     * @cfg {Ext.form.field.Checkbox[]/Object[]} items
+     * An Array of {@link Ext.form.field.Checkbox Checkbox}es or Checkbox config objects to arrange in the group.
      */
 
     /**
-     * @cfg {String/Number/Array} columns Specifies the number of columns to use when displaying grouped
-     * checkbox/radio controls using automatic layout.  This config can take several types of values:
-     * <ul><li><b>'auto'</b> : <p class="sub-desc">The controls will be rendered one per column on one row and the width
-     * of each column will be evenly distributed based on the width of the overall field container. This is the default.</p></li>
-     * <li><b>Number</b> : <p class="sub-desc">If you specific a number (e.g., 3) that number of columns will be
-     * created and the contained controls will be automatically distributed based on the value of {@link #vertical}.</p></li>
-     * <li><b>Array</b> : <p class="sub-desc">You can also specify an array of column widths, mixing integer
-     * (fixed width) and float (percentage width) values as needed (e.g., [100, .25, .75]). Any integer values will
-     * be rendered first, then any float values will be calculated as a percentage of the remaining space. Float
-     * values do not have to add up to 1 (100%) although if you want the controls to take up the entire field
-     * container you should do so.</p></li></ul>
+     * @cfg {String/Number/Number[]} columns
+     * Specifies the number of columns to use when displaying grouped checkbox/radio controls using automatic layout.
+     * This config can take several types of values:
+     *
+     * - 'auto' - The controls will be rendered one per column on one row and the width of each column will be evenly
+     *   distributed based on the width of the overall field container. This is the default.
+     * - Number - If you specific a number (e.g., 3) that number of columns will be created and the contained controls
+     *   will be automatically distributed based on the value of {@link #vertical}.
+     * - Array - You can also specify an array of column widths, mixing integer (fixed width) and float (percentage
+     *   width) values as needed (e.g., [100, .25, .75]). Any integer values will be rendered first, then any float
+     *   values will be calculated as a percentage of the remaining space. Float values do not have to add up to 1
+     *   (100%) although if you want the controls to take up the entire field container you should do so.
      */
     columns : 'auto',
 
     /**
-     * @cfg {Boolean} vertical True to distribute contained controls across columns, completely filling each column
-     * top to bottom before starting on the next column.  The number of controls in each column will be automatically
-     * calculated to keep columns as even as possible.  The default value is false, so that controls will be added
-     * to columns one at a time, completely filling each row left to right before starting on the next row.
+     * @cfg {Boolean} vertical
+     * True to distribute contained controls across columns, completely filling each column top to bottom before
+     * starting on the next column. The number of controls in each column will be automatically calculated to keep
+     * columns as even as possible. The default value is false, so that controls will be added to columns one at a time,
+     * completely filling each row left to right before starting on the next row.
      */
     vertical : false,
 
     /**
-     * @cfg {Boolean} allowBlank False to validate that at least one item in the group is checked (defaults to true).
-     * If no items are selected at validation time, {@link #blankText} will be used as the error text.
+     * @cfg {Boolean} allowBlank
+     * False to validate that at least one item in the group is checked. If no items are selected at
+     * validation time, {@link #blankText} will be used as the error text.
      */
     allowBlank : true,
 
     /**
-     * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails (defaults to "You must
-     * select at least one item in this group")
+     * @cfg {String} blankText
+     * Error text to display if the {@link #allowBlank} validation fails
      */
     blankText : "You must select at least one item in this group",
 
@@ -75758,10 +79134,10 @@ Ext.define('Ext.form.CheckboxGroup', {
     },
 
     /**
+     * Initializes the field's value based on the initial config. If the {@link #value} config is specified then we use
+     * that to set the value; otherwise we initialize the originalValue by querying the values of all sub-checkboxes
+     * after they have been initialized.
      * @protected
-     * Initializes the field's value based on the initial config. If the {@link #value} config is specified
-     * then we use that to set the value; otherwise we initialize the originalValue by querying the values of
-     * all sub-checkboxes after they have been initialized.
      */
     initValue: function() {
         var me = this,
@@ -75773,8 +79149,9 @@ Ext.define('Ext.form.CheckboxGroup', {
     },
 
     /**
-     * @protected
      * When a checkbox is added to the group, monitor it for changes
+     * @param {Object} field
+     * @protected
      */
     onFieldAdded: function(field) {
         var me = this;
@@ -75799,9 +79176,9 @@ Ext.define('Ext.form.CheckboxGroup', {
     },
 
     /**
-     * Runs CheckboxGroup's validations and returns an array of any errors. The only error by default
-     * is if allowBlank is set to true and no items are checked.
-     * @return {Array} Array of all validation errors
+     * Runs CheckboxGroup's validations and returns an array of any errors. The only error by default is if allowBlank
+     * is set to true and no items are checked.
+     * @return {String[]} Array of all validation errors
      */
     getErrors: function() {
         var errors = [];
@@ -75821,7 +79198,7 @@ Ext.define('Ext.form.CheckboxGroup', {
     /**
      * @private Convenience function which calls the given function for every checkbox in the group
      * @param {Function} fn The function to call
-     * @param {Object} scope Optional scope object
+     * @param {Object} scope (Optional) scope object
      */
     eachBox: function(fn, scope) {
         Ext.Array.forEach(this.getBoxes(), fn, scope || this);
@@ -75829,7 +79206,7 @@ Ext.define('Ext.form.CheckboxGroup', {
 
     /**
      * Returns an Array of all checkboxes in the container which are currently checked
-     * @return {Array} Array of Ext.form.field.Checkbox components
+     * @return {Ext.form.field.Checkbox[]} Array of Ext.form.field.Checkbox components
      */
     getChecked: function() {
         return Ext.Array.filter(this.getBoxes(), function(cb) {
@@ -75853,8 +79230,8 @@ Ext.define('Ext.form.CheckboxGroup', {
     },
 
     /**
-     * Resets the checked state of all {@link Ext.form.field.Checkbox checkboxes} in the group to their
-     * originally loaded values and clears any validation messages.
+     * Resets the checked state of all {@link Ext.form.field.Checkbox checkboxes} in the group to their originally
+     * loaded values and clears any validation messages.
      * See {@link Ext.form.Basic}.{@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
      */
     reset: function() {
@@ -75885,51 +79262,54 @@ Ext.define('Ext.form.CheckboxGroup', {
 
 
     /**
-     * <p>Sets the value(s) of all checkboxes in the group. The expected format is an Object of
-     * name-value pairs corresponding to the names of the checkboxes in the group. Each pair can
-     * have either a single or multiple values:</p>
-     * <ul>
-     *   <li>A single Boolean or String value will be passed to the <code>setValue</code> method of the
-     *   checkbox with that name. See the rules in {@link Ext.form.field.Checkbox#setValue} for accepted values.</li>
-     *   <li>An Array of String values will be matched against the {@link Ext.form.field.Checkbox#inputValue inputValue}
-     *   of checkboxes in the group with that name; those checkboxes whose inputValue exists in the array will be
-     *   checked and others will be unchecked.</li>
-     * </ul>
-     * <p>If a checkbox's name is not in the mapping at all, it will be unchecked.</p>
-     * <p>An example:</p>
-     * <pre><code>var myCheckboxGroup = new Ext.form.CheckboxGroup({
-    columns: 3,
-    items: [{
-        name: 'cb1',
-        boxLabel: 'Single 1'
-    }, {
-        name: 'cb2',
-        boxLabel: 'Single 2'
-    }, {
-        name: 'cb3',
-        boxLabel: 'Single 3'
-    }, {
-        name: 'cbGroup',
-        boxLabel: 'Grouped 1'
-        inputValue: 'value1'
-    }, {
-        name: 'cbGroup',
-        boxLabel: 'Grouped 2'
-        inputValue: 'value2'
-    }, {
-        name: 'cbGroup',
-        boxLabel: 'Grouped 3'
-        inputValue: 'value3'
-    }]
-});
-
-myCheckboxGroup.setValue({
-    cb1: true,
-    cb3: false,
-    cbGroup: ['value1', 'value3']
-});</code></pre>
-     * <p>The above code will cause the checkbox named 'cb1' to be checked, as well as the first and third
-     * checkboxes named 'cbGroup'. The other three checkboxes will be unchecked.</p>
+     * Sets the value(s) of all checkboxes in the group. The expected format is an Object of name-value pairs
+     * corresponding to the names of the checkboxes in the group. Each pair can have either a single or multiple values:
+     *
+     *   - A single Boolean or String value will be passed to the `setValue` method of the checkbox with that name.
+     *     See the rules in {@link Ext.form.field.Checkbox#setValue} for accepted values.
+     *   - An Array of String values will be matched against the {@link Ext.form.field.Checkbox#inputValue inputValue}
+     *     of checkboxes in the group with that name; those checkboxes whose inputValue exists in the array will be
+     *     checked and others will be unchecked.
+     *
+     * If a checkbox's name is not in the mapping at all, it will be unchecked.
+     *
+     * An example:
+     *
+     *     var myCheckboxGroup = new Ext.form.CheckboxGroup({
+     *         columns: 3,
+     *         items: [{
+     *             name: 'cb1',
+     *             boxLabel: 'Single 1'
+     *         }, {
+     *             name: 'cb2',
+     *             boxLabel: 'Single 2'
+     *         }, {
+     *             name: 'cb3',
+     *             boxLabel: 'Single 3'
+     *         }, {
+     *             name: 'cbGroup',
+     *             boxLabel: 'Grouped 1'
+     *             inputValue: 'value1'
+     *         }, {
+     *             name: 'cbGroup',
+     *             boxLabel: 'Grouped 2'
+     *             inputValue: 'value2'
+     *         }, {
+     *             name: 'cbGroup',
+     *             boxLabel: 'Grouped 3'
+     *             inputValue: 'value3'
+     *         }]
+     *     });
+     *
+     *     myCheckboxGroup.setValue({
+     *         cb1: true,
+     *         cb3: false,
+     *         cbGroup: ['value1', 'value3']
+     *     });
+     *
+     * The above code will cause the checkbox named 'cb1' to be checked, as well as the first and third checkboxes named
+     * 'cbGroup'. The other three checkboxes will be unchecked.
+     *
      * @param {Object} value The mapping of checkbox names to values.
      * @return {Ext.form.CheckboxGroup} this
      */
@@ -75955,15 +79335,17 @@ myCheckboxGroup.setValue({
 
 
     /**
-     * <p>Returns an object containing the values of all checked checkboxes within the group. Each key-value pair
-     * in the object corresponds to a checkbox {@link Ext.form.field.Checkbox#name name}. If there is only one checked
-     * checkbox with a particular name, the value of that pair will be the String
-     * {@link Ext.form.field.Checkbox#inputValue inputValue} of that checkbox. If there are multiple checked checkboxes
-     * with that name, the value of that pair will be an Array of the selected inputValues.</p>
-     * <p>The object format returned from this method can also be passed directly to the {@link #setValue} method.</p>
-     * <p>NOTE: In Ext 3, this method returned an array of Checkbox components; this was changed to make it more
-     * consistent with other field components and with the {@link #setValue} argument signature. If you need the old
-     * behavior in Ext 4+, use the {@link #getChecked} method instead.</p>
+     * Returns an object containing the values of all checked checkboxes within the group. Each key-value pair in the
+     * object corresponds to a checkbox {@link Ext.form.field.Checkbox#name name}. If there is only one checked checkbox
+     * with a particular name, the value of that pair will be the String {@link Ext.form.field.Checkbox#inputValue
+     * inputValue} of that checkbox. If there are multiple checked checkboxes with that name, the value of that pair
+     * will be an Array of the selected inputValues.
+     *
+     * The object format returned from this method can also be passed directly to the {@link #setValue} method.
+     *
+     * NOTE: In Ext 3, this method returned an array of Checkbox components; this was changed to make it more consistent
+     * with other field components and with the {@link #setValue} argument signature. If you need the old behavior in
+     * Ext 4+, use the {@link #getChecked} method instead.
      */
     getValue: function() {
         var values = {};
@@ -76054,19 +79436,18 @@ Ext.define('Ext.form.CheckboxManager', {
 });
 
 /**
- * @class Ext.form.FieldSet
- * @extends Ext.container.Container
- * 
+ * @docauthor Jason Johnston <jason@sencha.com>
+ *
  * A container for grouping sets of fields, rendered as a HTML `fieldset` element. The {@link #title}
  * config will be rendered as the fieldset's `legend`.
- * 
+ *
  * While FieldSets commonly contain simple groups of fields, they are general {@link Ext.container.Container Containers}
  * and may therefore contain any type of components in their {@link #items}, including other nested containers.
  * The default {@link #layout} for the FieldSet's items is `'anchor'`, but it can be configured to use any other
  * layout type.
- * 
+ *
  * FieldSets may also be collapsed if configured to do so; this can be done in two ways:
- * 
+ *
  * 1. Set the {@link #collapsible} config to true; this will result in a collapse button being rendered next to
  *    the {@link #title legend title}, or:
  * 2. Set the {@link #checkboxToggle} config to true; this is similar to using {@link #collapsible} but renders
@@ -76074,10 +79455,9 @@ Ext.define('Ext.form.CheckboxManager', {
  *    checkbox is checked and collapsed when it is unchecked. The checkbox will also be included in the
  *    {@link Ext.form.Basic#submit form submit parameters} using the {@link #checkboxName} as its parameter name.
  *
- * {@img Ext.form.FieldSet/Ext.form.FieldSet.png Ext.form.FieldSet component}
+ * # Example usage
  *
- * ## Example usage
- * 
+ *     @example
  *     Ext.create('Ext.form.Panel', {
  *         title: 'Simple Form with FieldSets',
  *         labelWidth: 75, // label settings here cascade unless overridden
@@ -76123,8 +79503,6 @@ Ext.define('Ext.form.CheckboxManager', {
  *             }]
  *         }]
  *     });
- * 
- * @docauthor Jason Johnston <jason@sencha.com>
  */
 Ext.define('Ext.form.FieldSet', {
     extend: 'Ext.container.Container',
@@ -76137,48 +79515,48 @@ Ext.define('Ext.form.FieldSet', {
      */
 
     /**
-     * @cfg {Boolean} checkboxToggle
-     * Set to <tt>true</tt> to render a checkbox into the fieldset frame just
-     * in front of the legend to expand/collapse the fieldset when the checkbox is toggled. (defaults
-     * to <tt>false</tt>). This checkbox will be included in form submits using the {@link #checkboxName}.
+     * @cfg {Boolean} [checkboxToggle=false]
+     * Set to true to render a checkbox into the fieldset frame just in front of the legend to expand/collapse the
+     * fieldset when the checkbox is toggled.. This checkbox will be included in form submits using
+     * the {@link #checkboxName}.
      */
 
     /**
      * @cfg {String} checkboxName
-     * The name to assign to the fieldset's checkbox if <tt>{@link #checkboxToggle} = true</tt>
-     * (defaults to <tt>'[fieldset id]-checkbox'</tt>).
+     * The name to assign to the fieldset's checkbox if {@link #checkboxToggle} = true
+     * (defaults to '[fieldset id]-checkbox').
      */
 
     /**
-     * @cfg {Boolean} collapsible
-     * Set to <tt>true</tt> to make the fieldset collapsible and have the expand/collapse toggle button automatically
-     * rendered into the legend element, <tt>false</tt> to keep the fieldset statically sized with no collapse
-     * button (defaults to <tt>false</tt>). Another option is to configure <tt>{@link #checkboxToggle}</tt>.
-     * Use the {@link #collapsed} config to collapse the fieldset by default.
+     * @cfg {Boolean} [collapsible=false]
+     * Set to true to make the fieldset collapsible and have the expand/collapse toggle button automatically rendered
+     * into the legend element, false to keep the fieldset statically sized with no collapse button.
+     * Another option is to configure {@link #checkboxToggle}. Use the {@link #collapsed} config to collapse the
+     * fieldset by default.
      */
 
     /**
      * @cfg {Boolean} collapsed
-     * Set to <tt>true</tt> to render the fieldset as collapsed by default. If {@link #checkboxToggle} is specified,
-     * the checkbox will also be unchecked by default.
+     * Set to true to render the fieldset as collapsed by default. If {@link #checkboxToggle} is specified, the checkbox
+     * will also be unchecked by default.
      */
     collapsed: false,
 
     /**
-     * @property legend
-     * @type Ext.Component
-     * The component for the fieldset's legend. Will only be defined if the configuration requires a legend
-     * to be created, by setting the {@link #title} or {@link #checkboxToggle} options.
+     * @property {Ext.Component} legend
+     * The component for the fieldset's legend. Will only be defined if the configuration requires a legend to be
+     * created, by setting the {@link #title} or {@link #checkboxToggle} options.
      */
 
     /**
-     * @cfg {String} baseCls The base CSS class applied to the fieldset (defaults to <tt>'x-fieldset'</tt>).
+     * @cfg {String} [baseCls='x-fieldset']
+     * The base CSS class applied to the fieldset.
      */
     baseCls: Ext.baseCSSPrefix + 'fieldset',
 
     /**
-     * @cfg {String} layout The {@link Ext.container.Container#layout} for the fieldset's immediate child items.
-     * Defaults to <tt>'anchor'</tt>.
+     * @cfg {String} layout
+     * The {@link Ext.container.Container#layout} for the fieldset's immediate child items.
      */
     layout: 'anchor',
 
@@ -76187,8 +79565,8 @@ Ext.define('Ext.form.FieldSet', {
     // No aria role necessary as fieldset has its own recognized semantics
     ariaRole: '',
 
-    renderTpl: ['<div class="{baseCls}-body"></div>'],
-    
+    renderTpl: ['<div id="{id}-body" class="{baseCls}-body"></div>'],
+
     maskOnDisable: false,
 
     getElConfig: function(){
@@ -76204,10 +79582,8 @@ Ext.define('Ext.form.FieldSet', {
         // Create the Legend component if needed
         me.initLegend();
 
-        // Add body el selector
-        Ext.applyIf(me.renderSelectors, {
-            body: '.' + baseCls + '-body'
-        });
+        // Add body el
+        me.addChildEls('body');
 
         if (me.collapsed) {
             me.addCls(baseCls + '-collapsed');
@@ -76250,8 +79626,23 @@ Ext.define('Ext.form.FieldSet', {
             legend = me.legend = Ext.create('Ext.container.Container', {
                 baseCls: me.baseCls + '-header',
                 ariaRole: '',
+                ownerCt: this,
                 getElConfig: function(){
-                    return {tag: 'legend', cls: this.baseCls};
+                    var result = {
+                        tag: 'legend',
+                        cls: this.baseCls
+                    };
+
+                    // Gecko3 will kick every <div> out of <legend> and mess up every thing.
+                    // So here we change every <div> into <span>s. Therefore the following
+                    // clearer is not needed and since div introduces a lot of subsequent
+                    // problems, it is actually harmful.
+                    if (!Ext.isGecko3) {
+                        result.children = [{
+                            cls: Ext.baseCSSPrefix + 'clear'
+                        }];
+                    }
+                    return result;
                 },
                 items: legendItems
             });
@@ -76264,39 +79655,51 @@ Ext.define('Ext.form.FieldSet', {
     },
 
     /**
-     * @protected
-     * Creates the legend title component. This is only called internally, but could be overridden in subclasses
-     * to customize the title component.
+     * Creates the legend title component. This is only called internally, but could be overridden in subclasses to
+     * customize the title component.
      * @return Ext.Component
+     * @protected
      */
     createTitleCmp: function() {
         var me = this;
         me.titleCmp = Ext.create('Ext.Component', {
             html: me.title,
+            getElConfig: function() {
+                return {
+                    tag: Ext.isGecko3 ? 'span' : 'div',
+                    cls: me.titleCmp.cls,
+                    id: me.titleCmp.id
+                };
+            },
             cls: me.baseCls + '-header-text'
         });
         return me.titleCmp;
-        
     },
 
     /**
-     * @property checkboxCmp
-     * @type Ext.form.field.Checkbox
+     * @property {Ext.form.field.Checkbox} checkboxCmp
      * Refers to the {@link Ext.form.field.Checkbox} component that is added next to the title in the legend. Only
-     * populated if the fieldset is configured with <tt>{@link #checkboxToggle}:true</tt>.
+     * populated if the fieldset is configured with {@link #checkboxToggle}:true.
      */
 
     /**
-     * @protected
-     * Creates the checkbox component. This is only called internally, but could be overridden in subclasses
-     * to customize the checkbox's configuration or even return an entirely different component type.
+     * Creates the checkbox component. This is only called internally, but could be overridden in subclasses to
+     * customize the checkbox's configuration or even return an entirely different component type.
      * @return Ext.Component
+     * @protected
      */
     createCheckboxCmp: function() {
         var me = this,
             suffix = '-checkbox';
-            
+
         me.checkboxCmp = Ext.create('Ext.form.field.Checkbox', {
+            getElConfig: function() {
+                return {
+                    tag: Ext.isGecko3 ? 'span' : 'div',
+                    id: me.checkboxCmp.id,
+                    cls: me.checkboxCmp.cls
+                };
+            },
             name: me.checkboxName || me.id + suffix,
             cls: me.baseCls + '-header' + suffix,
             checked: !me.collapsed,
@@ -76309,28 +79712,34 @@ Ext.define('Ext.form.FieldSet', {
     },
 
     /**
-     * @property toggleCmp
-     * @type Ext.panel.Tool
-     * Refers to the {@link Ext.panel.Tool} component that is added as the collapse/expand button next
-     * to the title in the legend. Only populated if the fieldset is configured with <tt>{@link #collapsible}:true</tt>.
+     * @property {Ext.panel.Tool} toggleCmp
+     * Refers to the {@link Ext.panel.Tool} component that is added as the collapse/expand button next to the title in
+     * the legend. Only populated if the fieldset is configured with {@link #collapsible}:true.
      */
 
     /**
-     * @protected
-     * Creates the toggle button component. This is only called internally, but could be overridden in
-     * subclasses to customize the toggle component.
+     * Creates the toggle button component. This is only called internally, but could be overridden in subclasses to
+     * customize the toggle component.
      * @return Ext.Component
+     * @protected
      */
     createToggleCmp: function() {
         var me = this;
         me.toggleCmp = Ext.create('Ext.panel.Tool', {
+            getElConfig: function() {
+                return {
+                    tag: Ext.isGecko3 ? 'span' : 'div',
+                    id: me.toggleCmp.id,
+                    cls: me.toggleCmp.cls
+                };
+            },
             type: 'toggle',
             handler: me.toggle,
             scope: me
         });
         return me.toggleCmp;
     },
-    
+
     /**
      * Sets the title of this fieldset
      * @param {String} title The new title
@@ -76343,15 +79752,15 @@ Ext.define('Ext.form.FieldSet', {
         me.titleCmp.update(title);
         return me;
     },
-    
+
     getTargetEl : function() {
         return this.body || this.frameBody || this.el;
     },
-    
+
     getContentTarget: function() {
         return this.body;
     },
-    
+
     /**
      * @private
      * Include the legend component in the items for ComponentQuery
@@ -76377,7 +79786,7 @@ Ext.define('Ext.form.FieldSet', {
     expand : function(){
         return this.setExpanded(true);
     },
-    
+
     /**
      * Collapses the fieldset.
      * @return {Ext.form.FieldSet} this
@@ -76394,11 +79803,11 @@ Ext.define('Ext.form.FieldSet', {
             checkboxCmp = me.checkboxCmp;
 
         expanded = !!expanded;
-        
+
         if (checkboxCmp) {
             checkboxCmp.setValue(expanded);
         }
-        
+
         if (expanded) {
             me.removeCls(me.baseCls + '-collapsed');
         } else {
@@ -76421,7 +79830,8 @@ Ext.define('Ext.form.FieldSet', {
     },
 
     /**
-     * @private Handle changes in the checkbox checked state
+     * @private
+     * Handle changes in the checkbox checked state
      */
     onCheckChange: function(cmp, checked) {
         this.setExpanded(checked);
@@ -76437,54 +79847,51 @@ Ext.define('Ext.form.FieldSet', {
 });
 
 /**
- * @class Ext.form.Label
- * @extends Ext.Component
-
-Produces a standalone `<label />` element which can be inserted into a form and be associated with a field
-in that form using the {@link #forId} property.
-
-**NOTE:** in most cases it will be more appropriate to use the {@link Ext.form.Labelable#fieldLabel fieldLabel}
-and associated config properties ({@link Ext.form.Labelable#labelAlign}, {@link Ext.form.Labelable#labelWidth},
-etc.) in field components themselves, as that allows labels to be uniformly sized throughout the form.
-Ext.form.Label should only be used when your layout can not be achieved with the standard
-{@link Ext.form.Labelable field layout}.
-
-You will likely be associating the label with a field component that extends {@link Ext.form.field.Base}, so
-you should make sure the {@link #forId} is set to the same value as the {@link Ext.form.field.Base#inputId inputId}
-of that field.
-
-The label's text can be set using either the {@link #text} or {@link #html} configuration properties; the
-difference between the two is that the former will automatically escape HTML characters when rendering, while
-the latter will not.
-{@img Ext.form.Label/Ext.form.Label.png Ext.form.Label component}
-#Example usage:#
-
-This example creates a Label after its associated Text field, an arrangement that cannot currently
-be achieved using the standard Field layout's labelAlign.
-
-    Ext.create('Ext.form.Panel', {
-        title: 'Field with Label',
-        width: 400,
-        bodyPadding: 10,
-        renderTo: Ext.getBody(),
-        layout: {
-            type: 'hbox',
-            align: 'middle'
-        },
-        items: [{
-            xtype: 'textfield',
-            hideLabel: true,
-            flex: 1
-        }, {
-            xtype: 'label',
-            forId: 'myFieldId',
-            text: 'My Awesome Field',
-            margins: '0 0 0 10'
-        }]
-    });
-
- * @markdown
  * @docauthor Jason Johnston <jason@sencha.com>
+ *
+ * Produces a standalone `<label />` element which can be inserted into a form and be associated with a field
+ * in that form using the {@link #forId} property.
+ * 
+ * **NOTE:** in most cases it will be more appropriate to use the {@link Ext.form.Labelable#fieldLabel fieldLabel}
+ * and associated config properties ({@link Ext.form.Labelable#labelAlign}, {@link Ext.form.Labelable#labelWidth},
+ * etc.) in field components themselves, as that allows labels to be uniformly sized throughout the form.
+ * Ext.form.Label should only be used when your layout can not be achieved with the standard
+ * {@link Ext.form.Labelable field layout}.
+ * 
+ * You will likely be associating the label with a field component that extends {@link Ext.form.field.Base}, so
+ * you should make sure the {@link #forId} is set to the same value as the {@link Ext.form.field.Base#inputId inputId}
+ * of that field.
+ * 
+ * The label's text can be set using either the {@link #text} or {@link #html} configuration properties; the
+ * difference between the two is that the former will automatically escape HTML characters when rendering, while
+ * the latter will not.
+ *
+ * # Example
+ * 
+ * This example creates a Label after its associated Text field, an arrangement that cannot currently
+ * be achieved using the standard Field layout's labelAlign.
+ * 
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'Field with Label',
+ *         width: 400,
+ *         bodyPadding: 10,
+ *         renderTo: Ext.getBody(),
+ *         layout: {
+ *             type: 'hbox',
+ *             align: 'middle'
+ *         },
+ *         items: [{
+ *             xtype: 'textfield',
+ *             hideLabel: true,
+ *             flex: 1
+ *         }, {
+ *             xtype: 'label',
+ *             forId: 'myFieldId',
+ *             text: 'My Awesome Field',
+ *             margins: '0 0 0 10'
+ *         }]
+ *     });
  */
 Ext.define('Ext.form.Label', {
     extend:'Ext.Component',
@@ -76492,17 +79899,20 @@ Ext.define('Ext.form.Label', {
     requires: ['Ext.util.Format'],
 
     /**
-     * @cfg {String} text The plain text to display within the label (defaults to ''). If you need to include HTML
+     * @cfg {String} [text='']
+     * The plain text to display within the label. If you need to include HTML
      * tags within the label's innerHTML, use the {@link #html} config instead.
      */
     /**
-     * @cfg {String} forId The id of the input element to which this label will be bound via the standard HTML 'for'
+     * @cfg {String} forId
+     * The id of the input element to which this label will be bound via the standard HTML 'for'
      * attribute. If not specified, the attribute will not be added to the label. In most cases you will be
      * associating the label with a {@link Ext.form.field.Base} component, so you should make sure this matches
      * the {@link Ext.form.field.Base#inputId inputId} of that field.
      */
     /**
-     * @cfg {String} html An HTML fragment that will be used as the label's innerHTML (defaults to '').
+     * @cfg {String} [html='']
+     * An HTML fragment that will be used as the label's innerHTML.
      * Note that if {@link #text} is specified it will take precedence and this value will be ignored.
      */
     
@@ -76520,10 +79930,10 @@ Ext.define('Ext.form.Label', {
     /**
      * Updates the label's innerHTML with the specified string.
      * @param {String} text The new label text
-     * @param {Boolean} encode (optional) False to skip HTML-encoding the text when rendering it
-     * to the label (defaults to true which encodes the value). This might be useful if you want to include
-     * tags in the label's innerHTML rather than rendering them as string literals per the default logic.
-     * @return {Label} this
+     * @param {Boolean} [encode=true] False to skip HTML-encoding the text when rendering it
+     * to the label. This might be useful if you want to include tags in the label's innerHTML rather
+     * than rendering them as string literals per the default logic.
+     * @return {Ext.form.Label} this
      */
     setText : function(text, encode){
         var me = this;
@@ -76546,128 +79956,125 @@ Ext.define('Ext.form.Label', {
 
 
 /**
- * @class Ext.form.Panel
- * @extends Ext.panel.Panel
-
-FormPanel provides a standard container for forms. It is essentially a standard {@link Ext.panel.Panel} which
-automatically creates a {@link Ext.form.Basic BasicForm} for managing any {@link Ext.form.field.Field}
-objects that are added as descendants of the panel. It also includes conveniences for configuring and
-working with the BasicForm and the collection of Fields.
-
-__Layout__
-
-By default, FormPanel is configured with `{@link Ext.layout.container.Anchor layout:'anchor'}` for
-the layout of its immediate child items. This can be changed to any of the supported container layouts.
-The layout of sub-containers is configured in {@link Ext.container.Container#layout the standard way}.
-
-__BasicForm__
-
-Although **not listed** as configuration options of FormPanel, the FormPanel class accepts all
-of the config options supported by the {@link Ext.form.Basic} class, and will pass them along to
-the internal BasicForm when it is created.
-
-**Note**: If subclassing FormPanel, any configuration options for the BasicForm must be applied to
-the `initialConfig` property of the FormPanel. Applying {@link Ext.form.Basic BasicForm}
-configuration settings to `this` will *not* affect the BasicForm's configuration.
-
-The following events fired by the BasicForm will be re-fired by the FormPanel and can therefore be
-listened for on the FormPanel itself:
-
-- {@link Ext.form.Basic#beforeaction beforeaction}
-- {@link Ext.form.Basic#actionfailed actionfailed}
-- {@link Ext.form.Basic#actioncomplete actioncomplete}
-- {@link Ext.form.Basic#validitychange validitychange}
-- {@link Ext.form.Basic#dirtychange dirtychange}
-
-__Field Defaults__
-
-The {@link #fieldDefaults} config option conveniently allows centralized configuration of default values
-for all fields added as descendants of the FormPanel. Any config option recognized by implementations
-of {@link Ext.form.Labelable} may be included in this object. See the {@link #fieldDefaults} documentation
-for details of how the defaults are applied.
-
-__Form Validation__
-
-With the default configuration, form fields are validated on-the-fly while the user edits their values.
-This can be controlled on a per-field basis (or via the {@link #fieldDefaults} config) with the field
-config properties {@link Ext.form.field.Field#validateOnChange} and {@link Ext.form.field.Base#checkChangeEvents},
-and the FormPanel's config properties {@link #pollForChanges} and {@link #pollInterval}.
-
-Any component within the FormPanel can be configured with `formBind: true`. This will cause that
-component to be automatically disabled when the form is invalid, and enabled when it is valid. This is most
-commonly used for Button components to prevent submitting the form in an invalid state, but can be used on
-any component type.
-
-For more information on form validation see the following:
-
-- {@link Ext.form.field.Field#validateOnChange}
-- {@link #pollForChanges} and {@link #pollInterval}
-- {@link Ext.form.field.VTypes}
-- {@link Ext.form.Basic#doAction BasicForm.doAction clientValidation notes}
-
-__Form Submission__
-
-By default, Ext Forms are submitted through Ajax, using {@link Ext.form.action.Action}. See the documentation for
-{@link Ext.form.Basic} for details.
-{@img Ext.form.FormPanel/Ext.form.FormPanel.png Ext.form.FormPanel FormPanel component}
-__Example usage:__
-
-    Ext.create('Ext.form.Panel', {
-        title: 'Simple Form',
-        bodyPadding: 5,
-        width: 350,
-        
-        // The form will submit an AJAX request to this URL when submitted
-        url: 'save-form.php',
-        
-        // Fields will be arranged vertically, stretched to full width
-        layout: 'anchor',
-        defaults: {
-            anchor: '100%'
-        },
-        
-        // The fields
-        defaultType: 'textfield',
-        items: [{
-            fieldLabel: 'First Name',
-            name: 'first',
-            allowBlank: false
-        },{
-            fieldLabel: 'Last Name',
-            name: 'last',
-            allowBlank: false
-        }],
-        
-        // Reset and Submit buttons
-        buttons: [{
-            text: 'Reset',
-            handler: function() {
-                this.up('form').getForm().reset();
-            }
-        }, {
-            text: 'Submit',
-            formBind: true, //only enabled once the form is valid
-            disabled: true,
-            handler: function() {
-                var form = this.up('form').getForm();
-                if (form.isValid()) {
-                    form.submit({
-                        success: function(form, action) {
-                           Ext.Msg.alert('Success', action.result.msg);
-                        },
-                        failure: function(form, action) {
-                            Ext.Msg.alert('Failed', action.result.msg);
-                        }
-                    });
-                }
-            }
-        }],
-        renderTo: Ext.getBody()
-    });
-
- *
- * @markdown
  * @docauthor Jason Johnston <jason@sencha.com>
+ * 
+ * FormPanel provides a standard container for forms. It is essentially a standard {@link Ext.panel.Panel} which
+ * automatically creates a {@link Ext.form.Basic BasicForm} for managing any {@link Ext.form.field.Field}
+ * objects that are added as descendants of the panel. It also includes conveniences for configuring and
+ * working with the BasicForm and the collection of Fields.
+ * 
+ * # Layout
+ * 
+ * By default, FormPanel is configured with `{@link Ext.layout.container.Anchor layout:'anchor'}` for
+ * the layout of its immediate child items. This can be changed to any of the supported container layouts.
+ * The layout of sub-containers is configured in {@link Ext.container.Container#layout the standard way}.
+ * 
+ * # BasicForm
+ * 
+ * Although **not listed** as configuration options of FormPanel, the FormPanel class accepts all
+ * of the config options supported by the {@link Ext.form.Basic} class, and will pass them along to
+ * the internal BasicForm when it is created.
+ * 
+ * **Note**: If subclassing FormPanel, any configuration options for the BasicForm must be applied to
+ * the `initialConfig` property of the FormPanel. Applying {@link Ext.form.Basic BasicForm}
+ * configuration settings to `this` will *not* affect the BasicForm's configuration.
+ * 
+ * The following events fired by the BasicForm will be re-fired by the FormPanel and can therefore be
+ * listened for on the FormPanel itself:
+ * 
+ * - {@link Ext.form.Basic#beforeaction beforeaction}
+ * - {@link Ext.form.Basic#actionfailed actionfailed}
+ * - {@link Ext.form.Basic#actioncomplete actioncomplete}
+ * - {@link Ext.form.Basic#validitychange validitychange}
+ * - {@link Ext.form.Basic#dirtychange dirtychange}
+ * 
+ * # Field Defaults
+ * 
+ * The {@link #fieldDefaults} config option conveniently allows centralized configuration of default values
+ * for all fields added as descendants of the FormPanel. Any config option recognized by implementations
+ * of {@link Ext.form.Labelable} may be included in this object. See the {@link #fieldDefaults} documentation
+ * for details of how the defaults are applied.
+ * 
+ * # Form Validation
+ * 
+ * With the default configuration, form fields are validated on-the-fly while the user edits their values.
+ * This can be controlled on a per-field basis (or via the {@link #fieldDefaults} config) with the field
+ * config properties {@link Ext.form.field.Field#validateOnChange} and {@link Ext.form.field.Base#checkChangeEvents},
+ * and the FormPanel's config properties {@link #pollForChanges} and {@link #pollInterval}.
+ * 
+ * Any component within the FormPanel can be configured with `formBind: true`. This will cause that
+ * component to be automatically disabled when the form is invalid, and enabled when it is valid. This is most
+ * commonly used for Button components to prevent submitting the form in an invalid state, but can be used on
+ * any component type.
+ * 
+ * For more information on form validation see the following:
+ * 
+ * - {@link Ext.form.field.Field#validateOnChange}
+ * - {@link #pollForChanges} and {@link #pollInterval}
+ * - {@link Ext.form.field.VTypes}
+ * - {@link Ext.form.Basic#doAction BasicForm.doAction clientValidation notes}
+ * 
+ * # Form Submission
+ * 
+ * By default, Ext Forms are submitted through Ajax, using {@link Ext.form.action.Action}. See the documentation for
+ * {@link Ext.form.Basic} for details.
+ *
+ * # Example usage
+ * 
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'Simple Form',
+ *         bodyPadding: 5,
+ *         width: 350,
+ * 
+ *         // The form will submit an AJAX request to this URL when submitted
+ *         url: 'save-form.php',
+ * 
+ *         // Fields will be arranged vertically, stretched to full width
+ *         layout: 'anchor',
+ *         defaults: {
+ *             anchor: '100%'
+ *         },
+ * 
+ *         // The fields
+ *         defaultType: 'textfield',
+ *         items: [{
+ *             fieldLabel: 'First Name',
+ *             name: 'first',
+ *             allowBlank: false
+ *         },{
+ *             fieldLabel: 'Last Name',
+ *             name: 'last',
+ *             allowBlank: false
+ *         }],
+ * 
+ *         // Reset and Submit buttons
+ *         buttons: [{
+ *             text: 'Reset',
+ *             handler: function() {
+ *                 this.up('form').getForm().reset();
+ *             }
+ *         }, {
+ *             text: 'Submit',
+ *             formBind: true, //only enabled once the form is valid
+ *             disabled: true,
+ *             handler: function() {
+ *                 var form = this.up('form').getForm();
+ *                 if (form.isValid()) {
+ *                     form.submit({
+ *                         success: function(form, action) {
+ *                            Ext.Msg.alert('Success', action.result.msg);
+ *                         },
+ *                         failure: function(form, action) {
+ *                             Ext.Msg.alert('Failed', action.result.msg);
+ *                         }
+ *                     });
+ *                 }
+ *             }
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ *
  */
 Ext.define('Ext.form.Panel', {
     extend:'Ext.panel.Panel',
@@ -76680,22 +80087,23 @@ Ext.define('Ext.form.Panel', {
 
     /**
      * @cfg {Boolean} pollForChanges
-     * If set to <tt>true</tt>, sets up an interval task (using the {@link #pollInterval}) in which the 
+     * If set to `true`, sets up an interval task (using the {@link #pollInterval}) in which the
      * panel's fields are repeatedly checked for changes in their values. This is in addition to the normal detection
      * each field does on its own input element, and is not needed in most cases. It does, however, provide a
      * means to absolutely guarantee detection of all changes including some edge cases in some browsers which
-     * do not fire native events. Defaults to <tt>false</tt>.
+     * do not fire native events. Defaults to `false`.
      */
 
     /**
      * @cfg {Number} pollInterval
      * Interval in milliseconds at which the form's fields are checked for value changes. Only used if
-     * the {@link #pollForChanges} option is set to <tt>true</tt>. Defaults to 500 milliseconds.
+     * the {@link #pollForChanges} option is set to `true`. Defaults to 500 milliseconds.
      */
 
     /**
-     * @cfg {String} layout The {@link Ext.container.Container#layout} for the form panel's immediate child items.
-     * Defaults to <tt>'anchor'</tt>.
+     * @cfg {String} layout
+     * The {@link Ext.container.Container#layout} for the form panel's immediate child items.
+     * Defaults to `'anchor'`.
      */
     layout: 'anchor',
 
@@ -76703,11 +80111,11 @@ Ext.define('Ext.form.Panel', {
 
     initComponent: function() {
         var me = this;
-        
+
         if (me.frame) {
             me.border = false;
         }
-        
+
         me.initFieldAncestor();
         me.callParent();
 
@@ -76728,7 +80136,7 @@ Ext.define('Ext.form.Panel', {
     initItems: function() {
         // Create the BasicForm
         var me = this;
-        
+
         me.form = me.createForm();
         me.callParent();
         me.form.initialize();
@@ -76748,17 +80156,17 @@ Ext.define('Ext.form.Panel', {
     getForm: function() {
         return this.form;
     },
-    
+
     /**
      * Loads an {@link Ext.data.Model} into this form (internally just calls {@link Ext.form.Basic#loadRecord})
-     * See also {@link #trackResetOnLoad}.
+     * See also {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}.
      * @param {Ext.data.Model} record The record to load
      * @return {Ext.form.Basic} The Ext.form.Basic attached to this FormPanel
      */
     loadRecord: function(record) {
         return this.getForm().loadRecord(record);
     },
-    
+
     /**
      * Returns the currently loaded Ext.data.Model instance if one was loaded via {@link #loadRecord}.
      * @return {Ext.data.Model} The loaded instance
@@ -76766,7 +80174,7 @@ Ext.define('Ext.form.Panel', {
     getRecord: function() {
         return this.getForm().getRecord();
     },
-    
+
     /**
      * Convenience function for fetching the current value of each field in the form. This is the same as calling
      * {@link Ext.form.Basic#getValues this.getForm().getValues()}
@@ -76850,7 +80258,7 @@ Ext.define('Ext.form.Panel', {
     },
 
     /**
-     * Forces each field within the form panel to 
+     * Forces each field within the form panel to
      * {@link Ext.form.field.Field#checkChange check if its value has changed}.
      */
     checkChange: function() {
@@ -76882,29 +80290,28 @@ Ext.define('Ext.form.Panel', {
  * types; for instance you may wish to use a custom arrangement of hbox and vbox containers. In that case
  * the Radio components at any depth will still be managed by the RadioGroup's validation.
  *
- * {@img Ext.form.RadioGroup/Ext.form.RadioGroup.png Ext.form.RadioGroup component}
- *
  * # Example usage
  *
+ *     @example
  *     Ext.create('Ext.form.Panel', {
  *         title: 'RadioGroup Example',
  *         width: 300,
  *         height: 125,
  *         bodyPadding: 10,
- *         renderTo: Ext.getBody(),        
- *         items:[{            
+ *         renderTo: Ext.getBody(),
+ *         items:[{
  *             xtype: 'radiogroup',
  *             fieldLabel: 'Two Columns',
  *             // Arrange radio buttons into two columns, distributed vertically
  *             columns: 2,
  *             vertical: true,
  *             items: [
- *                 {boxLabel: 'Item 1', name: 'rb', inputValue: '1'},
- *                 {boxLabel: 'Item 2', name: 'rb', inputValue: '2', checked: true},
- *                 {boxLabel: 'Item 3', name: 'rb', inputValue: '3'},
- *                 {boxLabel: 'Item 4', name: 'rb', inputValue: '4'},
- *                 {boxLabel: 'Item 5', name: 'rb', inputValue: '5'},
- *                 {boxLabel: 'Item 6', name: 'rb', inputValue: '6'}
+ *                 { boxLabel: 'Item 1', name: 'rb', inputValue: '1' },
+ *                 { boxLabel: 'Item 2', name: 'rb', inputValue: '2', checked: true},
+ *                 { boxLabel: 'Item 3', name: 'rb', inputValue: '3' },
+ *                 { boxLabel: 'Item 4', name: 'rb', inputValue: '4' },
+ *                 { boxLabel: 'Item 5', name: 'rb', inputValue: '5' },
+ *                 { boxLabel: 'Item 6', name: 'rb', inputValue: '6' }
  *             ]
  *         }]
  *     });
@@ -76915,31 +80322,50 @@ Ext.define('Ext.form.RadioGroup', {
     alias: 'widget.radiogroup',
 
     /**
-     * @cfg {Array} items An Array of {@link Ext.form.field.Radio Radio}s or Radio config objects
-     * to arrange in the group.
+     * @cfg {Ext.form.field.Radio[]/Object[]} items
+     * An Array of {@link Ext.form.field.Radio Radio}s or Radio config objects to arrange in the group.
      */
     /**
-     * @cfg {Boolean} allowBlank True to allow every item in the group to be blank (defaults to true).
+     * @cfg {Boolean} allowBlank True to allow every item in the group to be blank.
      * If allowBlank = false and no items are selected at validation time, {@link #blankText} will
      * be used as the error text.
      */
     allowBlank : true,
     /**
      * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails
-     * (defaults to 'You must select one item in this group')
      */
     blankText : 'You must select one item in this group',
-    
+
     // private
     defaultType : 'radiofield',
-    
+
     // private
     groupCls : Ext.baseCSSPrefix + 'form-radio-group',
 
     getBoxes: function() {
         return this.query('[isRadio]');
-    }
+    },
 
+    /**
+     * Sets the value of the radio group. The radio with corresponding name and value will be set.
+     * This method is simpler than {@link Ext.form.CheckboxGroup#setValue} because only 1 value is allowed
+     * for each name.
+     * 
+     * @param {Object} value The map from names to values to be set.
+     * @return {Ext.form.CheckboxGroup} this
+     */
+    setValue: function(value) {
+        var me = this;
+        if (Ext.isObject(value)) {
+            Ext.Object.each(value, function(name, cbValue) {
+                var radios = Ext.form.RadioManager.getWithValue(name, cbValue);
+                radios.each(function(cb) {
+                    cb.setValue(true);
+                });
+            });
+        }
+        return me;
+    }
 });
 
 /**
@@ -77228,7 +80654,7 @@ Ext.define('Ext.form.action.DirectSubmit', {
  * @extends Ext.form.action.Submit
  * <p>A class which handles submission of data from {@link Ext.form.Basic Form}s using a standard
  * <tt>&lt;form&gt;</tt> element submit. It does not handle the response from the submit.</p>
- * <p>If validation of the form fields fails, the Form's {@link Ext.form.Basic#afterAction} method
+ * <p>If validation of the form fields fails, the Form's afterAction method
  * will be called. Otherwise, afterAction will not be called.</p>
  * <p>Instances of this class are only created by a {@link Ext.form.Basic Form} when
  * {@link Ext.form.Basic#submit submit}ting, when the form's {@link Ext.form.Basic#standardSubmit}
@@ -77259,102 +80685,94 @@ Ext.define('Ext.form.action.StandardSubmit', {
 });
 
 /**
- * @class Ext.form.field.Checkbox
- * @extends Ext.form.field.Base
-
-Single checkbox field. Can be used as a direct replacement for traditional checkbox fields. Also serves as a
-parent class for {@link Ext.form.field.Radio radio buttons}.
-
-__Labeling:__ In addition to the {@link Ext.form.Labelable standard field labeling options}, checkboxes
-may be given an optional {@link #boxLabel} which will be displayed immediately after checkbox. Also see
-{@link Ext.form.CheckboxGroup} for a convenient method of grouping related checkboxes.
-
-__Values:__
-The main value of a checkbox is a boolean, indicating whether or not the checkbox is checked.
-The following values will check the checkbox:
-* `true`
-* `'true'`
-* `'1'`
-* `'on'`
-
-Any other value will uncheck the checkbox.
-
-In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be
-sent as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set
-this value if you have multiple checkboxes with the same {@link #name}. If not specified, the value `on`
-will be used.
-{@img Ext.form.Checkbox/Ext.form.Checkbox.png Ext.form.Checkbox Checkbox component}
-__Example usage:__
-
-    Ext.create('Ext.form.Panel', {
-        bodyPadding: 10,
-        width      : 300,
-        title      : 'Pizza Order',
-        items: [
-            {
-                xtype      : 'fieldcontainer',
-                fieldLabel : 'Toppings',
-                defaultType: 'checkboxfield',
-                items: [
-                    {
-                        boxLabel  : 'Anchovies',
-                        name      : 'topping',
-                        inputValue: '1',
-                        id        : 'checkbox1'
-                    }, {
-                        boxLabel  : 'Artichoke Hearts',
-                        name      : 'topping',
-                        inputValue: '2',
-                        checked   : true,
-                        id        : 'checkbox2'
-                    }, {
-                        boxLabel  : 'Bacon',
-                        name      : 'topping',
-                        inputValue: '3',
-                        id        : 'checkbox3'
-                    }
-                ]
-            }
-        ],
-        bbar: [
-            {
-                text: 'Select Bacon',
-                handler: function() {
-                    var checkbox = Ext.getCmp('checkbox3');
-                    checkbox.setValue(true);
-                }
-            },
-            '-',
-            {
-                text: 'Select All',
-                handler: function() {
-                    var checkbox1 = Ext.getCmp('checkbox1'),
-                        checkbox2 = Ext.getCmp('checkbox2'),
-                        checkbox3 = Ext.getCmp('checkbox3');
-
-                    checkbox1.setValue(true);
-                    checkbox2.setValue(true);
-                    checkbox3.setValue(true);
-                }
-            },
-            {
-                text: 'Deselect All',
-                handler: function() {
-                    var checkbox1 = Ext.getCmp('checkbox1'),
-                        checkbox2 = Ext.getCmp('checkbox2'),
-                        checkbox3 = Ext.getCmp('checkbox3');
-
-                    checkbox1.setValue(false);
-                    checkbox2.setValue(false);
-                    checkbox3.setValue(false);
-                }
-            }
-        ],
-        renderTo: Ext.getBody()
-    });
-
  * @docauthor Robert Dougan <rob@sencha.com>
- * @markdown
+ *
+ * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields. Also serves as a
+ * parent class for {@link Ext.form.field.Radio radio buttons}.
+ *
+ * # Labeling
+ *
+ * In addition to the {@link Ext.form.Labelable standard field labeling options}, checkboxes
+ * may be given an optional {@link #boxLabel} which will be displayed immediately after checkbox. Also see
+ * {@link Ext.form.CheckboxGroup} for a convenient method of grouping related checkboxes.
+ *
+ * # Values
+ *
+ * The main value of a checkbox is a boolean, indicating whether or not the checkbox is checked.
+ * The following values will check the checkbox:
+ *
+ * - `true`
+ * - `'true'`
+ * - `'1'`
+ * - `'on'`
+ *
+ * Any other value will uncheck the checkbox.
+ *
+ * In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be
+ * sent as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set
+ * this value if you have multiple checkboxes with the same {@link #name}. If not specified, the value `on`
+ * will be used.
+ *
+ * # Example usage
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         bodyPadding: 10,
+ *         width: 300,
+ *         title: 'Pizza Order',
+ *         items: [
+ *             {
+ *                 xtype: 'fieldcontainer',
+ *                 fieldLabel: 'Toppings',
+ *                 defaultType: 'checkboxfield',
+ *                 items: [
+ *                     {
+ *                         boxLabel  : 'Anchovies',
+ *                         name      : 'topping',
+ *                         inputValue: '1',
+ *                         id        : 'checkbox1'
+ *                     }, {
+ *                         boxLabel  : 'Artichoke Hearts',
+ *                         name      : 'topping',
+ *                         inputValue: '2',
+ *                         checked   : true,
+ *                         id        : 'checkbox2'
+ *                     }, {
+ *                         boxLabel  : 'Bacon',
+ *                         name      : 'topping',
+ *                         inputValue: '3',
+ *                         id        : 'checkbox3'
+ *                     }
+ *                 ]
+ *             }
+ *         ],
+ *         bbar: [
+ *             {
+ *                 text: 'Select Bacon',
+ *                 handler: function() {
+ *                     Ext.getCmp('checkbox3').setValue(true);
+ *                 }
+ *             },
+ *             '-',
+ *             {
+ *                 text: 'Select All',
+ *                 handler: function() {
+ *                     Ext.getCmp('checkbox1').setValue(true);
+ *                     Ext.getCmp('checkbox2').setValue(true);
+ *                     Ext.getCmp('checkbox3').setValue(true);
+ *                 }
+ *             },
+ *             {
+ *                 text: 'Deselect All',
+ *                 handler: function() {
+ *                     Ext.getCmp('checkbox1').setValue(false);
+ *                     Ext.getCmp('checkbox2').setValue(false);
+ *                     Ext.getCmp('checkbox3').setValue(false);
+ *                 }
+ *             }
+ *         ],
+ *         renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.form.field.Checkbox', {
     extend: 'Ext.form.field.Base',
@@ -77362,9 +80780,10 @@ Ext.define('Ext.form.field.Checkbox', {
     alternateClassName: 'Ext.form.Checkbox',
     requires: ['Ext.XTemplate', 'Ext.form.CheckboxManager'],
 
+    // note: {id} here is really {inputId}, but {cmpId} is available
     fieldSubTpl: [
         '<tpl if="boxLabel && boxLabelAlign == \'before\'">',
-            '<label class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
+            '<label id="{cmpId}-boxLabelEl" class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
         '</tpl>',
         // Creates not an actual checkbox, but a button which is given aria role="checkbox" and
         // styled with a custom checkbox image. This allows greater control and consistency in
@@ -77373,7 +80792,7 @@ Ext.define('Ext.form.field.Checkbox', {
             '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
             'class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />',
         '<tpl if="boxLabel && boxLabelAlign == \'after\'">',
-            '<label class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
+            '<label id="{cmpId}-boxLabelEl" class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
         '</tpl>',
         {
             disableFormats: true,
@@ -77384,72 +80803,79 @@ Ext.define('Ext.form.field.Checkbox', {
     isCheckbox: true,
 
     /**
-     * @cfg {String} focusCls The CSS class to use when the checkbox receives focus
-     * (defaults to <tt>'x-form-cb-focus'</tt>)
+     * @cfg {String} [focusCls='x-form-cb-focus']
+     * The CSS class to use when the checkbox receives focus
      */
     focusCls: Ext.baseCSSPrefix + 'form-cb-focus',
 
     /**
-     * @cfg {String} fieldCls The default CSS class for the checkbox (defaults to <tt>'x-form-field'</tt>)
+     * @cfg {String} [fieldCls='x-form-field']
+     * The default CSS class for the checkbox
      */
 
     /**
-     * @cfg {String} fieldBodyCls
+     * @cfg {String} [fieldBodyCls='x-form-cb-wrap']
      * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
-     * Defaults to 'x-form-cb-wrap.
+     * .
      */
     fieldBodyCls: Ext.baseCSSPrefix + 'form-cb-wrap',
 
     /**
-     * @cfg {Boolean} checked <tt>true</tt> if the checkbox should render initially checked (defaults to <tt>false</tt>)
+     * @cfg {Boolean} checked
+     * true if the checkbox should render initially checked
      */
     checked: false,
 
     /**
-     * @cfg {String} checkedCls The CSS class added to the component's main element when it is in the checked state.
+     * @cfg {String} [checkedCls='x-form-cb-checked']
+     * The CSS class added to the component's main element when it is in the checked state.
      */
     checkedCls: Ext.baseCSSPrefix + 'form-cb-checked',
 
     /**
-     * @cfg {String} boxLabel An optional text label that will appear next to the checkbox. Whether it appears before
-     * or after the checkbox is determined by the {@link #boxLabelAlign} config (defaults to after).
+     * @cfg {String} boxLabel
+     * An optional text label that will appear next to the checkbox. Whether it appears before or after the checkbox is
+     * determined by the {@link #boxLabelAlign} config.
      */
 
     /**
-     * @cfg {String} boxLabelCls The CSS class to be applied to the {@link #boxLabel} element
+     * @cfg {String} [boxLabelCls='x-form-cb-label']
+     * The CSS class to be applied to the {@link #boxLabel} element
      */
     boxLabelCls: Ext.baseCSSPrefix + 'form-cb-label',
 
     /**
-     * @cfg {String} boxLabelAlign The position relative to the checkbox where the {@link #boxLabel} should
-     * appear. Recognized values are <tt>'before'</tt> and <tt>'after'</tt>. Defaults to <tt>'after'</tt>.
+     * @cfg {String} boxLabelAlign
+     * The position relative to the checkbox where the {@link #boxLabel} should appear. Recognized values are 'before'
+     * and 'after'.
      */
     boxLabelAlign: 'after',
 
     /**
-     * @cfg {String} inputValue The value that should go into the generated input element's value attribute and
-     * should be used as the parameter value when submitting as part of a form. Defaults to <tt>"on"</tt>.
+     * @cfg {String} inputValue
+     * The value that should go into the generated input element's value attribute and should be used as the parameter
+     * value when submitting as part of a form.
      */
     inputValue: 'on',
 
     /**
-     * @cfg {String} uncheckedValue If configured, this will be submitted as the checkbox's value during form
-     * submit if the checkbox is unchecked. By default this is undefined, which results in nothing being
-     * submitted for the checkbox field when the form is submitted (the default behavior of HTML checkboxes).
+     * @cfg {String} uncheckedValue
+     * If configured, this will be submitted as the checkbox's value during form submit if the checkbox is unchecked. By
+     * default this is undefined, which results in nothing being submitted for the checkbox field when the form is
+     * submitted (the default behavior of HTML checkboxes).
      */
 
     /**
-     * @cfg {Function} handler A function called when the {@link #checked} value changes (can be used instead of
-     * handling the {@link #change change event}). The handler is passed the following parameters:
-     * <div class="mdetail-params"><ul>
-     * <li><b>checkbox</b> : Ext.form.field.Checkbox<div class="sub-desc">The Checkbox being toggled.</div></li>
-     * <li><b>checked</b> : Boolean<div class="sub-desc">The new checked state of the checkbox.</div></li>
-     * </ul></div>
+     * @cfg {Function} handler
+     * A function called when the {@link #checked} value changes (can be used instead of handling the {@link #change
+     * change event}).
+     * @cfg {Ext.form.field.Checkbox} handler.checkbox The Checkbox being toggled.
+     * @cfg {Boolean} handler.checked The new checked state of the checkbox.
      */
 
     /**
-     * @cfg {Object} scope An object to use as the scope ('this' reference) of the {@link #handler} function
-     * (defaults to this Checkbox).
+     * @cfg {Object} scope
+     * An object to use as the scope ('this' reference) of the {@link #handler} function (defaults to this Checkbox).
      */
 
     // private overrides
@@ -77470,11 +80896,9 @@ Ext.define('Ext.form.field.Checkbox', {
             checked = !!me.checked;
 
         /**
-         * The original value of the field as configured in the {@link #checked} configuration, or
-         * as loaded by the last form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
-         * setting is <code>true</code>.
-         * @type Mixed
-         * @property originalValue
+         * @property {Object} originalValue
+         * The original value of the field as configured in the {@link #checked} configuration, or as loaded by the last
+         * form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} setting is `true`.
          */
         me.originalValue = me.lastValue = checked;
 
@@ -77485,15 +80909,14 @@ Ext.define('Ext.form.field.Checkbox', {
     // private
     onRender : function(ct, position) {
         var me = this;
-        Ext.applyIf(me.renderSelectors, {
-            /**
-             * @property boxLabelEl
-             * @type Ext.core.Element
-             * A reference to the label element created for the {@link #boxLabel}. Only present if the
-             * component has been rendered and has a boxLabel configured.
-             */
-            boxLabelEl: 'label.' + me.boxLabelCls
-        });
+
+        /**
+         * @property {Ext.Element} boxLabelEl
+         * A reference to the label element created for the {@link #boxLabel}. Only present if the component has been
+         * rendered and has a boxLabel configured.
+         */
+        me.addChildEls('boxLabelEl');
+
         Ext.applyIf(me.subTplData, {
             boxLabel: me.boxLabel,
             boxLabelCls: me.boxLabelCls,
@@ -77537,7 +80960,7 @@ Ext.define('Ext.form.field.Checkbox', {
 
     /**
      * Returns the submit value for the checkbox which can be used when submitting forms.
-     * @return {Boolean/null} True if checked; otherwise either the {@link #uncheckedValue} or null.
+     * @return {Boolean/Object} True if checked; otherwise either the {@link #uncheckedValue} or null.
      */
     getSubmitValue: function() {
         var unchecked = this.uncheckedValue,
@@ -77547,8 +80970,9 @@ Ext.define('Ext.form.field.Checkbox', {
 
     /**
      * Sets the checked state of the checkbox.
-     * @param {Boolean/String} value The following values will check the checkbox:
-     * <code>true, 'true', '1', or 'on'</code>, as well as a String that matches the {@link #inputValue}.
+     *
+     * @param {Boolean/String/Number} value The following values will check the checkbox:
+     * `true, 'true', '1', 1, or 'on'`, as well as a String that matches the {@link #inputValue}.
      * Any other value will uncheck the checkbox.
      * @return {Boolean} the new checked state of the checkbox
      */
@@ -77556,8 +80980,8 @@ Ext.define('Ext.form.field.Checkbox', {
         var me = this,
             inputEl = me.inputEl,
             inputValue = me.inputValue,
-            checked = (value === true || value === 'true' || value === '1' ||
-                      ((Ext.isString(value) && inputValue) ? value == inputValue : me.onRe.test(value)));
+            checked = (value === true || value === 'true' || value === '1' || value === 1 ||
+                (((Ext.isString(value) || Ext.isNumber(value)) && inputValue) ? value == inputValue : me.onRe.test(value)));
 
         if (inputEl) {
             inputEl.dom.setAttribute('aria-checked', checked);
@@ -77570,9 +80994,8 @@ Ext.define('Ext.form.field.Checkbox', {
 
     /**
      * Sets the checked state of the checkbox, and invokes change detection.
-     * @param {Boolean/String} checked The following values will check the checkbox:
-     * <code>true, 'true', '1', or 'on'</code>, as well as a String that matches the {@link #inputValue}.
-     * Any other value will uncheck the checkbox.
+     * @param {Boolean/String} checked The following values will check the checkbox: `true, 'true', '1', or 'on'`, as
+     * well as a String that matches the {@link #inputValue}. Any other value will uncheck the checkbox.
      * @return {Ext.form.field.Checkbox} this
      */
     setValue: function(checked) {
@@ -77613,6 +81036,12 @@ Ext.define('Ext.form.field.Checkbox', {
         me.callParent(arguments);
     },
 
+    // inherit docs
+    beforeDestroy: function(){
+        this.callParent();
+        this.getManager().removeAtKey(this.id);
+    },
+
     // inherit docs
     getManager: function() {
         return Ext.form.CheckboxManager;
@@ -77638,11 +81067,8 @@ Ext.define('Ext.form.field.Checkbox', {
         me.readOnly = readOnly;
     },
 
-    /**
-     * @protected Calculate and return the natural width of the bodyEl. It's possible that the initial
-     * rendering will cause the boxLabel to wrap and give us a bad width, so we must prevent wrapping
-     * while measuring.
-     */
+    // Calculates and returns the natural width of the bodyEl. It's possible that the initial rendering will
+    // cause the boxLabel to wrap and give us a bad width, so we must prevent wrapping while measuring.
     getBodyNaturalWidth: function() {
         var me = this,
             bodyEl = me.bodyEl,
@@ -77697,24 +81123,23 @@ Ext.define('Ext.layout.component.field.Trigger', {
     }
 });
 /**
- * @class Ext.view.View
- * @extends Ext.view.AbstractView
- *
- * A mechanism for displaying data using custom layout templates and formatting. DataView uses an {@link Ext.XTemplate}
- * as its internal templating mechanism, and is bound to an {@link Ext.data.Store}
- * so that as the data in the store changes the view is automatically updated to reflect the changes.  The view also
- * provides built-in behavior for many common events that can occur for its contained items including click, doubleclick,
- * mouseover, mouseout, etc. as well as a built-in selection model. <b>In order to use these features, an {@link #itemSelector}
- * config must be provided for the DataView to determine what nodes it will be working with.</b>
+ * A mechanism for displaying data using custom layout templates and formatting.
  *
- * The example below binds a DataView to a {@link Ext.data.Store} and renders it into an {@link Ext.panel.Panel}.
+ * The View uses an {@link Ext.XTemplate} as its internal templating mechanism, and is bound to an
+ * {@link Ext.data.Store} so that as the data in the store changes the view is automatically updated
+ * to reflect the changes. The view also provides built-in behavior for many common events that can
+ * occur for its contained items including click, doubleclick, mouseover, mouseout, etc. as well as a
+ * built-in selection model. **In order to use these features, an {@link #itemSelector} config must
+ * be provided for the DataView to determine what nodes it will be working with.**
  *
- * {@img Ext.DataView/Ext.DataView.png Ext.DataView component}
+ * The example below binds a View to a {@link Ext.data.Store} and renders it into an {@link Ext.panel.Panel}.
  *
- *     Ext.regModel('Image', {
- *         Fields: [
- *             {name:'src', type:'string'},
- *             {name:'caption', type:'string'}
+ *     @example
+ *     Ext.define('Image', {
+ *         extend: 'Ext.data.Model',
+ *         fields: [
+ *             { name:'src', type:'string' },
+ *             { name:'caption', type:'string' }
  *         ]
  *     });
  *
@@ -77722,23 +81147,23 @@ Ext.define('Ext.layout.component.field.Trigger', {
  *         id:'imagesStore',
  *         model: 'Image',
  *         data: [
- *             {src:'http://www.sencha.com/img/20110215-feat-drawing.png', caption:'Drawing & Charts'},
- *             {src:'http://www.sencha.com/img/20110215-feat-data.png', caption:'Advanced Data'},
- *             {src:'http://www.sencha.com/img/20110215-feat-html5.png', caption:'Overhauled Theme'},
- *             {src:'http://www.sencha.com/img/20110215-feat-perf.png', caption:'Performance Tuned'}
+ *             { src:'http://www.sencha.com/img/20110215-feat-drawing.png', caption:'Drawing & Charts' },
+ *             { src:'http://www.sencha.com/img/20110215-feat-data.png', caption:'Advanced Data' },
+ *             { src:'http://www.sencha.com/img/20110215-feat-html5.png', caption:'Overhauled Theme' },
+ *             { src:'http://www.sencha.com/img/20110215-feat-perf.png', caption:'Performance Tuned' }
  *         ]
  *     });
  *
  *     var imageTpl = new Ext.XTemplate(
- *         '&lt;tpl for="."&gt;',
- *             '&lt;div style="thumb-wrap"&gt;',
- *               '&lt;img src="{src}" /&gt;',
- *               '&lt;br/&gt;&lt;span&gt;{caption}&lt;/span&gt;',
- *             '&lt;/div&gt;',
- *         '&lt;/tpl&gt;'
+ *         '<tpl for=".">',
+ *             '<div style="margin-bottom: 10px;" class="thumb-wrap">',
+ *               '<img src="{src}" />',
+ *               '<br/><span>{caption}</span>',
+ *             '</div>',
+ *         '</tpl>'
  *     );
  *
- *     Ext.create('Ext.DataView', {
+ *     Ext.create('Ext.view.View', {
  *         store: Ext.data.StoreManager.lookup('imagesStore'),
  *         tpl: imageTpl,
  *         itemSelector: 'div.thumb-wrap',
@@ -78039,7 +81464,7 @@ Ext.define('Ext.view.View', {
              * @event selectionchange
              * Fires when the selected nodes change. Relayed event from the underlying selection model.
              * @param {Ext.view.View} this
-             * @param {Array} selections Array of the selected nodes
+             * @param {HTMLElement[]} selections Array of the selected nodes
              */
             'selectionchange',
             /**
@@ -78047,7 +81472,7 @@ Ext.define('Ext.view.View', {
              * Fires before a selection is made. If any handlers return false, the selection is cancelled.
              * @param {Ext.view.View} this
              * @param {HTMLElement} node The node to be selected
-             * @param {Array} selections Array of currently selected nodes
+             * @param {HTMLElement[]} selections Array of currently selected nodes
              */
             'beforeselect'
         );
@@ -78257,7 +81682,7 @@ Ext.define('Ext.view.View', {
     onBeforeContainerKeyDown: Ext.emptyFn,
 
     /**
-     * Highlight a given item in the DataView. This is called by the mouseover handler if {@link #overItemCls}
+     * Highlights a given item in the DataView. This is called by the mouseover handler if {@link #overItemCls}
      * and {@link #trackOver} are configured, but can also be called manually by other code, for instance to
      * handle stepping through the list via keyboard navigation.
      * @param {HTMLElement} item The item to highlight
@@ -78270,7 +81695,7 @@ Ext.define('Ext.view.View', {
     },
 
     /**
-     * Un-highlight the currently highlighted item, if any.
+     * Un-highlights the currently highlighted item, if any.
      */
     clearHighlight: function() {
         var me = this,
@@ -78397,24 +81822,18 @@ Ext.define('Ext.layout.component.BoundList', {
 });
 
 /**
- * @class Ext.toolbar.TextItem
- * @extends Ext.toolbar.Item
- *
  * A simple class that renders text directly into a toolbar.
  *
- * ## Example usage
- *
- * {@img Ext.toolbar.TextItem/Ext.toolbar.TextItem.png TextItem component}
- *
- *      Ext.create('Ext.panel.Panel', {
- *          title: 'Panel with TextItem',
- *          width: 300,
- *          height: 200,
- *          tbar: [
- *              {xtype: 'tbtext', text: 'Sample TextItem'}
- *          ],
- *          renderTo: Ext.getBody()
- *      });
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Panel with TextItem',
+ *         width: 300,
+ *         height: 200,
+ *         tbar: [
+ *             { xtype: 'tbtext', text: 'Sample Text Item' }
+ *         ],
+ *         renderTo: Ext.getBody()
+ *     });
  *
  * @constructor
  * Creates a new TextItem
@@ -78425,16 +81844,16 @@ Ext.define('Ext.toolbar.TextItem', {
     requires: ['Ext.XTemplate'],
     alias: 'widget.tbtext',
     alternateClassName: 'Ext.Toolbar.TextItem',
-    
+
     /**
      * @cfg {String} text The text to be used as innerHTML (html tags are accepted)
      */
     text: '',
-    
+
     renderTpl: '{text}',
     //
     baseCls: Ext.baseCSSPrefix + 'toolbar-text',
-    
+
     onRender : function() {
         Ext.apply(this.renderData, {
             text: this.text
@@ -78456,59 +81875,53 @@ Ext.define('Ext.toolbar.TextItem', {
     }
 });
 /**
- * @class Ext.form.field.Trigger
- * @extends Ext.form.field.Text
- * <p>Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
- * The trigger has no default action, so you must assign a function to implement the trigger click handler by
- * overriding {@link #onTriggerClick}. You can create a Trigger field directly, as it renders exactly like a combobox
- * for which you can provide a custom implementation. 
- * {@img Ext.form.field.Trigger/Ext.form.field.Trigger.png Ext.form.field.Trigger component}
- * For example:</p>
- * <pre><code>
-Ext.define('Ext.ux.CustomTrigger', {
-    extend: 'Ext.form.field.Trigger',
-    alias: 'widget.customtrigger',
-    
-    // override onTriggerClick
-    onTriggerClick: function() {
-        Ext.Msg.alert('Status', 'You clicked my trigger!');
-    }
-});
-
-Ext.create('Ext.form.FormPanel', {
-    title: 'Form with TriggerField',
-    bodyPadding: 5,
-    width: 350,
-    renderTo: Ext.getBody(),
-    items:[{
-        xtype: 'customtrigger',
-        fieldLabel: 'Sample Trigger',
-        emptyText: 'click the trigger',
-    }]
-});
-</code></pre>
+ * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
+ * The trigger has no default action, so you must assign a function to implement the trigger click handler by overriding
+ * {@link #onTriggerClick}. You can create a Trigger field directly, as it renders exactly like a combobox for which you
+ * can provide a custom implementation.
  *
- * <p>However, in general you will most likely want to use Trigger as the base class for a reusable component.
- * {@link Ext.form.field.Date} and {@link Ext.form.field.ComboBox} are perfect examples of this.</p>
+ * For example:
  *
- * @constructor
- * Create a new Trigger field.
- * @param {Object} config Configuration options (valid {@Ext.form.field.Text} config options will also be applied
- * to the base Text field)
+ *     @example
+ *     Ext.define('Ext.ux.CustomTrigger', {
+ *         extend: 'Ext.form.field.Trigger',
+ *         alias: 'widget.customtrigger',
+ *
+ *         // override onTriggerClick
+ *         onTriggerClick: function() {
+ *             Ext.Msg.alert('Status', 'You clicked my trigger!');
+ *         }
+ *     });
+ *
+ *     Ext.create('Ext.form.FormPanel', {
+ *         title: 'Form with TriggerField',
+ *         bodyPadding: 5,
+ *         width: 350,
+ *         renderTo: Ext.getBody(),
+ *         items:[{
+ *             xtype: 'customtrigger',
+ *             fieldLabel: 'Sample Trigger',
+ *             emptyText: 'click the trigger',
+ *         }]
+ *     });
+ *
+ * However, in general you will most likely want to use Trigger as the base class for a reusable component.
+ * {@link Ext.form.field.Date} and {@link Ext.form.field.ComboBox} are perfect examples of this.
  */
 Ext.define('Ext.form.field.Trigger', {
     extend:'Ext.form.field.Text',
     alias: ['widget.triggerfield', 'widget.trigger'],
-    requires: ['Ext.core.DomHelper', 'Ext.util.ClickRepeater', 'Ext.layout.component.field.Trigger'],
+    requires: ['Ext.DomHelper', 'Ext.util.ClickRepeater', 'Ext.layout.component.field.Trigger'],
     alternateClassName: ['Ext.form.TriggerField', 'Ext.form.TwinTriggerField', 'Ext.form.Trigger'],
 
+    // note: {id} here is really {inputId}, but {cmpId} is available
     fieldSubTpl: [
         '<input id="{id}" type="{type}" ',
             '<tpl if="name">name="{name}" </tpl>',
             '<tpl if="size">size="{size}" </tpl>',
             '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
             'class="{fieldCls} {typeCls}" autocomplete="off" />',
-        '<div class="{triggerWrapCls}" role="presentation">',
+        '<div id="{cmpId}-triggerWrap" class="{triggerWrapCls}" role="presentation">',
             '{triggerEl}',
             '<div class="{clearCls}" role="presentation"></div>',
         '</div>',
@@ -78520,51 +81933,52 @@ Ext.define('Ext.form.field.Trigger', {
 
     /**
      * @cfg {String} triggerCls
-     * An additional CSS class used to style the trigger button.  The trigger will always get the
-     * {@link #triggerBaseCls} by default and <tt>triggerCls</tt> will be <b>appended</b> if specified.
-     * Defaults to undefined.
+     * An additional CSS class used to style the trigger button. The trigger will always get the {@link #triggerBaseCls}
+     * by default and triggerCls will be **appended** if specified.
      */
 
     /**
-     * @cfg {String} triggerBaseCls
-     * The base CSS class that is always added to the trigger button. The {@link #triggerCls} will be
-     * appended in addition to this class.
+     * @cfg {String} [triggerBaseCls='x-form-trigger']
+     * The base CSS class that is always added to the trigger button. The {@link #triggerCls} will be appended in
+     * addition to this class.
      */
     triggerBaseCls: Ext.baseCSSPrefix + 'form-trigger',
 
     /**
-     * @cfg {String} triggerWrapCls
+     * @cfg {String} [triggerWrapCls='x-form-trigger-wrap']
      * The CSS class that is added to the div wrapping the trigger button(s).
      */
     triggerWrapCls: Ext.baseCSSPrefix + 'form-trigger-wrap',
 
     /**
-     * @cfg {Boolean} hideTrigger <tt>true</tt> to hide the trigger element and display only the base
-     * text field (defaults to <tt>false</tt>)
+     * @cfg {Boolean} hideTrigger
+     * true to hide the trigger element and display only the base text field
      */
     hideTrigger: false,
 
     /**
-     * @cfg {Boolean} editable <tt>false</tt> to prevent the user from typing text directly into the field;
-     * the field can only have its value set via an action invoked by the trigger. (defaults to <tt>true</tt>).
+     * @cfg {Boolean} editable
+     * false to prevent the user from typing text directly into the field; the field can only have its value set via an
+     * action invoked by the trigger.
      */
     editable: true,
 
     /**
-     * @cfg {Boolean} readOnly <tt>true</tt> to prevent the user from changing the field, and
-     * hides the trigger.  Supercedes the editable and hideTrigger options if the value is true.
-     * (defaults to <tt>false</tt>)
+     * @cfg {Boolean} readOnly
+     * true to prevent the user from changing the field, and hides the trigger. Supercedes the editable and hideTrigger
+     * options if the value is true.
      */
     readOnly: false,
 
     /**
-     * @cfg {Boolean} selectOnFocus <tt>true</tt> to select any existing text in the field immediately on focus.
-     * Only applies when <tt>{@link #editable editable} = true</tt> (defaults to <tt>false</tt>).
+     * @cfg {Boolean} [selectOnFocus=false]
+     * true to select any existing text in the field immediately on focus. Only applies when
+     * {@link #editable editable} = true
      */
 
     /**
-     * @cfg {Boolean} repeatTriggerClick <tt>true</tt> to attach a {@link Ext.util.ClickRepeater click repeater}
-     * to the trigger. Defaults to <tt>false</tt>.
+     * @cfg {Boolean} repeatTriggerClick
+     * true to attach a {@link Ext.util.ClickRepeater click repeater} to the trigger.
      */
     repeatTriggerClick: false,
 
@@ -78614,30 +82028,27 @@ Ext.define('Ext.form.field.Trigger', {
         }
         triggerConfigs[i - 1].cls += ' ' + triggerBaseCls + '-last';
 
-        Ext.applyIf(me.renderSelectors, {
-            /**
-             * @property triggerWrap
-             * @type Ext.core.Element
-             * A reference to the div element wrapping the trigger button(s). Only set after the field has been rendered.
-             */
-            triggerWrap: '.' + triggerWrapCls
-        });
+        /**
+         * @property {Ext.Element} triggerWrap
+         * A reference to the div element wrapping the trigger button(s). Only set after the field has been rendered.
+         */
+        me.addChildEls('triggerWrap');
+
         Ext.applyIf(me.subTplData, {
             triggerWrapCls: triggerWrapCls,
-            triggerEl: Ext.core.DomHelper.markup(triggerConfigs),
+            triggerEl: Ext.DomHelper.markup(triggerConfigs),
             clearCls: me.clearCls
         });
 
         me.callParent(arguments);
 
         /**
-         * @property triggerEl
-         * @type Ext.CompositeElement
+         * @property {Ext.CompositeElement} triggerEl
          * A composite of all the trigger button elements. Only set after the field has been rendered.
          */
         me.triggerEl = Ext.select('.' + triggerBaseCls, true, me.triggerWrap.dom);
 
-        me.doc = Ext.isIE ? Ext.getBody() : Ext.getDoc();
+        me.doc = Ext.getDoc();
         me.initTrigger();
     },
 
@@ -78654,6 +82065,7 @@ Ext.define('Ext.form.field.Trigger', {
     afterRender: function() {
         this.callParent();
         this.updateEditState();
+        this.triggerEl.unselectable();
     },
 
     updateEditState: function() {
@@ -78711,11 +82123,11 @@ Ext.define('Ext.form.field.Trigger', {
     },
 
     /**
-     * @param {Boolean} editable True to allow the user to directly edit the field text
-     * Allow or prevent the user from directly editing the field text.  If false is passed,
-     * the user will only be able to modify the field using the trigger.  Will also add
-     * a click event to the text field which will call the trigger. This method
-     * is the runtime equivalent of setting the 'editable' config option at config time.
+     * Sets the editable state of this field. This method is the runtime equivalent of setting the 'editable' config
+     * option at config time.
+     * @param {Boolean} editable True to allow the user to directly edit the field text. If false is passed, the user
+     * will only be able to modify the field using the trigger. Will also add a click event to the text field which
+     * will call the trigger. 
      */
     setEditable: function(editable) {
         if (editable != this.editable) {
@@ -78725,11 +82137,11 @@ Ext.define('Ext.form.field.Trigger', {
     },
 
     /**
-     * @param {Boolean} readOnly True to prevent the user changing the field and explicitly
-     * hide the trigger.
-     * Setting this to true will superceed settings editable and hideTrigger.
-     * Setting this to false will defer back to editable and hideTrigger. This method
-     * is the runtime equivalent of setting the 'readOnly' config option at config time.
+     * Sets the read-only state of this field. This method is the runtime equivalent of setting the 'readOnly' config
+     * option at config time.
+     * @param {Boolean} readOnly True to prevent the user changing the field and explicitly hide the trigger. Setting
+     * this to true will superceed settings editable and hideTrigger. Setting this to false will defer back to editable
+     * and hideTrigger.
      */
     setReadOnly: function(readOnly) {
         if (readOnly != this.readOnly) {
@@ -78776,7 +82188,7 @@ Ext.define('Ext.form.field.Trigger', {
     // private
     onFocus: function() {
         var me = this;
-        this.callParent();
+        me.callParent();
         if (!me.mimicing) {
             me.bodyEl.addCls(me.wrapFocusCls);
             me.mimicing = true;
@@ -78848,10 +82260,10 @@ Ext.define('Ext.form.field.Trigger', {
     },
 
     /**
-     * The function that should handle the trigger's click event.  This method does nothing by default
-     * until overridden by an implementing function.  See Ext.form.field.ComboBox and Ext.form.field.Date for
-     * sample implementations.
-     * @method
+     * @method onTriggerClick
+     * @protected
+     * The function that should handle the trigger's click event. This method does nothing by default until overridden
+     * by an implementing function. See Ext.form.field.ComboBox and Ext.form.field.Date for sample implementations.
      * @param {Ext.EventObject} e
      */
     onTriggerClick: Ext.emptyFn
@@ -78868,17 +82280,15 @@ Ext.define('Ext.form.field.Trigger', {
 });
 
 /**
- * @class Ext.form.field.Picker
- * @extends Ext.form.field.Trigger
- * <p>An abstract class for fields that have a single trigger which opens a "picker" popup below
- * the field, e.g. a combobox menu list or a date picker. It provides a base implementation for
- * toggling the picker's visibility when the trigger is clicked, as well as keyboard navigation
- * and some basic events. Sizing and alignment of the picker can be controlled via the {@link #matchFieldWidth}
- * and {@link #pickerAlign}/{@link #pickerOffset} config properties respectively.</p>
- * <p>You would not normally use this class directly, but instead use it as the parent class for
- * a specific picker field implementation. Subclasses must implement the {@link #createPicker} method
- * to create a picker component appropriate for the field.</p>
- *
+ * An abstract class for fields that have a single trigger which opens a "picker" popup below the field, e.g. a combobox
+ * menu list or a date picker. It provides a base implementation for toggling the picker's visibility when the trigger
+ * is clicked, as well as keyboard navigation and some basic events. Sizing and alignment of the picker can be
+ * controlled via the {@link #matchFieldWidth} and {@link #pickerAlign}/{@link #pickerOffset} config properties
+ * respectively.
+ *
+ * You would not normally use this class directly, but instead use it as the parent class for a specific picker field
+ * implementation. Subclasses must implement the {@link #createPicker} method to create a picker component appropriate
+ * for the field.
  */
 Ext.define('Ext.form.field.Picker', {
     extend: 'Ext.form.field.Trigger',
@@ -78888,42 +82298,39 @@ Ext.define('Ext.form.field.Picker', {
 
     /**
      * @cfg {Boolean} matchFieldWidth
-     * Whether the picker dropdown's width should be explicitly set to match the width of the field.
-     * Defaults to <tt>true</tt>.
+     * Whether the picker dropdown's width should be explicitly set to match the width of the field. Defaults to true.
      */
     matchFieldWidth: true,
 
     /**
      * @cfg {String} pickerAlign
-     * The {@link Ext.core.Element#alignTo alignment position} with which to align the picker. Defaults
-     * to <tt>"tl-bl?"</tt>
+     * The {@link Ext.Element#alignTo alignment position} with which to align the picker. Defaults to "tl-bl?"
      */
     pickerAlign: 'tl-bl?',
 
     /**
-     * @cfg {Array} pickerOffset
+     * @cfg {Number[]} pickerOffset
      * An offset [x,y] to use in addition to the {@link #pickerAlign} when positioning the picker.
      * Defaults to undefined.
      */
 
     /**
      * @cfg {String} openCls
-     * A class to be added to the field's {@link #bodyEl} element when the picker is opened. Defaults
-     * to 'x-pickerfield-open'.
+     * A class to be added to the field's {@link #bodyEl} element when the picker is opened.
+     * Defaults to 'x-pickerfield-open'.
      */
     openCls: Ext.baseCSSPrefix + 'pickerfield-open',
 
     /**
-     * @property isExpanded
-     * @type Boolean
+     * @property {Boolean} isExpanded
      * True if the picker is currently expanded, false if not.
      */
 
     /**
-     * @cfg {Boolean} editable <tt>false</tt> to prevent the user from typing text directly into the field;
-     * the field can only have its value set via selecting a value from the picker. In this state, the picker
-     * can also be opened by clicking directly on the input field itself.
-     * (defaults to <tt>true</tt>).
+     * @cfg {Boolean} editable
+     * False to prevent the user from typing text directly into the field; the field can only have its value set via
+     * selecting a value from the picker. In this state, the picker can also be opened by clicking directly on the input
+     * field itself.
      */
     editable: true,
 
@@ -78949,7 +82356,7 @@ Ext.define('Ext.form.field.Picker', {
              * @event select
              * Fires when a value is selected via the picker.
              * @param {Ext.form.field.Picker} field This field instance
-             * @param {Mixed} value The value that was selected. The exact type of this value is dependent on
+             * @param {Object} value The value that was selected. The exact type of this value is dependent on
              * the individual field and picker implementations.
              */
             'select'
@@ -78988,7 +82395,7 @@ Ext.define('Ext.form.field.Picker', {
 
 
     /**
-     * Expand this field's picker dropdown.
+     * Expands this field's picker dropdown.
      */
     expand: function() {
         var me = this,
@@ -79020,34 +82427,45 @@ Ext.define('Ext.form.field.Picker', {
     onExpand: Ext.emptyFn,
 
     /**
+     * Aligns the picker to the input element
      * @protected
-     * Aligns the picker to the
      */
     alignPicker: function() {
         var me = this,
-            picker, isAbove,
-            aboveSfx = '-above';
+            picker;
 
-        if (this.isExpanded) {
+        if (me.isExpanded) {
             picker = me.getPicker();
             if (me.matchFieldWidth) {
                 // Auto the height (it will be constrained by min and max width) unless there are no records to display.
                 picker.setSize(me.bodyEl.getWidth(), picker.store && picker.store.getCount() ? null : 0);
             }
             if (picker.isFloating()) {
-                picker.alignTo(me.inputEl, me.pickerAlign, me.pickerOffset);
-
-                // add the {openCls}-above class if the picker was aligned above
-                // the field due to hitting the bottom of the viewport
-                isAbove = picker.el.getY() < me.inputEl.getY();
-                me.bodyEl[isAbove ? 'addCls' : 'removeCls'](me.openCls + aboveSfx);
-                picker.el[isAbove ? 'addCls' : 'removeCls'](picker.baseCls + aboveSfx);
+                me.doAlign();
             }
         }
     },
 
     /**
-     * Collapse this field's picker dropdown.
+     * Performs the alignment on the picker using the class defaults
+     * @private
+     */
+    doAlign: function(){
+        var me = this,
+            picker = me.picker,
+            aboveSfx = '-above',
+            isAbove;
+
+        me.picker.alignTo(me.inputEl, me.pickerAlign, me.pickerOffset);
+        // add the {openCls}-above class if the picker was aligned above
+        // the field due to hitting the bottom of the viewport
+        isAbove = picker.el.getY() < me.inputEl.getY();
+        me.bodyEl[isAbove ? 'addCls' : 'removeCls'](me.openCls + aboveSfx);
+        picker[isAbove ? 'addCls' : 'removeCls'](picker.baseCls + aboveSfx);
+    },
+
+    /**
+     * Collapses this field's picker dropdown.
      */
     collapse: function() {
         if (this.isExpanded && !this.isDestroyed) {
@@ -79090,7 +82508,7 @@ Ext.define('Ext.form.field.Picker', {
     },
 
     /**
-     * Return a reference to the picker component for this field, creating it if necessary by
+     * Returns a reference to the picker component for this field, creating it if necessary by
      * calling {@link #createPicker}.
      * @return {Ext.Component} The picker component
      */
@@ -79100,15 +82518,16 @@ Ext.define('Ext.form.field.Picker', {
     },
 
     /**
-     * Create and return the component to be used as this field's picker. Must be implemented
-     * by subclasses of Picker.
-     * @return {Ext.Component} The picker component
+     * @method
+     * Creates and returns the component to be used as this field's picker. Must be implemented by subclasses of Picker.
+     * The current field should also be passed as a configuration option to the picker component as the pickerField
+     * property.
      */
     createPicker: Ext.emptyFn,
 
     /**
-     * Handles the trigger click; by default toggles between expanding and collapsing the
-     * picker component.
+     * Handles the trigger click; by default toggles between expanding and collapsing the picker component.
+     * @protected
      */
     onTriggerClick: function() {
         var me = this;
@@ -79132,9 +82551,15 @@ Ext.define('Ext.form.field.Picker', {
     },
 
     onDestroy : function(){
-        var me = this;
+        var me = this,
+            picker = me.picker;
+
         Ext.EventManager.removeResizeListener(me.alignPicker, me);
-        Ext.destroy(me.picker, me.keyNav);
+        Ext.destroy(me.keyNav);
+        if (picker) {
+            delete picker.pickerField;
+            picker.destroy();
+        }
         me.callParent();
     }
 
@@ -79142,57 +82567,57 @@ Ext.define('Ext.form.field.Picker', {
 
 
 /**
- * @class Ext.form.field.Spinner
- * @extends Ext.form.field.Trigger
- * <p>A field with a pair of up/down spinner buttons. This class is not normally instantiated directly,
+ * A field with a pair of up/down spinner buttons. This class is not normally instantiated directly,
  * instead it is subclassed and the {@link #onSpinUp} and {@link #onSpinDown} methods are implemented
- * to handle when the buttons are clicked. A good example of this is the {@link Ext.form.field.Number} field
- * which uses the spinner to increment and decrement the field's value by its {@link Ext.form.field.Number#step step}
- * config value.</p>
- * {@img Ext.form.field.Spinner/Ext.form.field.Spinner.png Ext.form.field.Spinner field}
+ * to handle when the buttons are clicked. A good example of this is the {@link Ext.form.field.Number}
+ * field which uses the spinner to increment and decrement the field's value by its
+ * {@link Ext.form.field.Number#step step} config value.
+ *
  * For example:
-     Ext.define('Ext.ux.CustomSpinner', {
-        extend: 'Ext.form.field.Spinner',
-        alias: 'widget.customspinner',
-        
-        // override onSpinUp (using step isn't neccessary)
-        onSpinUp: function() {
-            var me = this;
-            if (!me.readOnly) {
-                var val = me.step; // set the default value to the step value
-                if(me.getValue() !== '') {
-                    val = parseInt(me.getValue().slice(0, -5)); // gets rid of " Pack"
-                }                          
-                me.setValue((val + me.step) + ' Pack');
-            }
-        },
-        
-        // override onSpinDown
-        onSpinDown: function() {
-            var me = this;
-            if (!me.readOnly) {
-                if(me.getValue() !== '') {
-                    val = parseInt(me.getValue().slice(0, -5)); // gets rid of " Pack"
-                }            
-                me.setValue((val - me.step) + ' Pack');
-            }
-        }
-    });
-    
-    Ext.create('Ext.form.FormPanel', {
-        title: 'Form with SpinnerField',
-        bodyPadding: 5,
-        width: 350,
-        renderTo: Ext.getBody(),
-        items:[{
-            xtype: 'customspinner',
-            fieldLabel: 'How Much Beer?',
-            step: 6
-        }]
-    });
- * <p>By default, pressing the up and down arrow keys will also trigger the onSpinUp and onSpinDown methods;
- * to prevent this, set <tt>{@link #keyNavEnabled} = false</tt>.</p>
  *
+ *     @example
+ *     Ext.define('Ext.ux.CustomSpinner', {
+ *         extend: 'Ext.form.field.Spinner',
+ *         alias: 'widget.customspinner',
+ *
+ *         // override onSpinUp (using step isn't neccessary)
+ *         onSpinUp: function() {
+ *             var me = this;
+ *             if (!me.readOnly) {
+ *                 var val = me.step; // set the default value to the step value
+ *                 if(me.getValue() !== '') {
+ *                     val = parseInt(me.getValue().slice(0, -5)); // gets rid of " Pack"
+ *                 }
+ *                 me.setValue((val + me.step) + ' Pack');
+ *             }
+ *         },
+ *
+ *         // override onSpinDown
+ *         onSpinDown: function() {
+ *             var val, me = this;
+ *             if (!me.readOnly) {
+ *                 if(me.getValue() !== '') {
+ *                     val = parseInt(me.getValue().slice(0, -5)); // gets rid of " Pack"
+ *                 }
+ *                 me.setValue((val - me.step) + ' Pack');
+ *             }
+ *         }
+ *     });
+ *
+ *     Ext.create('Ext.form.FormPanel', {
+ *         title: 'Form with SpinnerField',
+ *         bodyPadding: 5,
+ *         width: 350,
+ *         renderTo: Ext.getBody(),
+ *         items:[{
+ *             xtype: 'customspinner',
+ *             fieldLabel: 'How Much Beer?',
+ *             step: 6
+ *         }]
+ *     });
+ *
+ * By default, pressing the up and down arrow keys will also trigger the onSpinUp and onSpinDown methods;
+ * to prevent this, set `{@link #keyNavEnabled} = false`.
  */
 Ext.define('Ext.form.field.Spinner', {
     extend: 'Ext.form.field.Trigger',
@@ -79205,47 +82630,51 @@ Ext.define('Ext.form.field.Spinner', {
 
     /**
      * @cfg {Boolean} spinUpEnabled
-     * Specifies whether the up spinner button is enabled. Defaults to <tt>true</tt>. To change this
-     * after the component is created, use the {@link #setSpinUpEnabled} method.
+     * Specifies whether the up spinner button is enabled. Defaults to true. To change this after the component is
+     * created, use the {@link #setSpinUpEnabled} method.
      */
     spinUpEnabled: true,
 
     /**
      * @cfg {Boolean} spinDownEnabled
-     * Specifies whether the down spinner button is enabled. Defaults to <tt>true</tt>. To change this
-     * after the component is created, use the {@link #setSpinDownEnabled} method.
+     * Specifies whether the down spinner button is enabled. Defaults to true. To change this after the component is
+     * created, use the {@link #setSpinDownEnabled} method.
      */
     spinDownEnabled: true,
 
     /**
      * @cfg {Boolean} keyNavEnabled
-     * Specifies whether the up and down arrow keys should trigger spinning up and down.
-     * Defaults to <tt>true</tt>.
+     * Specifies whether the up and down arrow keys should trigger spinning up and down. Defaults to true.
      */
     keyNavEnabled: true,
 
     /**
      * @cfg {Boolean} mouseWheelEnabled
-     * Specifies whether the mouse wheel should trigger spinning up and down while the field has
-     * focus. Defaults to <tt>true</tt>.
+     * Specifies whether the mouse wheel should trigger spinning up and down while the field has focus.
+     * Defaults to true.
      */
     mouseWheelEnabled: true,
 
     /**
-     * @cfg {Boolean} repeatTriggerClick Whether a {@link Ext.util.ClickRepeater click repeater} should be
-     * attached to the spinner buttons. Defaults to <tt>true</tt>.
+     * @cfg {Boolean} repeatTriggerClick
+     * Whether a {@link Ext.util.ClickRepeater click repeater} should be attached to the spinner buttons.
+     * Defaults to true.
      */
     repeatTriggerClick: true,
 
     /**
-     * This method is called when the spinner up button is clicked, or when the up arrow key is pressed
-     * if {@link #keyNavEnabled} is <tt>true</tt>. Must be implemented by subclasses.
+     * @method
+     * @protected
+     * This method is called when the spinner up button is clicked, or when the up arrow key is pressed if
+     * {@link #keyNavEnabled} is true. Must be implemented by subclasses.
      */
     onSpinUp: Ext.emptyFn,
 
     /**
-     * This method is called when the spinner down button is clicked, or when the down arrow key is pressed
-     * if {@link #keyNavEnabled} is <tt>true</tt>. Must be implemented by subclasses.
+     * @method
+     * @protected
+     * This method is called when the spinner down button is clicked, or when the down arrow key is pressed if
+     * {@link #keyNavEnabled} is true. Must be implemented by subclasses.
      */
     onSpinDown: Ext.emptyFn,
 
@@ -79278,7 +82707,8 @@ Ext.define('Ext.form.field.Spinner', {
     },
 
     /**
-     * @private override
+     * @private
+     * Override.
      */
     onRender: function() {
         var me = this,
@@ -79288,14 +82718,12 @@ Ext.define('Ext.form.field.Spinner', {
         triggers = me.triggerEl;
 
         /**
-         * @property spinUpEl
-         * @type Ext.core.Element
+         * @property {Ext.Element} spinUpEl
          * The spinner up button element
          */
         me.spinUpEl = triggers.item(0);
         /**
-         * @property spinDownEl
-         * @type Ext.core.Element
+         * @property {Ext.Element} spinDownEl
          * The spinner down button element
          */
         me.spinDownEl = triggers.item(1);
@@ -79320,22 +82748,24 @@ Ext.define('Ext.form.field.Spinner', {
     },
 
     /**
-     * @private override
-     * Since the triggers are stacked, only measure the width of one of them.
+     * @private
+     * Override. Since the triggers are stacked, only measure the width of one of them.
      */
     getTriggerWidth: function() {
         return this.hideTrigger || this.readOnly ? 0 : this.spinUpEl.getWidth() + this.triggerWrap.getFrameWidth('lr');
     },
 
     /**
-     * @private Handles the spinner up button clicks.
+     * @private
+     * Handles the spinner up button clicks.
      */
     onTrigger1Click: function() {
         this.spinUp();
     },
 
     /**
-     * @private Handles the spinner down button clicks.
+     * @private
+     * Handles the spinner down button clicks.
      */
     onTrigger2Click: function() {
         this.spinDown();
@@ -79421,95 +82851,93 @@ Ext.define('Ext.form.field.Spinner', {
 
 });
 /**
- * @class Ext.form.field.Number
- * @extends Ext.form.field.Spinner
-
-A numeric text field that provides automatic keystroke filtering to disallow non-numeric characters,
-and numeric validation to limit the value to a range of valid numbers. The range of acceptable number
-values can be controlled by setting the {@link #minValue} and {@link #maxValue} configs, and fractional
-decimals can be disallowed by setting {@link #allowDecimals} to `false`.
-
-By default, the number field is also rendered with a set of up/down spinner buttons and has
-up/down arrow key and mouse wheel event listeners attached for incrementing/decrementing the value by the
-{@link #step} value. To hide the spinner buttons set `{@link #hideTrigger hideTrigger}:true`; to disable the arrow key
-and mouse wheel handlers set `{@link #keyNavEnabled keyNavEnabled}:false` and
-`{@link #mouseWheelEnabled mouseWheelEnabled}:false`. See the example below.
-
-#Example usage:#
-{@img Ext.form.Number/Ext.form.Number1.png Ext.form.Number component}
-    Ext.create('Ext.form.Panel', {
-        title: 'On The Wall',
-        width: 300,
-        bodyPadding: 10,
-        renderTo: Ext.getBody(),
-        items: [{
-            xtype: 'numberfield',
-            anchor: '100%',
-            name: 'bottles',
-            fieldLabel: 'Bottles of Beer',
-            value: 99,
-            maxValue: 99,
-            minValue: 0
-        }],
-        buttons: [{
-            text: 'Take one down, pass it around',
-            handler: function() {
-                this.up('form').down('[name=bottles]').spinDown();
-            }
-        }]
-    });
-
-#Removing UI Enhancements#
-{@img Ext.form.Number/Ext.form.Number2.png Ext.form.Number component}
-    Ext.create('Ext.form.Panel', {
-        title: 'Personal Info',
-        width: 300,
-        bodyPadding: 10,
-        renderTo: Ext.getBody(),        
-        items: [{
-            xtype: 'numberfield',
-            anchor: '100%',
-            name: 'age',
-            fieldLabel: 'Age',
-            minValue: 0, //prevents negative numbers
-    
-            // Remove spinner buttons, and arrow key and mouse wheel listeners
-            hideTrigger: true,
-            keyNavEnabled: false,
-            mouseWheelEnabled: false
-        }]
-    });
-
-#Using Step#
-    Ext.create('Ext.form.Panel', {
-        renderTo: Ext.getBody(),
-        title: 'Step',
-        width: 300,
-        bodyPadding: 10,
-        items: [{
-            xtype: 'numberfield',
-            anchor: '100%',
-            name: 'evens',
-            fieldLabel: 'Even Numbers',
-
-            // Set step so it skips every other number
-            step: 2,
-            value: 0,
-
-            // Add change handler to force user-entered numbers to evens
-            listeners: {
-                change: function(field, value) {
-                    value = parseInt(value, 10);
-                    field.setValue(value + value % 2);
-                }
-            }
-        }]
-    });
-
-
- *
- * @markdown
  * @docauthor Jason Johnston <jason@sencha.com>
+ *
+ * A numeric text field that provides automatic keystroke filtering to disallow non-numeric characters,
+ * and numeric validation to limit the value to a range of valid numbers. The range of acceptable number
+ * values can be controlled by setting the {@link #minValue} and {@link #maxValue} configs, and fractional
+ * decimals can be disallowed by setting {@link #allowDecimals} to `false`.
+ *
+ * By default, the number field is also rendered with a set of up/down spinner buttons and has
+ * up/down arrow key and mouse wheel event listeners attached for incrementing/decrementing the value by the
+ * {@link #step} value. To hide the spinner buttons set `{@link #hideTrigger hideTrigger}:true`; to disable
+ * the arrow key and mouse wheel handlers set `{@link #keyNavEnabled keyNavEnabled}:false` and
+ * `{@link #mouseWheelEnabled mouseWheelEnabled}:false`. See the example below.
+ *
+ * # Example usage
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'On The Wall',
+ *         width: 300,
+ *         bodyPadding: 10,
+ *         renderTo: Ext.getBody(),
+ *         items: [{
+ *             xtype: 'numberfield',
+ *             anchor: '100%',
+ *             name: 'bottles',
+ *             fieldLabel: 'Bottles of Beer',
+ *             value: 99,
+ *             maxValue: 99,
+ *             minValue: 0
+ *         }],
+ *         buttons: [{
+ *             text: 'Take one down, pass it around',
+ *             handler: function() {
+ *                 this.up('form').down('[name=bottles]').spinDown();
+ *             }
+ *         }]
+ *     });
+ *
+ * # Removing UI Enhancements
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'Personal Info',
+ *         width: 300,
+ *         bodyPadding: 10,
+ *         renderTo: Ext.getBody(),
+ *         items: [{
+ *             xtype: 'numberfield',
+ *             anchor: '100%',
+ *             name: 'age',
+ *             fieldLabel: 'Age',
+ *             minValue: 0, //prevents negative numbers
+ *
+ *             // Remove spinner buttons, and arrow key and mouse wheel listeners
+ *             hideTrigger: true,
+ *             keyNavEnabled: false,
+ *             mouseWheelEnabled: false
+ *         }]
+ *     });
+ *
+ * # Using Step
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         renderTo: Ext.getBody(),
+ *         title: 'Step',
+ *         width: 300,
+ *         bodyPadding: 10,
+ *         items: [{
+ *             xtype: 'numberfield',
+ *             anchor: '100%',
+ *             name: 'evens',
+ *             fieldLabel: 'Even Numbers',
+ *
+ *             // Set step so it skips every other number
+ *             step: 2,
+ *             value: 0,
+ *
+ *             // Add change handler to force user-entered numbers to evens
+ *             listeners: {
+ *                 change: function(field, value) {
+ *                     value = parseInt(value, 10);
+ *                     field.setValue(value + value % 2);
+ *                 }
+ *             }
+ *         }]
+ *     });
  */
 Ext.define('Ext.form.field.Number', {
     extend:'Ext.form.field.Spinner',
@@ -79524,71 +82952,79 @@ Ext.define('Ext.form.field.Number', {
      */
 
     /**
-     * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
+     * @cfg {Boolean} allowDecimals
+     * False to disallow decimal values
      */
     allowDecimals : true,
 
     /**
-     * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
+     * @cfg {String} decimalSeparator
+     * Character(s) to allow as the decimal separator
      */
     decimalSeparator : '.',
 
     /**
-     * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
+     * @cfg {Number} decimalPrecision
+     * The maximum precision to display after the decimal separator
      */
     decimalPrecision : 2,
 
     /**
-     * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY). Will be used by
-     * the field's validation logic, and for
-     * {@link Ext.form.field.Spinner#setSpinUpEnabled enabling/disabling the down spinner button}.
+     * @cfg {Number} minValue
+     * The minimum allowed value (defaults to Number.NEGATIVE_INFINITY). Will be used by the field's validation logic,
+     * and for {@link Ext.form.field.Spinner#setSpinUpEnabled enabling/disabling the down spinner button}.
      */
     minValue: Number.NEGATIVE_INFINITY,
 
     /**
-     * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE). Will be used by
-     * the field's validation logic, and for
+     * @cfg {Number} maxValue
+     * The maximum allowed value (defaults to Number.MAX_VALUE). Will be used by the field's validation logic, and for
      * {@link Ext.form.field.Spinner#setSpinUpEnabled enabling/disabling the up spinner button}.
      */
     maxValue: Number.MAX_VALUE,
 
     /**
-     * @cfg {Number} step Specifies a numeric interval by which the field's value will be incremented or
-     * decremented when the user invokes the spinner. Defaults to <tt>1</tt>.
+     * @cfg {Number} step
+     * Specifies a numeric interval by which the field's value will be incremented or decremented when the user invokes
+     * the spinner.
      */
     step: 1,
 
     /**
-     * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to 'The minimum
-     * value for this field is {minValue}')
+     * @cfg {String} minText
+     * Error text to display if the minimum value validation fails.
      */
     minText : 'The minimum value for this field is {0}',
 
     /**
-     * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to 'The maximum
-     * value for this field is {maxValue}')
+     * @cfg {String} maxText
+     * Error text to display if the maximum value validation fails.
      */
     maxText : 'The maximum value for this field is {0}',
 
     /**
-     * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
-     * if a valid character like '.' or '-' is left in the field with no number (defaults to '{value} is not a valid number')
+     * @cfg {String} nanText
+     * Error text to display if the value is not a valid number. For example, this can happen if a valid character like
+     * '.' or '-' is left in the field with no number.
      */
     nanText : '{0} is not a valid number',
 
     /**
-     * @cfg {String} negativeText Error text to display if the value is negative and {@link #minValue} is set to
-     * <tt>0</tt>. This is used instead of the {@link #minText} in that circumstance only.
+     * @cfg {String} negativeText
+     * Error text to display if the value is negative and {@link #minValue} is set to 0. This is used instead of the
+     * {@link #minText} in that circumstance only.
      */
     negativeText : 'The value cannot be negative',
 
     /**
-     * @cfg {String} baseChars The base set of characters to evaluate as valid numbers (defaults to '0123456789').
+     * @cfg {String} baseChars
+     * The base set of characters to evaluate as valid numbers.
      */
     baseChars : '0123456789',
 
     /**
-     * @cfg {Boolean} autoStripChars True to automatically strip not allowed characters from the field. Defaults to <tt>false</tt>
+     * @cfg {Boolean} autoStripChars
+     * True to automatically strip not allowed characters from the field.
      */
     autoStripChars: false,
 
@@ -79619,12 +83055,11 @@ Ext.define('Ext.form.field.Number', {
     },
 
     /**
-     * Runs all of Number's validations and returns an array of any errors. Note that this first
-     * runs Text's validations, so the returned array is an amalgamation of all field errors.
-     * The additional validations run test that the value is a number, and that it is within the
-     * configured min and max values.
-     * @param {Mixed} value The value to get errors for (defaults to the current field value)
-     * @return {Array} All validation errors for this field
+     * Runs all of Number's validations and returns an array of any errors. Note that this first runs Text's
+     * validations, so the returned array is an amalgamation of all field errors. The additional validations run test
+     * that the value is a number, and that it is within the configured min and max values.
+     * @param {Object} [value] The value to get errors for (defaults to the current field value)
+     * @return {String[]} All validation errors for this field
      */
     getErrors: function(value) {
         var me = this,
@@ -79715,7 +83150,6 @@ Ext.define('Ext.form.field.Number', {
 
     /**
      * @private
-     *
      */
     fixPrecision : function(value) {
         var me = this,
@@ -79756,110 +83190,107 @@ Ext.define('Ext.form.field.Number', {
 });
 
 /**
- * @class Ext.toolbar.Paging
- * @extends Ext.toolbar.Toolbar
- * <p>As the amount of records increases, the time required for the browser to render
- * them increases. Paging is used to reduce the amount of data exchanged with the client.
- * Note: if there are more records/rows than can be viewed in the available screen area, vertical
- * scrollbars will be added.</p>
- * <p>Paging is typically handled on the server side (see exception below). The client sends
- * parameters to the server side, which the server needs to interpret and then respond with the
- * appropriate data.</p>
- * <p><b>Ext.toolbar.Paging</b> is a specialized toolbar that is bound to a {@link Ext.data.Store}
- * and provides automatic paging control. This Component {@link Ext.data.Store#load load}s blocks
- * of data into the <tt>{@link #store}</tt> by passing {@link Ext.data.Store#paramNames paramNames} used for
- * paging criteria.</p>
+ * As the number of records increases, the time required for the browser to render them increases. Paging is used to
+ * reduce the amount of data exchanged with the client. Note: if there are more records/rows than can be viewed in the
+ * available screen area, vertical scrollbars will be added.
+ *
+ * Paging is typically handled on the server side (see exception below). The client sends parameters to the server side,
+ * which the server needs to interpret and then respond with the appropriate data.
+ *
+ * Ext.toolbar.Paging is a specialized toolbar that is bound to a {@link Ext.data.Store} and provides automatic
+ * paging control. This Component {@link Ext.data.Store#load load}s blocks of data into the {@link #store} by passing
+ * parameters used for paging criteria.
  *
  * {@img Ext.toolbar.Paging/Ext.toolbar.Paging.png Ext.toolbar.Paging component}
  *
- * <p>PagingToolbar is typically used as one of the Grid's toolbars:</p>
- * <pre><code>
- *    var itemsPerPage = 2;   // set the number of items you want per page
- *    
- *    var store = Ext.create('Ext.data.Store', {
- *        id:'simpsonsStore',
- *        autoLoad: false,
- *        fields:['name', 'email', 'phone'],
- *        pageSize: itemsPerPage, // items per page
- *        proxy: {
- *            type: 'ajax',
- *            url: 'pagingstore.js',  // url that will load data with respect to start and limit params
- *            reader: {
- *                type: 'json',
- *                root: 'items',
- *                totalProperty: 'total'
- *            }
- *        }
- *    });
- *    
- *    // specify segment of data you want to load using params
- *    store.load({
- *        params:{
- *            start:0,    
- *            limit: itemsPerPage
- *        }
- *    });
- *    
- *    Ext.create('Ext.grid.Panel', {
- *        title: 'Simpsons',
- *        store: store,
- *        columns: [
- *            {header: 'Name',  dataIndex: 'name'},
- *            {header: 'Email', dataIndex: 'email', flex:1},
- *            {header: 'Phone', dataIndex: 'phone'}
- *        ],
- *        width: 400,
- *        height: 125,
- *        dockedItems: [{
- *            xtype: 'pagingtoolbar',
- *            store: store,   // same store GridPanel is using
- *            dock: 'bottom',
- *            displayInfo: true
- *        }],
- *        renderTo: Ext.getBody()
- *    });
- * </code></pre>
+ * Paging Toolbar is typically used as one of the Grid's toolbars:
  *
- * <p>To use paging, pass the paging requirements to the server when the store is first loaded.</p>
- * <pre><code>
-store.load({
-    params: {
-        // specify params for the first page load if using paging
-        start: 0,          
-        limit: myPageSize,
-        // other params
-        foo:   'bar'
-    }
-});
- * </code></pre>
- * 
- * <p>If using {@link Ext.data.Store#autoLoad store's autoLoad} configuration:</p>
- * <pre><code>
-var myStore = new Ext.data.Store({
-    {@link Ext.data.Store#autoLoad autoLoad}: {start: 0, limit: 25},
-    ...
-});
- * </code></pre>
- * 
- * <p>The packet sent back from the server would have this form:</p>
- * <pre><code>
-{
-    "success": true,
-    "results": 2000, 
-    "rows": [ // <b>*Note:</b> this must be an Array 
-        { "id":  1, "name": "Bill", "occupation": "Gardener" },
-        { "id":  2, "name":  "Ben", "occupation": "Horticulturalist" },
-        ...
-        { "id": 25, "name":  "Sue", "occupation": "Botanist" }
-    ]
-}
- * </code></pre>
- * <p><u>Paging with Local Data</u></p>
- * <p>Paging can also be accomplished with local data using extensions:</p>
- * <div class="mdetail-params"><ul>
- * <li><a href="http://sencha.com/forum/showthread.php?t=71532">Ext.ux.data.PagingStore</a></li>
- * <li>Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)</li>
- * </ul></div>
+ *     @example
+ *     var itemsPerPage = 2;   // set the number of items you want per page
+ *
+ *     var store = Ext.create('Ext.data.Store', {
+ *         id:'simpsonsStore',
+ *         autoLoad: false,
+ *         fields:['name', 'email', 'phone'],
+ *         pageSize: itemsPerPage, // items per page
+ *         proxy: {
+ *             type: 'ajax',
+ *             url: 'pagingstore.js',  // url that will load data with respect to start and limit params
+ *             reader: {
+ *                 type: 'json',
+ *                 root: 'items',
+ *                 totalProperty: 'total'
+ *             }
+ *         }
+ *     });
+ *
+ *     // specify segment of data you want to load using params
+ *     store.load({
+ *         params:{
+ *             start:0,
+ *             limit: itemsPerPage
+ *         }
+ *     });
+ *
+ *     Ext.create('Ext.grid.Panel', {
+ *         title: 'Simpsons',
+ *         store: store,
+ *         columns: [
+ *             { header: 'Name',  dataIndex: 'name' },
+ *             { header: 'Email', dataIndex: 'email', flex: 1 },
+ *             { header: 'Phone', dataIndex: 'phone' }
+ *         ],
+ *         width: 400,
+ *         height: 125,
+ *         dockedItems: [{
+ *             xtype: 'pagingtoolbar',
+ *             store: store,   // same store GridPanel is using
+ *             dock: 'bottom',
+ *             displayInfo: true
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ * To use paging, pass the paging requirements to the server when the store is first loaded.
+ *
+ *     store.load({
+ *         params: {
+ *             // specify params for the first page load if using paging
+ *             start: 0,
+ *             limit: myPageSize,
+ *             // other params
+ *             foo:   'bar'
+ *         }
+ *     });
+ *
+ * If using {@link Ext.data.Store#autoLoad store's autoLoad} configuration:
+ *
+ *     var myStore = Ext.create('Ext.data.Store', {
+ *         {@link Ext.data.Store#autoLoad autoLoad}: {start: 0, limit: 25},
+ *         ...
+ *     });
+ *
+ * The packet sent back from the server would have this form:
+ *
+ *     {
+ *         "success": true,
+ *         "results": 2000,
+ *         "rows": [ // ***Note:** this must be an Array
+ *             { "id":  1, "name": "Bill", "occupation": "Gardener" },
+ *             { "id":  2, "name":  "Ben", "occupation": "Horticulturalist" },
+ *             ...
+ *             { "id": 25, "name":  "Sue", "occupation": "Botanist" }
+ *         ]
+ *     }
+ *
+ * ## Paging with Local Data
+ *
+ * Paging can also be accomplished with local data using extensions:
+ *
+ *   - [Ext.ux.data.PagingStore][1]
+ *   - Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)
+ *
+ *    [1]: http://sencha.com/forum/showthread.php?t=71532
  */
 Ext.define('Ext.toolbar.Paging', {
     extend: 'Ext.toolbar.Toolbar',
@@ -79867,89 +83298,98 @@ Ext.define('Ext.toolbar.Paging', {
     alternateClassName: 'Ext.PagingToolbar',
     requires: ['Ext.toolbar.TextItem', 'Ext.form.field.Number'],
     /**
-     * @cfg {Ext.data.Store} store
-     * The {@link Ext.data.Store} the paging toolbar should use as its data source (required).
+     * @cfg {Ext.data.Store} store (required)
+     * The {@link Ext.data.Store} the paging toolbar should use as its data source.
      */
+
     /**
      * @cfg {Boolean} displayInfo
-     * <tt>true</tt> to display the displayMsg (defaults to <tt>false</tt>)
+     * true to display the displayMsg
      */
     displayInfo: false,
+
     /**
      * @cfg {Boolean} prependButtons
-     * <tt>true</tt> to insert any configured <tt>items</tt> <i>before</i> the paging buttons.
-     * Defaults to <tt>false</tt>.
+     * true to insert any configured items _before_ the paging buttons.
      */
     prependButtons: false,
+
     /**
      * @cfg {String} displayMsg
-     * The paging status message to display (defaults to <tt>'Displaying {0} - {1} of {2}'</tt>).
-     * Note that this string is formatted using the braced numbers <tt>{0}-{2}</tt> as tokens
-     * that are replaced by the values for start, end and total respectively. These tokens should
-     * be preserved when overriding this string if showing those values is desired.
+     * The paging status message to display. Note that this string is
+     * formatted using the braced numbers {0}-{2} as tokens that are replaced by the values for start, end and total
+     * respectively. These tokens should be preserved when overriding this string if showing those values is desired.
      */
     displayMsg : 'Displaying {0} - {1} of {2}',
+
     /**
      * @cfg {String} emptyMsg
-     * The message to display when no records are found (defaults to 'No data to display')
+     * The message to display when no records are found.
      */
     emptyMsg : 'No data to display',
+
     /**
      * @cfg {String} beforePageText
-     * The text displayed before the input item (defaults to <tt>'Page'</tt>).
+     * The text displayed before the input item.
      */
     beforePageText : 'Page',
+
     /**
      * @cfg {String} afterPageText
-     * Customizable piece of the default paging text (defaults to <tt>'of {0}'</tt>). Note that
-     * this string is formatted using <tt>{0}</tt> as a token that is replaced by the number of
-     * total pages. This token should be preserved when overriding this string if showing the
-     * total page count is desired.
+     * Customizable piece of the default paging text. Note that this string is formatted using
+     * {0} as a token that is replaced by the number of total pages. This token should be preserved when overriding this
+     * string if showing the total page count is desired.
      */
     afterPageText : 'of {0}',
+
     /**
      * @cfg {String} firstText
-     * The quicktip text displayed for the first page button (defaults to <tt>'First Page'</tt>).
-     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
+     * The quicktip text displayed for the first page button.
+     * **Note**: quick tips must be initialized for the quicktip to show.
      */
     firstText : 'First Page',
+
     /**
      * @cfg {String} prevText
-     * The quicktip text displayed for the previous page button (defaults to <tt>'Previous Page'</tt>).
-     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
+     * The quicktip text displayed for the previous page button.
+     * **Note**: quick tips must be initialized for the quicktip to show.
      */
     prevText : 'Previous Page',
+
     /**
      * @cfg {String} nextText
-     * The quicktip text displayed for the next page button (defaults to <tt>'Next Page'</tt>).
-     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
+     * The quicktip text displayed for the next page button.
+     * **Note**: quick tips must be initialized for the quicktip to show.
      */
     nextText : 'Next Page',
+
     /**
      * @cfg {String} lastText
-     * The quicktip text displayed for the last page button (defaults to <tt>'Last Page'</tt>).
-     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
+     * The quicktip text displayed for the last page button.
+     * **Note**: quick tips must be initialized for the quicktip to show.
      */
     lastText : 'Last Page',
+
     /**
      * @cfg {String} refreshText
-     * The quicktip text displayed for the Refresh button (defaults to <tt>'Refresh'</tt>).
-     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
+     * The quicktip text displayed for the Refresh button.
+     * **Note**: quick tips must be initialized for the quicktip to show.
      */
     refreshText : 'Refresh',
+
     /**
      * @cfg {Number} inputItemWidth
-     * The width in pixels of the input field used to display and change the current page number (defaults to 30).
+     * The width in pixels of the input field used to display and change the current page number.
      */
     inputItemWidth : 30,
-    
+
     /**
      * Gets the standard paging items in the toolbar
      * @private
      */
     getPagingItems: function() {
         var me = this;
-        
+
         return [{
             itemId: 'first',
             tooltip: me.firstText,
@@ -80025,49 +83465,62 @@ Ext.define('Ext.toolbar.Paging', {
         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(
             /**
              * @event change
              * Fires after the active page has been changed.
              * @param {Ext.toolbar.Paging} this
-             * @param {Object} pageData An object that has these properties:<ul>
-             * <li><code>total</code> : Number <div class="sub-desc">The total number of records in the dataset as
-             * returned by the server</div></li>
-             * <li><code>currentPage</code> : Number <div class="sub-desc">The current page number</div></li>
-             * <li><code>pageCount</code> : Number <div class="sub-desc">The total number of pages (calculated from
-             * the total number of records in the dataset as returned by the server and the current {@link #pageSize})</div></li>
-             * <li><code>toRecord</code> : Number <div class="sub-desc">The starting record index for the current page</div></li>
-             * <li><code>fromRecord</code> : Number <div class="sub-desc">The ending record index for the current page</div></li>
-             * </ul>
+             * @param {Object} pageData An object that has these properties:
+             *
+             * - `total` : Number
+             *
+             *   The total number of records in the dataset as returned by the server
+             *
+             * - `currentPage` : Number
+             *
+             *   The current page number
+             *
+             * - `pageCount` : Number
+             *
+             *   The total number of pages (calculated from the total number of records in the dataset as returned by the
+             *   server and the current {@link Ext.data.Store#pageSize pageSize})
+             *
+             * - `toRecord` : Number
+             *
+             *   The starting record index for the current page
+             *
+             * - `fromRecord` : Number
+             *
+             *   The ending record index for the current page
              */
             'change',
+
             /**
              * @event beforechange
-             * Fires just before the active page is changed.
-             * Return false to prevent the active page from being changed.
+             * Fires just before the active page is changed. Return false to prevent the active page from being changed.
              * @param {Ext.toolbar.Paging} this
-             * @param {Number} page The page number that will be loaded on change 
+             * @param {Number} page The page number that will be loaded on change
              */
             'beforechange'
         );
         me.on('afterlayout', me.onLoad, me, {single: true});
 
-        me.bindStore(me.store, true);
+        me.bindStore(me.store || 'ext-empty-store', true);
     },
     // private
     updateInfo : function(){
@@ -80101,7 +83554,7 @@ Ext.define('Ext.toolbar.Paging', {
             currPage,
             pageCount,
             afterText;
-            
+
         if (!me.rendered) {
             return;
         }
@@ -80126,14 +83579,14 @@ Ext.define('Ext.toolbar.Paging', {
     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)
-            
+
         };
     },
 
@@ -80149,7 +83602,7 @@ Ext.define('Ext.toolbar.Paging', {
     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;
@@ -80232,7 +83685,7 @@ Ext.define('Ext.toolbar.Paging', {
     movePrevious : function(){
         var me = this,
             prev = me.store.currentPage - 1;
-        
+
         if (prev > 0) {
             if (me.fireEvent('beforechange', me, prev) !== false) {
                 me.store.previousPage();
@@ -80247,7 +83700,7 @@ Ext.define('Ext.toolbar.Paging', {
         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();
@@ -80259,9 +83712,9 @@ Ext.define('Ext.toolbar.Paging', {
      * Move to the last page, has the same effect as clicking the 'last' button.
      */
     moveLast : function(){
-        var me = this, 
+        var me = this,
             last = me.getPageData().pageCount;
-        
+
         if (me.fireEvent('beforechange', me, last) !== false) {
             me.store.loadPage(last);
         }
@@ -80273,7 +83726,7 @@ Ext.define('Ext.toolbar.Paging', {
     doRefresh : function(){
         var me = this,
             current = me.store.currentPage;
-        
+
         if (me.fireEvent('beforechange', me, current) !== false) {
             me.store.loadPage(current);
         }
@@ -80281,15 +83734,15 @@ Ext.define('Ext.toolbar.Paging', {
 
     /**
      * Binds the paging toolbar to the specified {@link Ext.data.Store}
-     * @param {Store} store The store to bind to this toolbar
+     * @param {Ext.data.Store} store The store to bind to this toolbar
      * @param {Boolean} initial (Optional) true to not remove listeners
      */
     bindStore : function(store, initial){
         var me = this;
-        
+
         if (!initial && me.store) {
             if(store !== me.store && me.store.autoDestroy){
-                me.store.destroy();
+                me.store.destroyStore();
             }else{
                 me.store.un('beforeload', me.beforeLoad, me);
                 me.store.un('load', me.onLoad, me);
@@ -80312,7 +83765,7 @@ Ext.define('Ext.toolbar.Paging', {
     },
 
     /**
-     * Unbinds the paging toolbar from the specified {@link Ext.data.Store} <b>(deprecated)</b>
+     * Unbinds the paging toolbar from the specified {@link Ext.data.Store} **(deprecated)**
      * @param {Ext.data.Store} store The data store to unbind
      */
     unbind : function(store){
@@ -80320,7 +83773,7 @@ Ext.define('Ext.toolbar.Paging', {
     },
 
     /**
-     * Binds the paging toolbar to the specified {@link Ext.data.Store} <b>(deprecated)</b>
+     * Binds the paging toolbar to the specified {@link Ext.data.Store} **(deprecated)**
      * @param {Ext.data.Store} store The data store to bind
      */
     bind : function(store){
@@ -80335,9 +83788,7 @@ Ext.define('Ext.toolbar.Paging', {
 });
 
 /**
- * @class Ext.view.BoundList
- * @extends Ext.view.View
- * An internal used DataView for ComboBox, MultiSelect and ItemSelector.
+ * An internally used DataView for {@link Ext.form.field.ComboBox ComboBox}.
  */
 Ext.define('Ext.view.BoundList', {
     extend: 'Ext.view.View',
@@ -80346,15 +83797,15 @@ Ext.define('Ext.view.BoundList', {
     requires: ['Ext.layout.component.BoundList', 'Ext.toolbar.Paging'],
 
     /**
-     * @cfg {Number} pageSize If greater than <tt>0</tt>, a {@link Ext.toolbar.Paging} is displayed at the
-     * bottom of the list and store queries will execute with page start and
-     * {@link Ext.toolbar.Paging#pageSize limit} parameters.
+     * @cfg {Number} pageSize
+     * If greater than `0`, a {@link Ext.toolbar.Paging} is displayed at the bottom of the list and store
+     * queries will execute with page {@link Ext.data.Operation#start start} and
+     * {@link Ext.data.Operation#limit limit} parameters. Defaults to `0`.
      */
     pageSize: 0,
 
     /**
-     * @property pagingToolbar
-     * @type {Ext.toolbar.Paging}
+     * @property {Ext.toolbar.Paging} pagingToolbar
      * A reference to the PagingToolbar instance in this view. Only populated if {@link #pageSize} is greater
      * than zero and the BoundList has been rendered.
      */
@@ -80362,6 +83813,7 @@ Ext.define('Ext.view.BoundList', {
     // private overrides
     autoScroll: true,
     baseCls: Ext.baseCSSPrefix + 'boundlist',
+    itemCls: Ext.baseCSSPrefix + 'boundlist-item',
     listItemCls: '',
     shadow: false,
     trackOver: true,
@@ -80371,13 +83823,13 @@ Ext.define('Ext.view.BoundList', {
 
     componentLayout: 'boundlist',
 
-    renderTpl: ['<div class="list-ct"></div>'],
+    renderTpl: ['<div id="{id}-listEl" class="list-ct"></div>'],
 
     initComponent: function() {
         var me = this,
             baseCls = me.baseCls,
-            itemCls = baseCls + '-item';
-        me.itemCls = itemCls;
+            itemCls = me.itemCls;
+            
         me.selectedItemCls = baseCls + '-selected';
         me.overItemCls = baseCls + '-item-over';
         me.itemSelector = "." + itemCls;
@@ -80404,9 +83856,7 @@ Ext.define('Ext.view.BoundList', {
 
         me.callParent();
 
-        Ext.applyIf(me.renderSelectors, {
-            listEl: '.list-ct'
-        });
+        me.addChildEls('listEl');
     },
 
     createPagingToolbar: function() {
@@ -80484,9 +83934,8 @@ Ext.define('Ext.view.BoundListKeyNav', {
     requires: 'Ext.view.BoundList',
 
     /**
-     * @cfg {Ext.view.BoundList} boundList
-     * @required
-     * The {@link Ext.view.BoundList} instance for which key navigation will be managed. This is required.
+     * @cfg {Ext.view.BoundList} boundList (required)
+     * The {@link Ext.view.BoundList} instance for which key navigation will be managed.
      */
 
     constructor: function(el, config) {
@@ -80568,8 +84017,7 @@ Ext.define('Ext.view.BoundListKeyNav', {
 
 });
 /**
- * @class Ext.form.field.ComboBox
- * @extends Ext.form.field.Picker
+ * @docauthor Jason Johnston <jason@sencha.com>
  *
  * A combobox control with support for autocomplete, remote loading, and many other features.
  *
@@ -80585,10 +84033,9 @@ Ext.define('Ext.view.BoundListKeyNav', {
  * If your store is not remote, i.e. it depends only on local data and is loaded up front, you should be
  * sure to set the {@link #queryMode} to `'local'`, as this will improve responsiveness for the user.
  *
- * {@img Ext.form.ComboBox/Ext.form.ComboBox.png Ext.form.ComboBox component}
- *
- * ## Example usage:
+ * # Example usage:
  *
+ *     @example
  *     // The data store containing the list of states
  *     var states = Ext.create('Ext.data.Store', {
  *         fields: ['abbr', 'name'],
@@ -80610,7 +84057,7 @@ Ext.define('Ext.view.BoundListKeyNav', {
  *         renderTo: Ext.getBody()
  *     });
  *
- * ## Events
+ * # Events
  *
  * To do something when something in ComboBox is selected, configure the select event:
  *
@@ -80626,12 +84073,10 @@ Ext.define('Ext.view.BoundListKeyNav', {
  *     var cb = new Ext.form.field.ComboBox(yourOptions);
  *     cb.on('select', yourFunction, yourScope);
  *
- * ## Multiple Selection
+ * # Multiple Selection
  *
  * ComboBox also allows selection of multiple items from the list; to enable multi-selection set the
  * {@link #multiSelect} config to `true`.
- *
- * @docauthor Jason Johnston <jason@sencha.com>
  */
 Ext.define('Ext.form.field.ComboBox', {
     extend:'Ext.form.field.Picker',
@@ -80640,213 +84085,267 @@ Ext.define('Ext.form.field.ComboBox', {
     alias: ['widget.combobox', 'widget.combo'],
 
     /**
-     * @cfg {String} triggerCls
-     * An additional CSS class used to style the trigger button. The trigger will always get the
-     * {@link #triggerBaseCls} by default and <code>triggerCls</code> will be <b>appended</b> if specified.
-     * Defaults to 'x-form-arrow-trigger' for ComboBox.
+     * @cfg {String} [triggerCls='x-form-arrow-trigger']
+     * An additional CSS class used to style the trigger button. The trigger will always get the {@link #triggerBaseCls}
+     * by default and `triggerCls` will be **appended** if specified.
      */
     triggerCls: Ext.baseCSSPrefix + 'form-arrow-trigger',
 
     /**
-     * @cfg {Ext.data.Store/Array} store The data source to which this combo is bound (defaults to <code>undefined</code>).
-     * Acceptable values for this property are:
-     * <div class="mdetail-params"><ul>
-     * <li><b>any {@link Ext.data.Store Store} subclass</b></li>
-     * <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.Store} internally,
-     * automatically generating {@link Ext.data.Field#name field names} to work with all data components.
-     * <div class="mdetail-params"><ul>
-     * <li><b>1-dimensional array</b> : (e.g., <code>['Foo','Bar']</code>)<div class="sub-desc">
-     * A 1-dimensional array will automatically be expanded (each array item will be used for both the combo
-     * {@link #valueField} and {@link #displayField})</div></li>
-     * <li><b>2-dimensional array</b> : (e.g., <code>[['f','Foo'],['b','Bar']]</code>)<div class="sub-desc">
-     * For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
-     * {@link #valueField}, while the value at index 1 is assumed to be the combo {@link #displayField}.
-     * </div></li></ul></div></li></ul></div>
-     * <p>See also <code>{@link #queryMode}</code>.</p>
+     * @private
+     * @cfg {String}
+     * CSS class used to find the {@link #hiddenDataEl}
+     */
+    hiddenDataCls: Ext.baseCSSPrefix + 'hide-display ' + Ext.baseCSSPrefix + 'form-data-hidden',
+
+    /**
+     * @override
+     */
+    fieldSubTpl: [
+        '<div class="{hiddenDataCls}" role="presentation"></div>',
+        '<input id="{id}" type="{type}" ',
+            '<tpl if="size">size="{size}" </tpl>',
+            '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
+            'class="{fieldCls} {typeCls}" autocomplete="off" />',
+        '<div id="{cmpId}-triggerWrap" class="{triggerWrapCls}" role="presentation">',
+            '{triggerEl}',
+            '<div class="{clearCls}" role="presentation"></div>',
+        '</div>',
+        {
+            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);
+    },
+
+    /**
+     * @cfg {Ext.data.Store/Array} store
+     * The data source to which this combo is bound. Acceptable values for this property are:
+     *
+     *   - **any {@link Ext.data.Store Store} subclass**
+     *   - **an Array** : Arrays will be converted to a {@link Ext.data.Store} internally, automatically generating
+     *     {@link Ext.data.Field#name field names} to work with all data components.
+     *
+     *     - **1-dimensional array** : (e.g., `['Foo','Bar']`)
+     *
+     *       A 1-dimensional array will automatically be expanded (each array item will be used for both the combo
+     *       {@link #valueField} and {@link #displayField})
+     *
+     *     - **2-dimensional array** : (e.g., `[['f','Foo'],['b','Bar']]`)
+     *
+     *       For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
+     *       {@link #valueField}, while the value at index 1 is assumed to be the combo {@link #displayField}.
+     *
+     * See also {@link #queryMode}.
      */
 
     /**
      * @cfg {Boolean} multiSelect
-     * If set to <code>true</code>, allows the combo field to hold more than one value at a time, and allows selecting
-     * multiple items from the dropdown list. The combo's text field will show all selected values separated by
-     * the {@link #delimiter}. (Defaults to <code>false</code>.)
+     * If set to `true`, allows the combo field to hold more than one value at a time, and allows selecting multiple
+     * items from the dropdown list. The combo's text field will show all selected values separated by the
+     * {@link #delimiter}.
      */
     multiSelect: false,
 
     /**
      * @cfg {String} delimiter
-     * The character(s) used to separate the {@link #displayField display values} of multiple selected items
-     * when <code>{@link #multiSelect} = true</code>. Defaults to <code>', '</code>.
+     * The character(s) used to separate the {@link #displayField display values} of multiple selected items when
+     * `{@link #multiSelect} = true`.
      */
     delimiter: ', ',
 
     /**
-     * @cfg {String} displayField The underlying {@link Ext.data.Field#name data field name} to bind to this
-     * ComboBox (defaults to 'text').
-     * <p>See also <code>{@link #valueField}</code>.</p>
+     * @cfg {String} displayField
+     * The underlying {@link Ext.data.Field#name data field name} to bind to this ComboBox.
+     *
+     * See also `{@link #valueField}`.
      */
     displayField: 'text',
 
     /**
-     * @cfg {String} valueField
-     * @required
+     * @cfg {String} valueField (required)
      * The underlying {@link Ext.data.Field#name data value name} to bind to this ComboBox (defaults to match
      * the value of the {@link #displayField} config).
-     * <p><b>Note</b>: use of a <code>valueField</code> requires the user to make a selection in order for a value to be
-     * mapped. See also <code>{@link #displayField}</code>.</p>
+     *
+     * **Note**: use of a `valueField` requires the user to make a selection in order for a value to be mapped. See also
+     * `{@link #displayField}`.
      */
 
     /**
-     * @cfg {String} triggerAction The action to execute when the trigger is clicked.
-     * <div class="mdetail-params"><ul>
-     * <li><b><code>'all'</code></b> : <b>Default</b>
-     * <p class="sub-desc">{@link #doQuery run the query} specified by the <code>{@link #allQuery}</code> config option</p></li>
-     * <li><b><code>'query'</code></b> :
-     * <p class="sub-desc">{@link #doQuery run the query} using the {@link Ext.form.field.Base#getRawValue raw value}.</p></li>
-     * </ul></div>
-     * <p>See also <code>{@link #queryParam}</code>.</p>
+     * @cfg {String} triggerAction
+     * The action to execute when the trigger is clicked.
+     *
+     *   - **`'all'`** :
+     *
+     *     {@link #doQuery run the query} specified by the `{@link #allQuery}` config option
+     *
+     *   - **`'query'`** :
+     *
+     *     {@link #doQuery run the query} using the {@link Ext.form.field.Base#getRawValue raw value}.
+     *
+     * See also `{@link #queryParam}`.
      */
     triggerAction: 'all',
 
     /**
-     * @cfg {String} allQuery The text query to send to the server to return all records for the list
-     * with no filtering (defaults to '')
+     * @cfg {String} allQuery
+     * The text query to send to the server to return all records for the list with no filtering
      */
     allQuery: '',
 
     /**
-     * @cfg {String} queryParam Name of the parameter used by the Store to pass the typed string when the ComboBox is configured with
-     * <code>{@link #queryMode}: 'remote'</code> (defaults to <code>'query'</code>). If explicitly set to a falsy value it will
-     * not be sent.
+     * @cfg {String} queryParam
+     * Name of the parameter used by the Store to pass the typed string when the ComboBox is configured with
+     * `{@link #queryMode}: 'remote'`. If explicitly set to a falsy value it will not be sent.
      */
     queryParam: 'query',
 
     /**
      * @cfg {String} queryMode
      * The mode in which the ComboBox uses the configured Store. Acceptable values are:
-     * <div class="mdetail-params"><ul>
-     * <li><b><code>'remote'</code></b> : <b>Default</b>
-     * <p>In <code>queryMode: 'remote'</code>, the ComboBox loads its Store dynamically based upon user interaction.</p>
-     * <p>This is typically used for "autocomplete" type inputs, and after the user finishes typing, the Store is {@link Ext.data.Store#load load}ed.</p>
-     * <p>A parameter containing the typed string is sent in the load request. The default parameter name for the input string is <code>query</code>, but this
-     * can be configured using the {@link #queryParam} config.</p>
-     * <p>In <code>queryMode: 'remote'</code>, the Store may be configured with <code>{@link Ext.data.Store#remoteFilter remoteFilter}: true</code>,
-     * and further filters may be <i>programatically</i> added to the Store which are then passed with every load request which allows the server
-     * to further refine the returned dataset.</p>
-     * <p>Typically, in an autocomplete situation, {@link #hideTrigger} is configured <code>true</code> because it has no meaning for autocomplete.</p></li>
-     * <li><b><code>'local'</code></b> :
-     * <p class="sub-desc">ComboBox loads local data</p>
-     * <pre><code>
-var combo = new Ext.form.field.ComboBox({
-    renderTo: document.body,
-    queryMode: 'local',
-    store: new Ext.data.ArrayStore({
-        id: 0,
-        fields: [
-            'myId',  // numeric value is the key
-            'displayText'
-        ],
-        data: [[1, 'item1'], [2, 'item2']]  // data is local
-    }),
-    valueField: 'myId',
-    displayField: 'displayText',
-    triggerAction: 'all'
-});
-     * </code></pre></li>
-     * </ul></div>
+     *
+     *   - **`'remote'`** :
+     *
+     *     In `queryMode: 'remote'`, the ComboBox loads its Store dynamically based upon user interaction.
+     *
+     *     This is typically used for "autocomplete" type inputs, and after the user finishes typing, the Store is {@link
+     *     Ext.data.Store#load load}ed.
+     *
+     *     A parameter containing the typed string is sent in the load request. The default parameter name for the input
+     *     string is `query`, but this can be configured using the {@link #queryParam} config.
+     *
+     *     In `queryMode: 'remote'`, the Store may be configured with `{@link Ext.data.Store#remoteFilter remoteFilter}:
+     *     true`, and further filters may be _programatically_ added to the Store which are then passed with every load
+     *     request which allows the server to further refine the returned dataset.
+     *
+     *     Typically, in an autocomplete situation, {@link #hideTrigger} is configured `true` because it has no meaning for
+     *     autocomplete.
+     *
+     *   - **`'local'`** :
+     *
+     *     ComboBox loads local data
+     *
+     *         var combo = new Ext.form.field.ComboBox({
+     *             renderTo: document.body,
+     *             queryMode: 'local',
+     *             store: new Ext.data.ArrayStore({
+     *                 id: 0,
+     *                 fields: [
+     *                     'myId',  // numeric value is the key
+     *                     'displayText'
+     *                 ],
+     *                 data: [[1, 'item1'], [2, 'item2']]  // data is local
+     *             }),
+     *             valueField: 'myId',
+     *             displayField: 'displayText',
+     *             triggerAction: 'all'
+     *         });
      */
     queryMode: 'remote',
 
     queryCaching: true,
 
     /**
-     * @cfg {Number} pageSize If greater than <code>0</code>, a {@link Ext.toolbar.Paging} is displayed in the
-     * footer of the dropdown list and the {@link #doQuery filter queries} will execute with page start and
-     * {@link Ext.toolbar.Paging#pageSize limit} parameters. Only applies when <code>{@link #queryMode} = 'remote'</code>
-     * (defaults to <code>0</code>).
+     * @cfg {Number} pageSize
+     * If greater than `0`, a {@link Ext.toolbar.Paging} is displayed in the footer of the dropdown list and the
+     * {@link #doQuery filter queries} will execute with page start and {@link Ext.view.BoundList#pageSize limit}
+     * parameters. Only applies when `{@link #queryMode} = 'remote'`.
      */
     pageSize: 0,
 
     /**
-     * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and
-     * sending the query to filter the dropdown list (defaults to <code>500</code> if <code>{@link #queryMode} = 'remote'</code>
-     * or <code>10</code> if <code>{@link #queryMode} = 'local'</code>)
+     * @cfg {Number} queryDelay
+     * The length of time in milliseconds to delay between the start of typing and sending the query to filter the
+     * dropdown list (defaults to `500` if `{@link #queryMode} = 'remote'` or `10` if `{@link #queryMode} = 'local'`)
      */
 
     /**
-     * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and
-     * {@link #typeAhead} activate (defaults to <code>4</code> if <code>{@link #queryMode} = 'remote'</code> or <code>0</code> if
-     * <code>{@link #queryMode} = 'local'</code>, does not apply if <code>{@link Ext.form.field.Trigger#editable editable} = false</code>).
+     * @cfg {Number} minChars
+     * The minimum number of characters the user must type before autocomplete and {@link #typeAhead} activate (defaults
+     * to `4` if `{@link #queryMode} = 'remote'` or `0` if `{@link #queryMode} = 'local'`, does not apply if
+     * `{@link Ext.form.field.Trigger#editable editable} = false`).
      */
 
     /**
-     * @cfg {Boolean} autoSelect <code>true</code> to automatically highlight the first result gathered by the data store
-     * in the dropdown list when it is opened. (Defaults to <code>true</code>). A false value would cause nothing in the
-     * list to be highlighted automatically, so the user would have to manually highlight an item before pressing
-     * the enter or {@link #selectOnTab tab} key to select it (unless the value of ({@link #typeAhead}) were true),
-     * or use the mouse to select a value.
+     * @cfg {Boolean} autoSelect
+     * `true` to automatically highlight the first result gathered by the data store in the dropdown list when it is
+     * opened. A false value would cause nothing in the list to be highlighted automatically, so
+     * the user would have to manually highlight an item before pressing the enter or {@link #selectOnTab tab} key to
+     * select it (unless the value of ({@link #typeAhead}) were true), or use the mouse to select a value.
      */
     autoSelect: true,
 
     /**
-     * @cfg {Boolean} typeAhead <code>true</code> to populate and autoselect the remainder of the text being
-     * typed after a configurable delay ({@link #typeAheadDelay}) if it matches a known value (defaults
-     * to <code>false</code>)
+     * @cfg {Boolean} typeAhead
+     * `true` to populate and autoselect the remainder of the text being typed after a configurable delay
+     * ({@link #typeAheadDelay}) if it matches a known value.
      */
     typeAhead: false,
 
     /**
-     * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
-     * if <code>{@link #typeAhead} = true</code> (defaults to <code>250</code>)
+     * @cfg {Number} typeAheadDelay
+     * The length of time in milliseconds to wait until the typeahead text is displayed if `{@link #typeAhead} = true`
      */
     typeAheadDelay: 250,
 
     /**
      * @cfg {Boolean} selectOnTab
-     * Whether the Tab key should select the currently highlighted item. Defaults to <code>true</code>.
+     * Whether the Tab key should select the currently highlighted item.
      */
     selectOnTab: true,
 
     /**
-     * @cfg {Boolean} forceSelection <code>true</code> to restrict the selected value to one of the values in the list,
-     * <code>false</code> to allow the user to set arbitrary text into the field (defaults to <code>false</code>)
+     * @cfg {Boolean} forceSelection
+     * `true` to restrict the selected value to one of the values in the list, `false` to allow the user to set
+     * arbitrary text into the field.
      */
     forceSelection: false,
 
     /**
-     * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
-     * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined). If this
-     * default text is used, it means there is no value set and no validation will occur on this field.
+     * @cfg {String} valueNotFoundText
+     * When using a name/value combo, if the value passed to setValue is not found in the store, valueNotFoundText will
+     * be displayed as the field text if defined. If this default text is used, it means there
+     * is no value set and no validation will occur on this field.
      */
 
     /**
-     * The value of the match string used to filter the store. Delete this property to force a requery.
-     * Example use:
-     * <pre><code>
-var combo = new Ext.form.field.ComboBox({
-    ...
-    queryMode: 'remote',
-    listeners: {
-        // delete the previous query in the beforequery event or set
-        // combo.lastQuery = null (this will reload the store the next time it expands)
-        beforequery: function(qe){
-            delete qe.combo.lastQuery;
-        }
-    }
-});
-     * </code></pre>
-     * To make sure the filter in the store is not cleared the first time the ComboBox trigger is used
-     * configure the combo with <code>lastQuery=''</code>. Example use:
-     * <pre><code>
-var combo = new Ext.form.field.ComboBox({
-    ...
-    queryMode: 'local',
-    triggerAction: 'all',
-    lastQuery: ''
-});
-     * </code></pre>
-     * @property lastQuery
-     * @type String
+     * @property {String} lastQuery
+     * The value of the match string used to filter the store. Delete this property to force a requery. Example use:
+     *
+     *     var combo = new Ext.form.field.ComboBox({
+     *         ...
+     *         queryMode: 'remote',
+     *         listeners: {
+     *             // delete the previous query in the beforequery event or set
+     *             // combo.lastQuery = null (this will reload the store the next time it expands)
+     *             beforequery: function(qe){
+     *                 delete qe.combo.lastQuery;
+     *             }
+     *         }
+     *     });
+     *
+     * To make sure the filter in the store is not cleared the first time the ComboBox trigger is used configure the
+     * combo with `lastQuery=''`. Example use:
+     *
+     *     var combo = new Ext.form.field.ComboBox({
+     *         ...
+     *         queryMode: 'local',
+     *         triggerAction: 'all',
+     *         lastQuery: ''
+     *     });
      */
 
     /**
@@ -80863,31 +84362,28 @@ var combo = new Ext.form.field.ComboBox({
     },
 
     /**
-     * @cfg {Mixed} transform
-     * The id, DOM node or {@link Ext.core.Element} of an existing HTML <code>&lt;select&gt;</code> element to
-     * convert into a ComboBox. The target select's options will be used to build the options in the ComboBox
-     * dropdown; a configured {@link #store} will take precedence over this.
+     * @cfg {String/HTMLElement/Ext.Element} transform
+     * The id, DOM node or {@link Ext.Element} of an existing HTML `<select>` element to convert into a ComboBox. The
+     * target select's options will be used to build the options in the ComboBox dropdown; a configured {@link #store}
+     * will take precedence over this.
      */
 
     /**
      * @cfg {Object} listConfig
-     * <p>An optional set of configuration properties that will be passed to the {@link Ext.view.BoundList}'s
-     * constructor. Any configuration that is valid for BoundList can be included. Some of the more useful
-     * ones are:</p>
-     * <ul>
-     *     <li>{@link Ext.view.BoundList#cls} - defaults to empty</li>
-     *     <li>{@link Ext.view.BoundList#emptyText} - defaults to empty string</li>
-     *     <li>{@link Ext.view.BoundList#getInnerTpl} - defaults to the template defined in BoundList</li>
-     *     <li>{@link Ext.view.BoundList#itemSelector} - defaults to the value defined in BoundList</li>
-     *     <li>{@link Ext.view.BoundList#loadingText} - defaults to <code>'Loading...'</code></li>
-     *     <li>{@link Ext.view.BoundList#minWidth} - defaults to <code>70</code></li>
-     *     <li>{@link Ext.view.BoundList#maxWidth} - defaults to <code>undefined</code></li>
-     *     <li>{@link Ext.view.BoundList#maxHeight} - defaults to <code>300</code></li>
-     *     <li>{@link Ext.view.BoundList#resizable} - defaults to <code>false</code></li>
-     *     <li>{@link Ext.view.BoundList#shadow} - defaults to <code>'sides'</code></li>
-     *     <li>{@link Ext.view.BoundList#width} - defaults to <code>undefined</code> (automatically set to the width
-     *         of the ComboBox field if {@link #matchFieldWidth} is true)</li>
-     * </ul>
+     * An optional set of configuration properties that will be passed to the {@link Ext.view.BoundList}'s constructor.
+     * Any configuration that is valid for BoundList can be included. Some of the more useful ones are:
+     *
+     *   - {@link Ext.view.BoundList#cls} - defaults to empty
+     *   - {@link Ext.view.BoundList#emptyText} - defaults to empty string
+     *   - {@link Ext.view.BoundList#itemSelector} - defaults to the value defined in BoundList
+     *   - {@link Ext.view.BoundList#loadingText} - defaults to `'Loading...'`
+     *   - {@link Ext.view.BoundList#minWidth} - defaults to `70`
+     *   - {@link Ext.view.BoundList#maxWidth} - defaults to `undefined`
+     *   - {@link Ext.view.BoundList#maxHeight} - defaults to `300`
+     *   - {@link Ext.view.BoundList#resizable} - defaults to `false`
+     *   - {@link Ext.view.BoundList#shadow} - defaults to `'sides'`
+     *   - {@link Ext.view.BoundList#width} - defaults to `undefined` (automatically set to the width of the ComboBox
+     *     field if {@link #matchFieldWidth} is true)
      */
 
     //private
@@ -80900,10 +84396,11 @@ var combo = new Ext.form.field.ComboBox({
             transform = me.transform,
             transformSelect, isLocalMode;
 
+        Ext.applyIf(me.renderSelectors, {
+            hiddenDataEl: '.' + me.hiddenDataCls.split(' ').join('.')
+        });
+        
         //<debug>
-        if (!store && !transform) {
-            Ext.Error.raise('Either a valid store, or a HTML select to transform, must be configured on the combo.');
-        }
         if (me.typeAhead && me.multiSelect) {
             Ext.Error.raise('typeAhead and multiSelect are mutually exclusive options -- please remove one of them.');
         }
@@ -80916,32 +84413,60 @@ var combo = new Ext.form.field.ComboBox({
         //</debug>
 
         this.addEvents(
-            // TODO need beforeselect?
-
             /**
              * @event beforequery
-             * Fires before all queries are processed. Return false to cancel the query or set the queryEvent's
-             * cancel property to true.
-             * @param {Object} queryEvent An object that has these properties:<ul>
-             * <li><code>combo</code> : Ext.form.field.ComboBox <div class="sub-desc">This combo box</div></li>
-             * <li><code>query</code> : String <div class="sub-desc">The query string</div></li>
-             * <li><code>forceAll</code> : Boolean <div class="sub-desc">True to force "all" query</div></li>
-             * <li><code>cancel</code> : Boolean <div class="sub-desc">Set to true to cancel the query</div></li>
-             * </ul>
+             * Fires before all queries are processed. Return false to cancel the query or set the queryEvent's cancel
+             * property to true.
+             *
+             * @param {Object} queryEvent An object that has these properties:
+             *
+             *   - `combo` : Ext.form.field.ComboBox
+             *
+             *     This combo box
+             *
+             *   - `query` : String
+             *
+             *     The query string
+             *
+             *   - `forceAll` : Boolean
+             *
+             *     True to force "all" query
+             *
+             *   - `cancel` : Boolean
+             *
+             *     Set to true to cancel the query
              */
             'beforequery',
 
-            /*
+            /**
              * @event select
              * Fires when at least one list item is selected.
              * @param {Ext.form.field.ComboBox} combo This combo box
              * @param {Array} records The selected records
              */
-            'select'
+            'select',
+
+            /**
+             * @event beforeselect
+             * Fires before the selected item is added to the collection
+             * @param {Ext.form.field.ComboBox} combo This combo box
+             * @param {Ext.data.Record} record The selected record
+             * @param {Number} index The index of the selected record
+             */
+            'beforeselect',
+
+            /**
+             * @event beforedeselect
+             * Fires before the deselected item is removed from the collection
+             * @param {Ext.form.field.ComboBox} combo This combo box
+             * @param {Ext.data.Record} record The deselected record
+             * @param {Number} index The index of the deselected record
+             */
+            'beforedeselect'
         );
 
         // Build store from 'transform' HTML select element's options
-        if (!store && transform) {
+        if (transform) {
             transformSelect = Ext.getDom(transform);
             if (transformSelect) {
                 store = Ext.Array.map(Ext.Array.from(transformSelect.options), function(option) {
@@ -80956,7 +84481,7 @@ var combo = new Ext.form.field.ComboBox({
             }
         }
 
-        me.bindStore(store, true);
+        me.bindStore(store || 'ext-empty-store', true);
         store = me.store;
         if (store.autoCreated) {
             me.queryMode = 'local';
@@ -80982,7 +84507,7 @@ var combo = new Ext.form.field.ComboBox({
         if (!me.displayTpl) {
             me.displayTpl = Ext.create('Ext.XTemplate',
                 '<tpl for=".">' +
-                    '{[typeof values === "string" ? values : values.' + me.displayField + ']}' +
+                    '{[typeof values === "string" ? values : values["' + me.displayField + '"]]}' +
                     '<tpl if="xindex < xcount">' + me.delimiter + '</tpl>' +
                 '</tpl>'
             );
@@ -81007,14 +84532,17 @@ var combo = new Ext.form.field.ComboBox({
         }
     },
 
+    /**
+     * Returns the store associated with this ComboBox.
+     * @return {Ext.data.Store} The store
+     */
+    getStore : function(){
+        return this.store;
+    },
+
     beforeBlur: function() {
-        var me = this;
-        me.doQueryTask.cancel();
-        if (me.forceSelection) {
-            me.assertValue();
-        } else {
-            me.collapse();
-        }
+        this.doQueryTask.cancel();
+        this.assertValue();
     },
 
     // private
@@ -81023,20 +84551,22 @@ var combo = new Ext.form.field.ComboBox({
             value = me.getRawValue(),
             rec;
 
-        if (me.multiSelect) {
-            // For multiselect, check that the current displayed value matches the current
-            // selection, if it does not then revert to the most recent selection.
-            if (value !== me.getDisplayValue()) {
-                me.setValue(me.lastSelection);
-            }
-        } else {
-            // For single-select, match the displayed value to a record and select it,
-            // if it does not match a record then revert to the most recent selection.
-            rec = me.findRecordByDisplay(value);
-            if (rec) {
-                me.select(rec);
+        if (me.forceSelection) {
+            if (me.multiSelect) {
+                // For multiselect, check that the current displayed value matches the current
+                // selection, if it does not then revert to the most recent selection.
+                if (value !== me.getDisplayValue()) {
+                    me.setValue(me.lastSelection);
+                }
             } else {
-                me.setValue(me.lastSelection);
+                // For single-select, match the displayed value to a record and select it,
+                // if it does not match a record then revert to the most recent selection.
+                rec = me.findRecordByDisplay(value);
+                if (rec) {
+                    me.select(rec);
+                } else {
+                    me.setValue(me.lastSelection);
+                }
             }
         }
         me.collapse();
@@ -81077,7 +84607,7 @@ var combo = new Ext.form.field.ComboBox({
         // would create it when we may be preping to destroy it
         if (oldStore && !initial) {
             if (oldStore !== store && oldStore.autoDestroy) {
-                oldStore.destroy();
+                oldStore.destroyStore();
             } else {
                 oldStore.un({
                     scope: me,
@@ -81114,9 +84644,28 @@ var combo = new Ext.form.field.ComboBox({
         var me = this,
             value = me.value;
 
-        me.syncSelection();
-        if (me.picker && !me.picker.getSelectionModel().hasSelection()) {
-            me.doAutoSelect();
+        // If performing a remote query upon the raw value...
+        if (me.rawQuery) {
+            me.rawQuery = false;
+            me.syncSelection();
+            if (me.picker && !me.picker.getSelectionModel().hasSelection()) {
+                me.doAutoSelect();
+            }
+        }
+        // If store initial load or triggerAction: 'all' trigger click.
+        else {
+            // Set the value on load
+            if (me.value) {
+                me.setValue(me.value);
+            } else {
+                // There's no value.
+                // Highlight the first item in the list if autoSelect: true
+                if (me.store.getCount()) {
+                    me.doAutoSelect();
+                } else {
+                    me.setValue('');
+                }
+            }
         }
     },
 
@@ -81125,19 +84674,23 @@ var combo = new Ext.form.field.ComboBox({
      * Execute the query with the raw contents within the textfield.
      */
     doRawQuery: function() {
-        this.doQuery(this.getRawValue());
+        this.doQuery(this.getRawValue(), false, true);
     },
 
     /**
-     * Executes a query to filter the dropdown list. Fires the {@link #beforequery} event prior to performing the
-     * query allowing the query action to be canceled if needed.
+     * Executes a query to filter the dropdown list. Fires the {@link #beforequery} event prior to performing the query
+     * allowing the query action to be canceled if needed.
+     *
      * @param {String} queryString The SQL query to execute
-     * @param {Boolean} forceAll <code>true</code> to force the query to execute even if there are currently fewer
-     * characters in the field than the minimum specified by the <code>{@link #minChars}</code> config option.  It
-     * also clears any filter previously saved in the current store (defaults to <code>false</code>)
-     * @return {Boolean} true if the query was permitted to run, false if it was cancelled by a {@link #beforequery} handler.
-     */
-    doQuery: function(queryString, forceAll) {
+     * @param {Boolean} [forceAll=false] `true` to force the query to execute even if there are currently fewer characters in
+     * the field than the minimum specified by the `{@link #minChars}` config option. It also clears any filter
+     * previously saved in the current store.
+     * @param {Boolean} [rawQuery=false] Pass as true if the raw typed value is being used as the query string. This causes the
+     * resulting store load to leave the raw value undisturbed.
+     * @return {Boolean} true if the query was permitted to run, false if it was cancelled by a {@link #beforequery}
+     * handler.
+     */
+    doQuery: function(queryString, forceAll, rawQuery) {
         queryString = queryString || '';
 
         // store in object and pass by reference in 'beforequery'
@@ -81179,11 +84732,19 @@ var combo = new Ext.form.field.ComboBox({
                         store.filter(me.displayField, queryString);
                     }
                 } else {
+                    // Set flag for onLoad handling to know how the Store was loaded
+                    me.rawQuery = rawQuery;
+
                     // In queryMode: 'remote', we assume Store filters are added by the developer as remote filters,
                     // and these are automatically passed as params with every load call, so we do *not* call clearFilter.
-                    store.load({
-                        params: me.getParams(queryString)
-                    });
+                    if (me.pageSize) {
+                        // if we're paging, we've changed the query so start at page 1.
+                        me.loadPage(1);
+                    } else {
+                        store.load({
+                            params: me.getParams(queryString)
+                        });
+                    }
                 }
             }
 
@@ -81204,21 +84765,31 @@ var combo = new Ext.form.field.ComboBox({
         return true;
     },
 
+    loadPage: function(pageNum){
+        this.store.loadPage(pageNum, {
+            params: this.getParams(this.lastQuery)
+        });
+    },
+
+    onPageChange: function(toolbar, newPage){
+        /*
+         * Return false here so we can call load ourselves and inject the query param.
+         * We don't want to do this for every store load since the developer may load
+         * the store through some other means so we won't add the query param.
+         */
+        this.loadPage(newPage);
+        return false;
+    },
+
     // private
     getParams: function(queryString) {
-        var p = {},
-            pageSize = this.pageSize,
+        var params = {},
             param = this.queryParam;
 
         if (param) {
-            p[param] = queryString;
+            params[param] = queryString;
         }
-
-        if (pageSize) {
-            p.start = 0;
-            p.limit = pageSize;
-        }
-        return p;
+        return params;
     },
 
     /**
@@ -81259,7 +84830,7 @@ var combo = new Ext.form.field.ComboBox({
                 if (me.triggerAction === 'all') {
                     me.doQuery(me.allQuery, true);
                 } else {
-                    me.doQuery(me.getRawValue());
+                    me.doQuery(me.getRawValue(), false, true);
                 }
             }
             me.inputEl.focus();
@@ -81300,12 +84871,18 @@ var combo = new Ext.form.field.ComboBox({
             me.mon(me.inputEl, 'keyup', me.onKeyUp, me);
         }
     },
+    
+    onDestroy: function(){
+        this.bindStore(null);
+        this.callParent();    
+    },
 
     createPicker: function() {
         var me = this,
             picker,
             menuCls = Ext.baseCSSPrefix + 'menu',
             opts = Ext.apply({
+                pickerField: me,
                 selModel: {
                     mode: me.multiSelect ? 'SIMPLE' : 'SINGLE'
                 },
@@ -81321,6 +84898,9 @@ var combo = new Ext.form.field.ComboBox({
             }, me.listConfig, me.defaultListConfig);
 
         picker = me.picker = Ext.create('Ext.view.BoundList', opts);
+        if (me.pageSize) {
+            picker.pagingToolbar.on('beforechange', me.onPageChange, me);
+        }
 
         me.mon(picker, {
             itemclick: me.onItemClick,
@@ -81328,11 +84908,30 @@ var combo = new Ext.form.field.ComboBox({
             scope: me
         });
 
-        me.mon(picker.getSelectionModel(), 'selectionchange', me.onListSelectionChange, 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.picker,
+            heightAbove = me.getPosition()[1] - Ext.getBody().getScroll().top,
+            heightBelow = Ext.Element.getViewHeight() - heightAbove - me.getHeight(),
+            space = Math.max(heightAbove, heightBelow);
+
+        me.callParent();
+        if (picker.getHeight() > space) {
+            picker.setHeight(space - 5); // have some leeway so we aren't flush against
+            me.doAlign();
+        }
+    },
+
     onListRefresh: function() {
         this.alignPicker();
         this.syncSelection();
@@ -81351,11 +84950,22 @@ var combo = new Ext.form.field.ComboBox({
         if (!me.multiSelect && lastSelection) {
             selected = lastSelection[0];
             if (selected && (record.get(valueField) === selected.get(valueField))) {
+                // Make sure we also update the display value if it's only partial
+                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,
@@ -81433,25 +85043,38 @@ var combo = new Ext.form.field.ComboBox({
 
     /**
      * Selects an item by a {@link Ext.data.Model Model}, or by a key value.
-     * @param r
+     * @param {Object} r
      */
     select: function(r) {
         this.setValue(r, true);
     },
 
     /**
-     * Find the record by searching for a specific field/value combination
-     * Returns an Ext.data.Record or false
-     * @private
+     * Finds the record by searching for a specific field/value combination.
+     * @param {String} field The name of the field to test.
+     * @param {Object} value The value to match the field against.
+     * @return {Ext.data.Model} The matched record or false.
      */
     findRecord: function(field, value) {
         var ds = this.store,
             idx = ds.findExact(field, value);
         return idx !== -1 ? ds.getAt(idx) : false;
     },
+
+    /**
+     * Finds the record by searching values in the {@link #valueField}.
+     * @param {Object} value The value to match the field against.
+     * @return {Ext.data.Model} The matched record or false.
+     */
     findRecordByValue: function(value) {
         return this.findRecord(this.valueField, value);
     },
+
+    /**
+     * Finds the record by searching values in the {@link #displayField}.
+     * @param {Object} value The value to match the field against.
+     * @return {Ext.data.Model} The matched record or false.
+     */
     findRecordByDisplay: function(value) {
         return this.findRecord(this.displayField, value);
     },
@@ -81459,9 +85082,9 @@ var combo = new Ext.form.field.ComboBox({
     /**
      * Sets the specified value(s) into the field. For each value, if a record is found in the {@link #store} that
      * matches based on the {@link #valueField}, then that record's {@link #displayField} will be displayed in the
-     * field.  If no match is found, and the {@link #valueNotFoundText} config option is defined, then that will be
+     * field. If no match is found, and the {@link #valueNotFoundText} config option is defined, then that will be
      * displayed as the default field text. Otherwise a blank value will be shown, although the value will still be set.
-     * @param {String|Array} value The value(s) to be set. Can be either a single String or {@link Ext.data.Model},
+     * @param {String/String[]} value The value(s) to be set. Can be either a single String or {@link Ext.data.Model},
      * or an Array of Strings or Models.
      * @return {Ext.form.field.Field} this
      */
@@ -81477,6 +85100,7 @@ var combo = new Ext.form.field.ComboBox({
         if (me.store.loading) {
             // Called while the Store is loading. Ensure it is processed by the onLoad method.
             me.value = value;
+            me.setHiddenValue(me.value);
             return me;
         }
 
@@ -81498,15 +85122,20 @@ var combo = new Ext.form.field.ComboBox({
             // record was not found, this could happen because
             // store is not loaded or they set a value not in the store
             else {
-                // if valueNotFoundText is defined, display it, otherwise display nothing for this value
-                if (Ext.isDefined(valueNotFoundText)) {
+                // If we are allowing insertion of values not represented in the Store, then set the value, and the display value
+                if (!me.forceSelection) {
+                    displayTplData.push(value[i]);
+                    processedValue.push(value[i]);
+                }
+                // Else, if valueNotFoundText is defined, display it, otherwise display nothing for this value
+                else if (Ext.isDefined(valueNotFoundText)) {
                     displayTplData.push(valueNotFoundText);
                 }
-                processedValue.push(value[i]);
             }
         }
 
         // Set the value of this field. If we are multiselecting, then that is an array.
+        me.setHiddenValue(processedValue);
         me.value = me.multiSelect ? processedValue : processedValue[0];
         if (!Ext.isDefined(me.value)) {
             me.value = null;
@@ -81531,7 +85160,42 @@ var combo = new Ext.form.field.ComboBox({
     },
 
     /**
-     * @private Generate the string value to be displayed in the text field for the currently stored value
+     * @private
+     * Set the value of {@link #hiddenDataEl}
+     * Dynamically adds and removes input[type=hidden] elements
+     */
+    setHiddenValue: function(values){
+        var me = this, i;
+        if (!me.hiddenDataEl) {
+            return;
+        }
+        values = Ext.Array.from(values);
+        var 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:me.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];
+        }
+    },
+
+    /**
+     * @private Generates the string value to be displayed in the text field for the currently stored value
      */
     getDisplayValue: function() {
         return this.displayTpl.apply(this.displayTplData);
@@ -81621,11 +85285,8 @@ var combo = new Ext.form.field.ComboBox({
 });
 
 /**
- * @private
- * @class Ext.picker.Month
- * @extends Ext.Component
- * <p>A month picker component. This class is used by the {@link Ext.picker.Date DatePicker} class
- * to allow browsing and selection of year/months combinations.</p>
+ * A month picker component. This class is used by the {@link Ext.picker.Date Date picker} class
+ * to allow browsing and selection of year/months combinations.
  */
 Ext.define('Ext.picker.Month', {
     extend: 'Ext.Component',
@@ -81634,7 +85295,7 @@ Ext.define('Ext.picker.Month', {
     alternateClassName: 'Ext.MonthPicker',
 
     renderTpl: [
-        '<div class="{baseCls}-body">',
+        '<div id="{id}-bodyEl" class="{baseCls}-body">',
           '<div class="{baseCls}-months">',
               '<tpl for="months">',
                   '<div class="{parent.baseCls}-item {parent.baseCls}-month"><a href="#" hidefocus="on">{.}</a></div>',
@@ -81642,27 +85303,27 @@ Ext.define('Ext.picker.Month', {
           '</div>',
           '<div class="{baseCls}-years">',
               '<div class="{baseCls}-yearnav">',
-                  '<button class="{baseCls}-yearnav-prev"></button>',
-                  '<button class="{baseCls}-yearnav-next"></button>',
+                  '<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>',
-        '<div class="' + Ext.baseCSSPrefix + 'clear"></div>',
         '<tpl if="showButtons">',
-          '<div class="{baseCls}-buttons"></div>',
+          '<div id="{id}-buttonsEl" class="{baseCls}-buttons"></div>',
         '</tpl>'
     ],
 
     /**
-     * @cfg {String} okText The text to display on the ok button. Defaults to <tt>'OK'</tt>
+     * @cfg {String} okText The text to display on the ok button.
      */
     okText: 'OK',
 
     /**
-     * @cfg {String} cancelText The text to display on the cancel button. Defaults to <tt>'Cancel'</tt>
+     * @cfg {String} cancelText The text to display on the cancel button.
      */
     cancelText: 'Cancel',
 
@@ -81672,7 +85333,7 @@ Ext.define('Ext.picker.Month', {
     baseCls: Ext.baseCSSPrefix + 'monthpicker',
 
     /**
-     * @cfg {Boolean} showButtons True to show ok and cancel buttons below the picker. Defaults to <tt>true</tt>.
+     * @cfg {Boolean} showButtons True to show ok and cancel buttons below the picker.
      */
     showButtons: true,
 
@@ -81682,10 +85343,10 @@ Ext.define('Ext.picker.Month', {
      */
 
     /**
-     * @cfg {Date/Array} value The default value to set. See {#setValue setValue}
+     * @cfg {Date/Number[]} value The default value to set. See {@link #setValue}
      */
     width: 178,
-    
+
     // used when attached to date picker which isnt showing buttons
     smallCls: Ext.baseCSSPrefix + 'monthpicker-small',
 
@@ -81781,13 +85442,9 @@ Ext.define('Ext.picker.Month', {
             showButtons: me.showButtons
         });
 
-        Ext.apply(me.renderSelectors, {
-            bodyEl: '.' + me.baseCls + '-body',
-            prevEl: '.' + me.baseCls + '-yearnav-prev',
-            nextEl: '.' + me.baseCls + '-yearnav-next',
-            buttonsEl: '.' + me.baseCls + '-buttons'
-        });
-        this.callParent([ct, position]);
+        me.addChildEls('bodyEl', 'prevEl', 'nextEl', 'buttonsEl');
+
+        me.callParent(arguments);
     },
 
     // private, inherit docs
@@ -81834,7 +85491,7 @@ Ext.define('Ext.picker.Month', {
 
     /**
      * Set the value for the picker.
-     * @param {Date/Array} value The value to set. It can be a Date object, where the month/year will be extracted, or
+     * @param {Date/Number[]} value The value to set. It can be a Date object, where the month/year will be extracted, or
      * it can be an array, with the month as the first index and the year as the second.
      * @return {Ext.picker.Month} this
      */
@@ -81870,7 +85527,7 @@ Ext.define('Ext.picker.Month', {
      * Gets the selected value. It is returned as an array [month, year]. It may
      * be a partial value, for example [null, 2010]. The month is returned as
      * 0 based.
-     * @return {Array} The selected value
+     * @return {Number[]} The selected value
      */
     getValue: function(){
         return this.value;
@@ -81889,7 +85546,7 @@ Ext.define('Ext.picker.Month', {
      * Get an array of years to be pushed in the template. It is not in strict
      * numerical order because we want to show them in columns.
      * @private
-     * @return {Array} An array of years
+     * @return {Number[]} An array of years
      */
     getYears: function(){
         var me = this,
@@ -81974,7 +85631,7 @@ Ext.define('Ext.picker.Month', {
 
     /**
      * Modify the year display by passing an offset.
-     * @param {Number} offset The offset to move by. If not specified, it defaults to 10.
+     * @param {Number} [offset=10] The offset to move by.
      */
     adjustYear: function(offset){
         if (typeof offset != 'number') {
@@ -82049,38 +85706,37 @@ Ext.define('Ext.picker.Month', {
     beforeDestroy: function(){
         var me = this;
         me.years = me.months = null;
-        Ext.destroyMembers('backRepeater', 'nextRepeater', 'okBtn', 'cancelBtn');
-        this.callParent();
+        Ext.destroyMembers(me, 'backRepeater', 'nextRepeater', 'okBtn', 'cancelBtn');
+        me.callParent();
     }
 });
 
 /**
- * @class Ext.picker.Date
- * @extends Ext.Component
- * <p>A date picker. This class is used by the {@link Ext.form.field.Date} field to allow browsing and
- * selection of valid dates in a popup next to the field, but may also be used with other components.</p>
- * <p>Typically you will need to implement a handler function to be notified when the user chooses a color from the
- * picker; you can register the handler using the {@link #select} event, or by implementing the {@link #handler}
- * method.</p>
- * <p>By default the user will be allowed to pick any date; this can be changed by using the {@link #minDate},
- * {@link #maxDate}, {@link #disabledDays}, {@link #disabledDatesRE}, and/or {@link #disabledDates} configs.</p>
- * <p>All the string values documented below may be overridden by including an Ext locale file in your page.</p>
- * <p>Example usage:</p>
- * <pre><code>new Ext.panel.Panel({
-    title: 'Choose a future date:',
-    width: 200,
-    bodyPadding: 10,
-    renderTo: Ext.getBody(),
-    items: [{
-        xtype: 'datepicker',
-        minDate: new Date(),
-        handler: function(picker, date) {
-            // do something with the selected date
-        }
-    }]
-});</code></pre>
- * {@img Ext.picker.Date/Ext.picker.Date.png Ext.picker.Date component}
+ * A date picker. This class is used by the Ext.form.field.Date field to allow browsing and selection of valid
+ * dates in a popup next to the field, but may also be used with other components.
+ *
+ * Typically you will need to implement a handler function to be notified when the user chooses a date from the picker;
+ * you can register the handler using the {@link #select} event, or by implementing the {@link #handler} method.
+ *
+ * By default the user will be allowed to pick any date; this can be changed by using the {@link #minDate},
+ * {@link #maxDate}, {@link #disabledDays}, {@link #disabledDatesRE}, and/or {@link #disabledDates} configs.
  *
+ * All the string values documented below may be overridden by including an Ext locale file in your page.
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Choose a future date:',
+ *         width: 200,
+ *         bodyPadding: 10,
+ *         renderTo: Ext.getBody(),
+ *         items: [{
+ *             xtype: 'datepicker',
+ *             minDate: new Date(),
+ *             handler: function(picker, date) {
+ *                 // do something with the selected date
+ *             }
+ *         }]
+ *     });
  */
 Ext.define('Ext.picker.Date', {
     extend: 'Ext.Component',
@@ -82100,11 +85756,11 @@ Ext.define('Ext.picker.Date', {
     renderTpl: [
         '<div class="{cls}" id="{id}" role="grid" title="{ariaTitle} {value:this.longDay}">',
             '<div role="presentation" class="{baseCls}-header">',
-                '<div class="{baseCls}-prev"><a href="#" role="button" title="{prevText}"></a></div>',
-                '<div class="{baseCls}-month"></div>',
-                '<div class="{baseCls}-next"><a href="#" role="button" title="{nextText}"></a></div>',
+                '<div class="{baseCls}-prev"><a id="{id}-prevEl" href="#" role="button" title="{prevText}"></a></div>',
+                '<div class="{baseCls}-month" id="{id}-middleBtnEl"></div>',
+                '<div class="{baseCls}-next"><a id="{id}-nextEl" href="#" role="button" title="{nextText}"></a></div>',
             '</div>',
-            '<table class="{baseCls}-inner" cellspacing="0" role="presentation">',
+            '<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>',
@@ -82122,7 +85778,7 @@ Ext.define('Ext.picker.Date', {
                 '</tr></tbody>',
             '</table>',
             '<tpl if="showToday">',
-                '<div role="presentation" class="{baseCls}-footer"></div>',
+                '<div id="{id}-footerEl" role="presentation" class="{baseCls}-footer"></div>',
             '</tpl>',
         '</div>',
         {
@@ -82143,160 +85799,187 @@ Ext.define('Ext.picker.Date', {
     ],
 
     ariaTitle: 'Date Picker',
+
     /**
      * @cfg {String} todayText
-     * The text to display on the button that selects the current date (defaults to <code>'Today'</code>)
+     * The text to display on the button that selects the current date
      */
     todayText : 'Today',
+
     /**
      * @cfg {Function} handler
-     * Optional. A function that will handle the select event of this picker.
-     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
-     * <li><code>picker</code> : Ext.picker.Date <div class="sub-desc">This Date picker.</div></li>
-     * <li><code>date</code> : Date <div class="sub-desc">The selected date.</div></li>
-     * </ul></div>
+     * Optional. A function that will handle the select event of this picker. The handler is passed the following
+     * parameters:
+     *
+     *   - `picker` : Ext.picker.Date
+     *
+     * This Date picker.
+     *
+     *   - `date` : Date
+     *
+     * The selected date.
      */
+
     /**
      * @cfg {Object} scope
-     * The scope (<code><b>this</b></code> reference) in which the <code>{@link #handler}</code>
-     * function will be called.  Defaults to this DatePicker instance.
+     * The scope (`this` reference) in which the `{@link #handler}` function will be called. Defaults to this
+     * DatePicker instance.
      */
+
     /**
      * @cfg {String} todayTip
-     * A string used to format the message for displaying in a tooltip over the button that
-     * selects the current date. Defaults to <code>'{0} (Spacebar)'</code> where
-     * the <code>{0}</code> token is replaced by today's date.
+     * A string used to format the message for displaying in a tooltip over the button that selects the current date.
+     * The `{0}` token in string is replaced by today's date.
      */
     todayTip : '{0} (Spacebar)',
+
     /**
      * @cfg {String} minText
-     * The error text to display if the minDate validation fails (defaults to <code>'This date is before the minimum date'</code>)
+     * The error text to display if the minDate validation fails.
      */
     minText : 'This date is before the minimum date',
+
     /**
      * @cfg {String} maxText
-     * The error text to display if the maxDate validation fails (defaults to <code>'This date is after the maximum date'</code>)
+     * The error text to display if the maxDate validation fails.
      */
     maxText : 'This date is after the maximum date',
+
     /**
      * @cfg {String} format
-     * The default date format string which can be overriden for localization support.  The format must be
-     * valid according to {@link Ext.Date#parse} (defaults to {@link Ext.Date#defaultFormat}).
+     * The default date format string which can be overriden for localization support. The format must be valid
+     * according to {@link Ext.Date#parse} (defaults to {@link Ext.Date#defaultFormat}).
      */
+
     /**
      * @cfg {String} disabledDaysText
-     * The tooltip to display when the date falls on a disabled day (defaults to <code>'Disabled'</code>)
+     * The tooltip to display when the date falls on a disabled day.
      */
     disabledDaysText : 'Disabled',
+
     /**
      * @cfg {String} disabledDatesText
-     * The tooltip text to display when the date falls on a disabled date (defaults to <code>'Disabled'</code>)
+     * The tooltip text to display when the date falls on a disabled date.
      */
     disabledDatesText : 'Disabled',
+
     /**
-     * @cfg {Array} monthNames
+     * @cfg {String[]} monthNames
      * An array of textual month names which can be overriden for localization support (defaults to Ext.Date.monthNames)
      */
+
     /**
-     * @cfg {Array} dayNames
+     * @cfg {String[]} dayNames
      * An array of textual day names which can be overriden for localization support (defaults to Ext.Date.dayNames)
      */
+
     /**
      * @cfg {String} nextText
-     * The next month navigation button tooltip (defaults to <code>'Next Month (Control+Right)'</code>)
+     * The next month navigation button tooltip
      */
     nextText : 'Next Month (Control+Right)',
+
     /**
      * @cfg {String} prevText
-     * The previous month navigation button tooltip (defaults to <code>'Previous Month (Control+Left)'</code>)
+     * The previous month navigation button tooltip
      */
     prevText : 'Previous Month (Control+Left)',
+
     /**
      * @cfg {String} monthYearText
-     * The header month selector tooltip (defaults to <code>'Choose a month (Control+Up/Down to move years)'</code>)
+     * The header month selector tooltip
      */
     monthYearText : 'Choose a month (Control+Up/Down to move years)',
+
     /**
      * @cfg {Number} startDay
-     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
+     * Day index at which the week should begin, 0-based (defaults to Sunday)
      */
     startDay : 0,
+
     /**
      * @cfg {Boolean} showToday
-     * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar
-     * that selects the current date (defaults to <code>true</code>).
+     * False to hide the footer area containing the Today button and disable the keyboard handler for spacebar that
+     * selects the current date.
      */
     showToday : true,
+
     /**
-     * @cfg {Date} minDate
-     * Minimum allowable date (JavaScript date object, defaults to null)
+     * @cfg {Date} [minDate=null]
+     * Minimum allowable date (JavaScript date object)
      */
+
     /**
-     * @cfg {Date} maxDate
-     * Maximum allowable date (JavaScript date object, defaults to null)
+     * @cfg {Date} [maxDate=null]
+     * Maximum allowable date (JavaScript date object)
      */
+
     /**
-     * @cfg {Array} disabledDays
-     * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
+     * @cfg {Number[]} [disabledDays=null]
+     * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday.
      */
+
     /**
-     * @cfg {RegExp} disabledDatesRE
-     * JavaScript regular expression used to disable a pattern of dates (defaults to null).  The {@link #disabledDates}
+     * @cfg {RegExp} [disabledDatesRE=null]
+     * JavaScript regular expression used to disable a pattern of dates. The {@link #disabledDates}
      * config will generate this regex internally, but if you specify disabledDatesRE it will take precedence over the
      * disabledDates value.
      */
+
     /**
-     * @cfg {Array} disabledDates
-     * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular
-     * expression so they are very powerful. Some examples:
-     * <ul>
-     * <li>['03/08/2003', '09/16/2003'] would disable those exact dates</li>
-     * <li>['03/08', '09/16'] would disable those days for every year</li>
-     * <li>['^03/08'] would only match the beginning (useful if you are using short years)</li>
-     * <li>['03/../2006'] would disable every day in March 2006</li>
-     * <li>['^03'] would disable every day in every March</li>
-     * </ul>
-     * Note that the format of the dates included in the array should exactly match the {@link #format} config.
-     * In order to support regular expressions, if you are using a date format that has '.' in it, you will have to
-     * escape the dot when restricting dates. For example: ['03\\.08\\.03'].
+     * @cfg {String[]} disabledDates
+     * An array of 'dates' to disable, as strings. These strings will be used to build a dynamic regular expression so
+     * they are very powerful. Some examples:
+     *
+     *   - ['03/08/2003', '09/16/2003'] would disable those exact dates
+     *   - ['03/08', '09/16'] would disable those days for every year
+     *   - ['^03/08'] would only match the beginning (useful if you are using short years)
+     *   - ['03/../2006'] would disable every day in March 2006
+     *   - ['^03'] would disable every day in every March
+     *
+     * Note that the format of the dates included in the array should exactly match the {@link #format} config. In order
+     * to support regular expressions, if you are using a date format that has '.' in it, you will have to escape the
+     * dot when restricting dates. For example: ['03\\.08\\.03'].
      */
 
     /**
-     * @cfg {Boolean} disableAnim True to disable animations when showing the month picker. Defaults to <tt>false</tt>.
+     * @cfg {Boolean} disableAnim
+     * True to disable animations when showing the month picker.
      */
-    disableAnim: true,
+    disableAnim: false,
 
     /**
-     * @cfg {String} baseCls
-     * The base CSS class to apply to this components element (defaults to <tt>'x-datepicker'</tt>).
+     * @cfg {String} [baseCls='x-datepicker']
+     * The base CSS class to apply to this components element.
      */
     baseCls: Ext.baseCSSPrefix + 'datepicker',
 
     /**
-     * @cfg {String} selectedCls
-     * The class to apply to the selected cell. Defaults to <tt>'x-datepicker-selected'</tt>
+     * @cfg {String} [selectedCls='x-datepicker-selected']
+     * The class to apply to the selected cell.
      */
 
     /**
-     * @cfg {String} disabledCellCls
-     * The class to apply to disabled cells. Defaults to <tt>'x-datepicker-disabled'</tt>
+     * @cfg {String} [disabledCellCls='x-datepicker-disabled']
+     * The class to apply to disabled cells.
      */
 
     /**
      * @cfg {String} longDayFormat
-     * The format for displaying a date in a longer format. Defaults to <tt>'F d, Y'</tt>
+     * The format for displaying a date in a longer format.
      */
     longDayFormat: 'F d, Y',
 
     /**
-     * @cfg {Object} keyNavConfig Specifies optional custom key event handlers for the {@link Ext.util.KeyNav}
-     * attached to this date picker. Must conform to the config format recognized by the {@link Ext.util.KeyNav}
-     * constructor. Handlers specified in this object will replace default handlers of the same name.
+     * @cfg {Object} keyNavConfig
+     * Specifies optional custom key event handlers for the {@link Ext.util.KeyNav} attached to this date picker. Must
+     * conform to the config format recognized by the {@link Ext.util.KeyNav} constructor. Handlers specified in this
+     * object will replace default handlers of the same name.
      */
 
     /**
      * @cfg {Boolean} focusOnShow
-     * True to automatically focus the picker on show. Defaults to <tt>false</tt>.
+     * True to automatically focus the picker on show.
      */
     focusOnShow: false,
 
@@ -82333,7 +86016,7 @@ Ext.define('Ext.picker.Date', {
             /**
              * @event select
              * Fires when a date is selected
-             * @param {DatePicker} this DatePicker
+             * @param {Ext.picker.Date} this DatePicker
              * @param {Date} date The selected date
              */
             'select'
@@ -82355,8 +86038,7 @@ Ext.define('Ext.picker.Date', {
             today = Ext.Date.format(new Date(), me.format);
 
         Ext.applyIf(me, {
-            renderData: {},
-            renderSelectors: {}
+            renderData: {}
         });
 
         Ext.apply(me.renderData, {
@@ -82370,13 +86052,7 @@ Ext.define('Ext.picker.Date', {
         });
         me.getTpl('renderTpl').longDayFormat = me.longDayFormat;
 
-        Ext.apply(me.renderSelectors, {
-            eventEl: 'table.' + me.baseCls + '-inner',
-            prevEl: '.' + me.baseCls + '-prev a',
-            nextEl: '.' + me.baseCls + '-next a',
-            middleBtnEl: '.' + me.baseCls + '-month',
-            footerEl: '.' + me.baseCls + '-footer'
-        });
+        me.addChildEls('eventEl', 'prevEl', 'nextEl', 'middleBtnEl', 'footerEl');
 
         this.callParent(arguments);
         me.el.unselectable();
@@ -82499,8 +86175,8 @@ Ext.define('Ext.picker.Date', {
 
     /**
      * Replaces any existing disabled dates with new values and refreshes the DatePicker.
-     * @param {Array/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config
-     * for details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
+     * @param {String[]/RegExp} disabledDates An array of date strings (see the {@link #disabledDates} config for
+     * details on supported values), or a JavaScript regular expression used to disable a pattern of dates.
      * @return {Ext.picker.Date} this
      */
     setDisabledDates : function(dd){
@@ -82519,8 +86195,8 @@ Ext.define('Ext.picker.Date', {
 
     /**
      * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the DatePicker.
-     * @param {Array} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config
-     * for details on supported values.
+     * @param {Number[]} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config for details
+     * on supported values.
      * @return {Ext.picker.Date} this
      */
     setDisabledDays : function(dd){
@@ -82608,7 +86284,7 @@ Ext.define('Ext.picker.Date', {
      * @return {Date} The active date
      */
     getActive: function(){
-        return this.activeDate || me.value;
+        return this.activeDate || this.value;
     },
 
     /**
@@ -82617,33 +86293,41 @@ Ext.define('Ext.picker.Date', {
      * @param {Boolean} isHide True if it's a hide operation
      */
     runAnimation: function(isHide){
-        var options = {
-                target: this.monthPicker,
-                duration: 200
+        var picker = this.monthPicker,
+            options = {
+                duration: 200,
+                callback: function(){
+                    if (isHide) {
+                        picker.hide();
+                    } else {
+                        picker.show();
+                    }
+                }
             };
 
-        Ext.fx.Manager.run();
         if (isHide) {
-            //TODO: slideout
+            picker.el.slideOut('t', options);
         } else {
-            //TODO: slidein
+            picker.el.slideIn('t', options);
         }
-        Ext.create('Ext.fx.Anim', options);
     },
 
     /**
      * Hides the month picker, if it's visible.
+     * @param {Boolean} [animate] Indicates whether to animate this action. If the animate
+     * parameter is not specified, the behavior will use {@link #disableAnim} to determine
+     * whether to animate or not.
      * @return {Ext.picker.Date} this
      */
-    hideMonthPicker : function(){
+    hideMonthPicker : function(animate){
         var me = this,
             picker = me.monthPicker;
 
         if (picker) {
-            if (me.disableAnim) {
-                picker.hide();
+            if (me.shouldAnimate(animate)) {
+                me.runAnimation(true);
             } else {
-                this.runAnimation(true);
+                picker.hide();
             }
         }
         return me;
@@ -82651,32 +86335,38 @@ Ext.define('Ext.picker.Date', {
 
     /**
      * Show the month picker
+     * @param {Boolean} [animate] Indicates whether to animate this action. If the animate
+     * parameter is not specified, the behavior will use {@link #disableAnim} to determine
+     * whether to animate or not.
      * @return {Ext.picker.Date} this
      */
-    showMonthPicker : function(){
-
+    showMonthPicker : function(animate){
         var me = this,
-            picker,
-            size,
-            top,
-            left;
-
-
+            picker;
+        
         if (me.rendered && !me.disabled) {
-            size = me.getSize();
             picker = me.createMonthPicker();
-            picker.show();
-            picker.setSize(size);
             picker.setValue(me.getActive());
-
-            if (me.disableAnim) {
-                picker.setPosition(-1, -1);
-            } else {
+            picker.setSize(me.getSize());
+            picker.setPosition(-1, -1);
+            if (me.shouldAnimate(animate)) {
                 me.runAnimation(false);
+            } else {
+                picker.show();
             }
         }
         return me;
     },
+    
+    /**
+     * Checks whether a hide/show action should animate
+     * @private
+     * @param {Boolean} [animate] A possible animation value
+     * @return {Boolean} Whether to animate the action
+     */
+    shouldAnimate: function(animate){
+        return Ext.isDefined(animate) ? animate : !this.disableAnim;
+    },
 
     /**
      * Create the month picker instance
@@ -82701,8 +86391,11 @@ Ext.define('Ext.picker.Date', {
                     monthdblclick: me.onOkClick
                 }
             });
-
-            me.on('beforehide', me.hideMonthPicker, me);
+            if (!me.disableAnim) {
+                // hide the element if we're animating to prevent an initial flicker
+                picker.el.setStyle('display', 'none');
+            }
+            me.on('beforehide', Ext.Function.bind(me.hideMonthPicker, me, [false]));
         }
         return picker;
     },
@@ -82735,6 +86428,7 @@ Ext.define('Ext.picker.Date', {
 
     /**
      * Show the previous month.
+     * @param {Object} e
      * @return {Ext.picker.Date} this
      */
     showPrevMonth : function(e){
@@ -82743,6 +86437,7 @@ Ext.define('Ext.picker.Date', {
 
     /**
      * Show the next month.
+     * @param {Object} e
      * @return {Ext.picker.Date} this
      */
     showNextMonth : function(e){
@@ -83023,6 +86718,7 @@ Ext.define('Ext.picker.Date', {
             delete me.textNodes;
             delete me.cells.elements;
         }
+        me.callParent();
     },
 
     // private, inherit docs
@@ -83046,76 +86742,73 @@ function() {
 });
 
 /**
- * @class Ext.form.field.Date
- * @extends Ext.form.field.Picker
-
-Provides a date input field with a {@link Ext.picker.Date date picker} dropdown and automatic date
-validation.
-
-This field recognizes and uses the JavaScript Date object as its main {@link #value} type. In addition,
-it recognizes string values which are parsed according to the {@link #format} and/or {@link #altFormats}
-configs. These may be reconfigured to use date formats appropriate for the user's locale.
-
-The field may be limited to a certain range of dates by using the {@link #minValue}, {@link #maxValue},
-{@link #disabledDays}, and {@link #disabledDates} config parameters. These configurations will be used both
-in the field's validation, and in the date picker dropdown by preventing invalid dates from being selected.
-{@img Ext.form.Date/Ext.form.Date.png Ext.form.Date component}
-#Example usage:#
-
-    Ext.create('Ext.form.Panel', {
-        width: 300,
-        bodyPadding: 10,
-        title: 'Dates',
-        items: [{
-            xtype: 'datefield',
-            anchor: '100%',
-            fieldLabel: 'From',
-            name: 'from_date',
-            maxValue: new Date()  // limited to the current date or prior
-        }, {
-            xtype: 'datefield',
-            anchor: '100%',
-            fieldLabel: 'To',
-            name: 'to_date',
-            value: new Date()  // defaults to today
-        }],
-            renderTo: Ext.getBody()
-    });
-
-#Date Formats Examples#
-
-This example shows a couple of different date format parsing scenarios. Both use custom date format
-configurations; the first one matches the configured `format` while the second matches the `altFormats`.
-
-    Ext.create('Ext.form.Panel', {
-        renderTo: Ext.getBody(),
-        width: 300,
-        bodyPadding: 10,
-        title: 'Dates',
-        items: [{
-            xtype: 'datefield',
-            anchor: '100%',
-            fieldLabel: 'Date',
-            name: 'date',
-            // The value matches the format; will be parsed and displayed using that format.
-            format: 'm d Y',
-            value: '2 4 1978'
-        }, {
-            xtype: 'datefield',
-            anchor: '100%',
-            fieldLabel: 'Date',
-            name: 'date',
-            // The value does not match the format, but does match an altFormat; will be parsed
-            // using the altFormat and displayed using the format.
-            format: 'm d Y',
-            altFormats: 'm,d,Y|m.d.Y',
-            value: '2.4.1978'
-        }]
-    });
-
- * 
- * @markdown
  * @docauthor Jason Johnston <jason@sencha.com>
+ *
+ * Provides a date input field with a {@link Ext.picker.Date date picker} dropdown and automatic date
+ * validation.
+ *
+ * This field recognizes and uses the JavaScript Date object as its main {@link #value} type. In addition,
+ * it recognizes string values which are parsed according to the {@link #format} and/or {@link #altFormats}
+ * configs. These may be reconfigured to use date formats appropriate for the user's locale.
+ *
+ * The field may be limited to a certain range of dates by using the {@link #minValue}, {@link #maxValue},
+ * {@link #disabledDays}, and {@link #disabledDates} config parameters. These configurations will be used both
+ * in the field's validation, and in the date picker dropdown by preventing invalid dates from being selected.
+ *
+ * # Example usage
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         renderTo: Ext.getBody(),
+ *         width: 300,
+ *         bodyPadding: 10,
+ *         title: 'Dates',
+ *         items: [{
+ *             xtype: 'datefield',
+ *             anchor: '100%',
+ *             fieldLabel: 'From',
+ *             name: 'from_date',
+ *             maxValue: new Date()  // limited to the current date or prior
+ *         }, {
+ *             xtype: 'datefield',
+ *             anchor: '100%',
+ *             fieldLabel: 'To',
+ *             name: 'to_date',
+ *             value: new Date()  // defaults to today
+ *         }]
+ *     });
+ *
+ * # Date Formats Examples
+ *
+ * This example shows a couple of different date format parsing scenarios. Both use custom date format
+ * configurations; the first one matches the configured `format` while the second matches the `altFormats`.
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         renderTo: Ext.getBody(),
+ *         width: 300,
+ *         bodyPadding: 10,
+ *         title: 'Dates',
+ *         items: [{
+ *             xtype: 'datefield',
+ *             anchor: '100%',
+ *             fieldLabel: 'Date',
+ *             name: 'date',
+ *             // The value matches the format; will be parsed and displayed using that format.
+ *             format: 'm d Y',
+ *             value: '2 4 1978'
+ *         }, {
+ *             xtype: 'datefield',
+ *             anchor: '100%',
+ *             fieldLabel: 'Date',
+ *             name: 'date',
+ *             // The value does not match the format, but does match an altFormat; will be parsed
+ *             // using the altFormat and displayed using the format.
+ *             format: 'm d Y',
+ *             altFormats: 'm,d,Y|m.d.Y',
+ *             value: '2.4.1978'
+ *         }]
+ *     });
  */
 Ext.define('Ext.form.field.Date', {
     extend:'Ext.form.field.Picker',
@@ -83125,100 +86818,95 @@ Ext.define('Ext.form.field.Date', {
 
     /**
      * @cfg {String} format
-     * The default date format string which can be overriden for localization support.  The format must be
-     * valid according to {@link Ext.Date#parse} (defaults to <tt>'m/d/Y'</tt>).
+     * The default date format string which can be overriden for localization support. The format must be valid
+     * according to {@link Ext.Date#parse}.
      */
     format : "m/d/Y",
     /**
      * @cfg {String} altFormats
-     * Multiple date formats separated by "<tt>|</tt>" to try when parsing a user input value and it
-     * does not match the defined format (defaults to
-     * <tt>'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'</tt>).
+     * Multiple date formats separated by "|" to try when parsing a user input value and it does not match the defined
+     * format.
      */
     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",
     /**
      * @cfg {String} disabledDaysText
-     * The tooltip to display when the date falls on a disabled day (defaults to <tt>'Disabled'</tt>)
+     * The tooltip to display when the date falls on a disabled day.
      */
     disabledDaysText : "Disabled",
     /**
      * @cfg {String} disabledDatesText
-     * The tooltip text to display when the date falls on a disabled date (defaults to <tt>'Disabled'</tt>)
+     * The tooltip text to display when the date falls on a disabled date.
      */
     disabledDatesText : "Disabled",
     /**
      * @cfg {String} minText
-     * The error text to display when the date in the cell is before <tt>{@link #minValue}</tt> (defaults to
-     * <tt>'The date in this field must be after {minValue}'</tt>).
+     * The error text to display when the date in the cell is before {@link #minValue}.
      */
     minText : "The date in this field must be equal to or after {0}",
     /**
      * @cfg {String} maxText
-     * The error text to display when the date in the cell is after <tt>{@link #maxValue}</tt> (defaults to
-     * <tt>'The date in this field must be before {maxValue}'</tt>).
+     * The error text to display when the date in the cell is after {@link #maxValue}.
      */
     maxText : "The date in this field must be equal to or before {0}",
     /**
      * @cfg {String} invalidText
-     * The error text to display when the date in the field is invalid (defaults to
-     * <tt>'{value} is not a valid date - it must be in the format {format}'</tt>).
+     * The error text to display when the date in the field is invalid.
      */
     invalidText : "{0} is not a valid date - it must be in the format {1}",
     /**
-     * @cfg {String} triggerCls
-     * An additional CSS class used to style the trigger button.  The trigger will always get the
-     * class <tt>'x-form-trigger'</tt> and <tt>triggerCls</tt> will be <b>appended</b> if specified
-     * (defaults to <tt>'x-form-date-trigger'</tt> which displays a calendar icon).
+     * @cfg {String} [triggerCls='x-form-date-trigger']
+     * An additional CSS class used to style the trigger button. The trigger will always get the class 'x-form-trigger'
+     * and triggerCls will be **appended** if specified (default class displays a calendar icon).
      */
     triggerCls : Ext.baseCSSPrefix + 'form-date-trigger',
     /**
      * @cfg {Boolean} showToday
-     * <tt>false</tt> to hide the footer area of the Date picker containing the Today button and disable
-     * the keyboard handler for spacebar that selects the current date (defaults to <tt>true</tt>).
+     * false to hide the footer area of the Date picker containing the Today button and disable the keyboard handler for
+     * spacebar that selects the current date.
      */
     showToday : true,
     /**
      * @cfg {Date/String} minValue
-     * The minimum allowed date. Can be either a Javascript date object or a string date in a
-     * valid format (defaults to undefined).
+     * The minimum allowed date. Can be either a Javascript date object or a string date in a valid format.
      */
     /**
      * @cfg {Date/String} maxValue
-     * The maximum allowed date. Can be either a Javascript date object or a string date in a
-     * valid format (defaults to undefined).
+     * The maximum allowed date. Can be either a Javascript date object or a string date in a valid format.
      */
     /**
-     * @cfg {Array} disabledDays
-     * An array of days to disable, 0 based (defaults to undefined). Some examples:<pre><code>
-// disable Sunday and Saturday:
-disabledDays:  [0, 6]
-// disable weekdays:
-disabledDays: [1,2,3,4,5]
-     * </code></pre>
+     * @cfg {Number[]} disabledDays
+     * An array of days to disable, 0 based. Some examples:
+     *
+     *     // disable Sunday and Saturday:
+     *     disabledDays:  [0, 6]
+     *     // disable weekdays:
+     *     disabledDays: [1,2,3,4,5]
      */
     /**
-     * @cfg {Array} disabledDates
-     * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
-     * expression so they are very powerful. Some examples:<pre><code>
-// disable these exact dates:
-disabledDates: ["03/08/2003", "09/16/2003"]
-// disable these days for every year:
-disabledDates: ["03/08", "09/16"]
-// only match the beginning (useful if you are using short years):
-disabledDates: ["^03/08"]
-// disable every day in March 2006:
-disabledDates: ["03/../2006"]
-// disable every day in every March:
-disabledDates: ["^03"]
-     * </code></pre>
-     * Note that the format of the dates included in the array should exactly match the {@link #format} config.
-     * In order to support regular expressions, if you are using a {@link #format date format} that has "." in
-     * it, you will have to escape the dot when restricting dates. For example: <tt>["03\\.08\\.03"]</tt>.
+     * @cfg {String[]} disabledDates
+     * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular expression so
+     * they are very powerful. Some examples:
+     *
+     *     // disable these exact dates:
+     *     disabledDates: ["03/08/2003", "09/16/2003"]
+     *     // disable these days for every year:
+     *     disabledDates: ["03/08", "09/16"]
+     *     // only match the beginning (useful if you are using short years):
+     *     disabledDates: ["^03/08"]
+     *     // disable every day in March 2006:
+     *     disabledDates: ["03/../2006"]
+     *     // disable every day in every March:
+     *     disabledDates: ["^03"]
+     *
+     * Note that the format of the dates included in the array should exactly match the {@link #format} config. In order
+     * to support regular expressions, if you are using a {@link #format date format} that has "." in it, you will have
+     * to escape the dot when restricting dates. For example: `["03\\.08\\.03"]`.
      */
-    
+
     /**
-     * @cfg {String} submitFormat The date format string which will be submitted to the server.  
-     * The format must be valid according to {@link Ext.Date#parse} (defaults to <tt>{@link #format}</tt>).
+     * @cfg {String} submitFormat
+     * The date format string which will be submitted to the server. The format must be valid according to {@link
+     * Ext.Date#parse} (defaults to {@link #format}).
      */
 
     // in the absence of a time value, a default value of 12 noon will be used
@@ -83230,10 +86918,10 @@ disabledDates: ["^03"]
     matchFieldWidth: false,
     /**
      * @cfg {Number} startDay
-     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
+     * Day index at which the week should begin, 0-based (defaults to Sunday)
      */
     startDay: 0,
-    
+
     initComponent : function(){
         var me = this,
             isString = Ext.isString,
@@ -83284,13 +86972,13 @@ disabledDates: ["^03"]
 
     /**
      * Replaces any existing disabled dates with new values and refreshes the Date picker.
-     * @param {Array} disabledDates An array of date strings (see the <tt>{@link #disabledDates}</tt> config
-     * for details on supported values) used to disable a pattern of dates.
+     * @param {String[]} disabledDates An array of date strings (see the {@link #disabledDates} config for details on
+     * supported values) used to disable a pattern of dates.
      */
     setDisabledDates : function(dd){
         var me = this,
             picker = me.picker;
-            
+
         me.disabledDates = dd;
         me.initDisabledDays();
         if (picker) {
@@ -83300,12 +86988,12 @@ disabledDates: ["^03"]
 
     /**
      * Replaces any existing disabled days (by index, 0-6) with new values and refreshes the Date picker.
-     * @param {Array} disabledDays An array of disabled day indexes. See the <tt>{@link #disabledDays}</tt>
-     * config for details on supported values.
+     * @param {Number[]} disabledDays An array of disabled day indexes. See the {@link #disabledDays} config for details on
+     * supported values.
      */
     setDisabledDays : function(dd){
         var picker = this.picker;
-            
+
         this.disabledDays = dd;
         if (picker) {
             picker.setDisabledDays(dd);
@@ -83313,14 +87001,14 @@ disabledDates: ["^03"]
     },
 
     /**
-     * Replaces any existing <tt>{@link #minValue}</tt> with the new value and refreshes the Date picker.
+     * Replaces any existing {@link #minValue} with the new value and refreshes the Date picker.
      * @param {Date} value The minimum date that can be selected
      */
     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));
@@ -83329,14 +87017,14 @@ disabledDates: ["^03"]
     },
 
     /**
-     * Replaces any existing <tt>{@link #maxValue}</tt> with the new value and refreshes the Date picker.
+     * Replaces any existing {@link #maxValue} with the new value and refreshes the Date picker.
      * @param {Date} value The maximum date that can be selected
      */
     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));
@@ -83345,13 +87033,12 @@ disabledDates: ["^03"]
     },
 
     /**
-     * Runs all of Date's validations and returns an array of any errors. Note that this first
-     * runs Text's validations, so the returned array is an amalgamation of all field errors.
-     * The additional validation checks are testing that the date format is valid, that the chosen
-     * date is within the min and max date constraints set, that the date chosen is not in the disabledDates
-     * regex and that the day chosed is not one of the disabledDays.
-     * @param {Mixed} value The value to get errors for (defaults to the current field value)
-     * @return {Array} All validation errors for this field
+     * Runs all of Date's validations and returns an array of any errors. Note that this first runs Text's validations,
+     * so the returned array is an amalgamation of all field errors. The additional validation checks are testing that
+     * the date format is valid, that the chosen date is within the min and max date constraints set, that the date
+     * chosen is not in the disabledDates regex and that the day chosed is not one of the disabledDays.
+     * @param {Object} [value] The value to get errors for (defaults to the current field value)
+     * @return {String[]} All validation errors for this field
      */
     getErrors: function(value) {
         var me = this,
@@ -83419,27 +87106,28 @@ disabledDates: ["^03"]
     },
 
     /**
-     * Sets the value of the date field.  You can pass a date object or any string that can be
-     * parsed into a valid date, using <tt>{@link #format}</tt> as the date format, according
-     * to the same rules as {@link Ext.Date#parse} (the default format used is <tt>"m/d/Y"</tt>).
-     * <br />Usage:
-     * <pre><code>
-//All of these calls set the same date value (May 4, 2006)
-
-//Pass a date object:
-var dt = new Date('5/4/2006');
-dateField.setValue(dt);
-
-//Pass a date string (default format):
-dateField.setValue('05/04/2006');
-
-//Pass a date string (custom format):
-dateField.format = 'Y-m-d';
-dateField.setValue('2006-05-04');
-</code></pre>
+     * @method setValue
+     * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid date,
+     * using {@link #format} as the date format, according to the same rules as {@link Ext.Date#parse} (the default
+     * format used is "m/d/Y").
+     *
+     * Usage:
+     *
+     *     //All of these calls set the same date value (May 4, 2006)
+     *
+     *     //Pass a date object:
+     *     var dt = new Date('5/4/2006');
+     *     dateField.setValue(dt);
+     *
+     *     //Pass a date string (default format):
+     *     dateField.setValue('05/04/2006');
+     *
+     *     //Pass a date string (custom format):
+     *     dateField.format = 'Y-m-d';
+     *     dateField.setValue('2006-05-04');
+     *
      * @param {String/Date} date The date or valid date string
      * @return {Ext.form.field.Date} this
-     * @method setValue
      */
 
     /**
@@ -83453,7 +87141,7 @@ dateField.setValue('2006-05-04');
             utilDate = Ext.Date,
             parsedDate,
             result = null;
-            
+
         if (utilDate.formatContainsHourInfo(format)) {
             // if parse format contains hour information, no DST adjustment is necessary
             result = utilDate.parse(value, format);
@@ -83466,14 +87154,13 @@ dateField.setValue('2006-05-04');
         }
         return result;
     },
-    
+
     // @private
     getSubmitValue: function() {
-        var me = this,
-            format = me.submitFormat || me.format,
-            value = me.getValue();
-            
-        return value ? Ext.Date.format(value, format) : null;
+        var format = this.submitFormat || this.format,
+            value = this.getValue();
+
+        return value ? Ext.Date.format(value, format) : '';
     },
 
     /**
@@ -83511,6 +87198,7 @@ dateField.setValue('2006-05-04');
             format = Ext.String.format;
 
         return Ext.create('Ext.picker.Date', {
+            pickerField: me,
             ownerCt: me.ownerCt,
             renderTo: document.body,
             floating: true,
@@ -83541,7 +87229,7 @@ dateField.setValue('2006-05-04');
 
     onSelect: function(m, d) {
         var me = this;
-        
+
         me.setValue(d);
         me.fireEvent('select', me, d);
         me.collapse();
@@ -83552,9 +87240,8 @@ dateField.setValue('2006-05-04');
      * Sets the Date picker's value to match the current field value when expanding.
      */
     onExpand: function() {
-        var me = this,
-            value = me.getValue();
-        me.picker.setValue(Ext.isDate(value) ? value : new Date());
+        var value = this.getValue();
+        this.picker.setValue(Ext.isDate(value) ? value : new Date());
     },
 
     /**
@@ -83570,24 +87257,27 @@ dateField.setValue('2006-05-04');
         var me = this,
             v = me.parseDate(me.getRawValue()),
             focusTask = me.focusTask;
-        
+
         if (focusTask) {
             focusTask.cancel();
         }
-        
+
         if (v) {
             me.setValue(v);
         }
     }
 
     /**
-     * @cfg {Boolean} grow @hide
+     * @hide
+     * @cfg {Boolean} grow
      */
     /**
-     * @cfg {Number} growMin @hide
+     * @hide
+     * @cfg {Number} growMin
      */
     /**
-     * @cfg {Number} growMax @hide
+     * @hide
+     * @cfg {Number} growMax
      */
     /**
      * @hide
@@ -83596,39 +87286,38 @@ dateField.setValue('2006-05-04');
 });
 
 /**
- * @class Ext.form.field.Display
- * @extends Ext.form.field.Base
- * <p>A display-only text field which is not validated and not submitted. This is useful for when you want
- * to display a value from a form's {@link Ext.form.Basic#load loaded data} but do not want to allow the
- * user to edit or submit that value. The value can be optionally {@link #htmlEncode HTML encoded} if it contains
- * HTML markup that you do not want to be rendered.</p>
- * <p>If you have more complex content, or need to include components within the displayed content, also
- * consider using a {@link Ext.form.FieldContainer} instead.</p>
- * {@img Ext.form.Display/Ext.form.Display.png Ext.form.Display component}
- * <p>Example:</p>
- * <pre><code>
-    Ext.create('Ext.form.Panel', {
-        width: 175,
-        height: 120,
-        bodyPadding: 10,
-        title: 'Final Score',
-        items: [{
-            xtype: 'displayfield',
-            fieldLabel: 'Home',
-            name: 'home_score',
-            value: '10'
-        }, {
-            xtype: 'displayfield',
-            fieldLabel: 'Visitor',
-            name: 'visitor_score',
-            value: '11'
-        }],
-        buttons: [{
-            text: 'Update',
-        }],
-        renderTo: Ext.getBody()
-    });
-</code></pre>
+ * A display-only text field which is not validated and not submitted. This is useful for when you want to display a
+ * value from a form's {@link Ext.form.Basic#load loaded data} but do not want to allow the user to edit or submit that
+ * value. The value can be optionally {@link #htmlEncode HTML encoded} if it contains HTML markup that you do not want
+ * to be rendered.
+ *
+ * If you have more complex content, or need to include components within the displayed content, also consider using a
+ * {@link Ext.form.FieldContainer} instead.
+ *
+ * Example:
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         renderTo: Ext.getBody(),
+ *         width: 175,
+ *         height: 120,
+ *         bodyPadding: 10,
+ *         title: 'Final Score',
+ *         items: [{
+ *             xtype: 'displayfield',
+ *             fieldLabel: 'Home',
+ *             name: 'home_score',
+ *             value: '10'
+ *         }, {
+ *             xtype: 'displayfield',
+ *             fieldLabel: 'Visitor',
+ *             name: 'visitor_score',
+ *             value: '11'
+ *         }],
+ *         buttons: [{
+ *             text: 'Update',
+ *         }]
+ *     });
  */
 Ext.define('Ext.form.field.Display', {
     extend:'Ext.form.field.Base',
@@ -83644,14 +87333,15 @@ Ext.define('Ext.form.field.Display', {
     ],
 
     /**
-     * @cfg {String} fieldCls The default CSS class for the field (defaults to <tt>"x-form-display-field"</tt>)
+     * @cfg {String} [fieldCls="x-form-display-field"]
+     * The default CSS class for the field.
      */
     fieldCls: Ext.baseCSSPrefix + 'form-display-field',
 
     /**
-     * @cfg {Boolean} htmlEncode <tt>false</tt> to skip HTML-encoding the text when rendering it (defaults to
-     * <tt>false</tt>). This might be useful if you want to include tags in the field's innerHTML rather than
-     * rendering them as string literals per the default logic.
+     * @cfg {Boolean} htmlEncode
+     * false to skip HTML-encoding the text when rendering it. This might be useful if you want to
+     * include tags in the field's innerHTML rather than rendering them as string literals per the default logic.
      */
     htmlEncode: false,
 
@@ -83715,57 +87405,57 @@ Ext.define('Ext.form.field.Display', {
 });
 
 /**
- * @class Ext.form.field.File
- * @extends Ext.form.field.Text
-
-A file upload field which has custom styling and allows control over the button text and other
-features of {@link Ext.form.field.Text text fields} like {@link Ext.form.field.Text#emptyText empty text}.
-It uses a hidden file input element behind the scenes to allow user selection of a file and to
-perform the actual upload during {@link Ext.form.Basic#submit form submit}.
-
-Because there is no secure cross-browser way to programmatically set the value of a file input,
-the standard Field `setValue` method is not implemented. The `{@link #getValue}` method will return
-a value that is browser-dependent; some have just the file name, some have a full path, some use
-a fake path.
-{@img Ext.form.File/Ext.form.File.png Ext.form.File component}
-#Example Usage:#
-
-    Ext.create('Ext.form.Panel', {
-        title: 'Upload a Photo',
-        width: 400,
-        bodyPadding: 10,
-        frame: true,
-        renderTo: Ext.getBody(),    
-        items: [{
-            xtype: 'filefield',
-            name: 'photo',
-            fieldLabel: 'Photo',
-            labelWidth: 50,
-            msgTarget: 'side',
-            allowBlank: false,
-            anchor: '100%',
-            buttonText: 'Select Photo...'
-        }],
-    
-        buttons: [{
-            text: 'Upload',
-            handler: function() {
-                var form = this.up('form').getForm();
-                if(form.isValid()){
-                    form.submit({
-                        url: 'photo-upload.php',
-                        waitMsg: 'Uploading your photo...',
-                        success: function(fp, o) {
-                            Ext.Msg.alert('Success', 'Your photo "' + o.result.file + '" has been uploaded.');
-                        }
-                    });
-                }
-            }
-        }]
-    });
-
- * @markdown
  * @docauthor Jason Johnston <jason@sencha.com>
+ *
+ * A file upload field which has custom styling and allows control over the button text and other
+ * features of {@link Ext.form.field.Text text fields} like {@link Ext.form.field.Text#emptyText empty text}.
+ * It uses a hidden file input element behind the scenes to allow user selection of a file and to
+ * perform the actual upload during {@link Ext.form.Basic#submit form submit}.
+ *
+ * Because there is no secure cross-browser way to programmatically set the value of a file input,
+ * the standard Field `setValue` method is not implemented. The `{@link #getValue}` method will return
+ * a value that is browser-dependent; some have just the file name, some have a full path, some use
+ * a fake path.
+ *
+ * **IMPORTANT:** File uploads are not performed using normal 'Ajax' techniques; see the description for
+ * {@link Ext.form.Basic#hasUpload} for details.
+ *
+ * # Example Usage
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title: 'Upload a Photo',
+ *         width: 400,
+ *         bodyPadding: 10,
+ *         frame: true,
+ *         renderTo: Ext.getBody(),
+ *         items: [{
+ *             xtype: 'filefield',
+ *             name: 'photo',
+ *             fieldLabel: 'Photo',
+ *             labelWidth: 50,
+ *             msgTarget: 'side',
+ *             allowBlank: false,
+ *             anchor: '100%',
+ *             buttonText: 'Select Photo...'
+ *         }],
+ *
+ *         buttons: [{
+ *             text: 'Upload',
+ *             handler: function() {
+ *                 var form = this.up('form').getForm();
+ *                 if(form.isValid()){
+ *                     form.submit({
+ *                         url: 'photo-upload.php',
+ *                         waitMsg: 'Uploading your photo...',
+ *                         success: function(fp, o) {
+ *                             Ext.Msg.alert('Success', 'Your photo "' + o.result.file + '" has been uploaded.');
+ *                         }
+ *                     });
+ *                 }
+ *             }
+ *         }]
+ *     });
  */
 Ext.define("Ext.form.field.File", {
     extend: 'Ext.form.field.Text',
@@ -83774,60 +87464,64 @@ Ext.define("Ext.form.field.File", {
     uses: ['Ext.button.Button', 'Ext.layout.component.field.File'],
 
     /**
-     * @cfg {String} buttonText The button text to display on the upload button (defaults to
-     * 'Browse...').  Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.text
-     * value will be used instead if available.
+     * @cfg {String} buttonText
+     * The button text to display on the upload button. Note that if you supply a value for
+     * {@link #buttonConfig}, the buttonConfig.text value will be used instead if available.
      */
     buttonText: 'Browse...',
 
     /**
-     * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
-     * text field (defaults to false).  If true, all inherited Text members will still be available.
+     * @cfg {Boolean} buttonOnly
+     * True to display the file upload field as a button with no visible text field. If true, all
+     * inherited Text members will still be available.
      */
     buttonOnly: false,
 
     /**
-     * @cfg {Number} buttonMargin The number of pixels of space reserved between the button and the text field
-     * (defaults to 3).  Note that this only applies if {@link #buttonOnly} = false.
+     * @cfg {Number} buttonMargin
+     * The number of pixels of space reserved between the button and the text field. Note that this only
+     * applies if {@link #buttonOnly} = false.
      */
     buttonMargin: 3,
 
     /**
-     * @cfg {Object} buttonConfig A standard {@link Ext.button.Button} config object.
+     * @cfg {Object} buttonConfig
+     * A standard {@link Ext.button.Button} config object.
      */
 
     /**
      * @event change
-     * Fires when the underlying file input field's value has changed from the user
-     * selecting a new file from the system file selection dialog.
+     * Fires when the underlying file input field's value has changed from the user selecting a new file from the system
+     * file selection dialog.
      * @param {Ext.ux.form.FileUploadField} this
      * @param {String} value The file value returned by the underlying file input field
      */
 
     /**
-     * @property fileInputEl
-     * @type {Ext.core.Element}
-     * A reference to the invisible file input element created for this upload field. Only
-     * populated after this component is rendered.
+     * @property {Ext.Element} fileInputEl
+     * A reference to the invisible file input element created for this upload field. Only populated after this
+     * component is rendered.
      */
 
     /**
-     * @property button
-     * @type {Ext.button.Button}
-     * A reference to the trigger Button component created for this upload field. Only
-     * populated after this component is rendered.
+     * @property {Ext.button.Button} button
+     * A reference to the trigger Button component created for this upload field. Only populated after this component is
+     * rendered.
      */
 
     /**
-     * @cfg {String} fieldBodyCls
+     * @cfg {String} [fieldBodyCls='x-form-file-wrap']
      * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
-     * Defaults to 'x-form-file-wrap' for file upload field.
      */
     fieldBodyCls: Ext.baseCSSPrefix + 'form-file-wrap',
 
+    /**
+     * @cfg {Boolean} readOnly
+     * Unlike with other form fields, the readOnly config defaults to true in File field.
+     */
+    readOnly: true,
 
     // private
-    readOnly: true,
     componentLayout: 'filefield',
 
     // private
@@ -83860,6 +87554,7 @@ Ext.define("Ext.form.field.File", {
     createButton: function() {
         var me = this;
         me.button = Ext.widget('button', Ext.apply({
+            ui: me.ui,
             renderTo: me.bodyEl,
             text: me.buttonText,
             cls: Ext.baseCSSPrefix + 'form-file-btn',
@@ -83900,9 +87595,13 @@ Ext.define("Ext.form.field.File", {
     setValue: Ext.emptyFn,
 
     reset : function(){
-        this.fileInputEl.remove();
-        this.createFileInput();
-        this.callParent();
+        var me = this;
+        if (me.rendered) {
+            me.fileInputEl.remove();
+            me.createFileInput();
+            me.inputEl.dom.value = '';
+        }
+        me.callParent();
     },
 
     onDisable: function(){
@@ -83948,42 +87647,46 @@ Ext.define("Ext.form.field.File", {
 });
 
 /**
- * @class Ext.form.field.Hidden
- * @extends Ext.form.field.Base
- * <p>A basic hidden field for storing hidden values in forms that need to be passed in the form submit.</p>
- * <p>This creates an actual input element with type="submit" in the DOM. While its label is
- * {@link #hideLabel not rendered} by default, it is still a real component and may be sized according to
- * its owner container's layout.</p>
- * <p>Because of this, in most cases it is more convenient and less problematic to simply
+ * A basic hidden field for storing hidden values in forms that need to be passed in the form submit.
+ *
+ * This creates an actual input element with type="submit" in the DOM. While its label is
+ * {@link #hideLabel not rendered} by default, it is still a real component and may be sized according
+ * to its owner container's layout.
+ *
+ * Because of this, in most cases it is more convenient and less problematic to simply
  * {@link Ext.form.action.Action#params pass hidden parameters} directly when
- * {@link Ext.form.Basic#submit submitting the form}.</p>
- * <p>Example:</p>
- * <pre><code>new Ext.form.Panel({
-    title: 'My Form',
-    items: [{
-        xtype: 'textfield',
-        fieldLabel: 'Text Field',
-        name: 'text_field',
-        value: 'value from text field'
-    }, {
-        xtype: 'hiddenfield',
-        name: 'hidden_field_1',
-        value: 'value from hidden field'
-    }],
-
-    buttons: [{
-        text: 'Submit',
-        handler: function() {
-            this.up('form').getForm().submit({
-                params: {
-                    hidden_field_2: 'value from submit call'
-                }
-            });
-        }
-    }]
-});</code></pre>
- * <p>Submitting the above form will result in three values sent to the server:
- * <code>text_field=value+from+text+field&hidden_field_1=value+from+hidden+field&<br>hidden_field_2=value+from+submit+call</code></p>
+ * {@link Ext.form.Basic#submit submitting the form}.
+ *
+ * Example:
+ *
+ *     new Ext.form.Panel({
+ *         title: 'My Form',
+ *         items: [{
+ *             xtype: 'textfield',
+ *             fieldLabel: 'Text Field',
+ *             name: 'text_field',
+ *             value: 'value from text field'
+ *         }, {
+ *             xtype: 'hiddenfield',
+ *             name: 'hidden_field_1',
+ *             value: 'value from hidden field'
+ *         }],
+ *
+ *         buttons: [{
+ *             text: 'Submit',
+ *             handler: function() {
+ *                 this.up('form').getForm().submit({
+ *                     params: {
+ *                         hidden_field_2: 'value from submit call'
+ *                     }
+ *                 });
+ *             }
+ *         }]
+ *     });
+ *
+ * Submitting the above form will result in three values sent to the server:
+ *
+ *     text_field=value+from+text+field&hidden;_field_1=value+from+hidden+field&hidden_field_2=value+from+submit+call
  *
  */
 Ext.define('Ext.form.field.Hidden', {
@@ -83999,6 +87702,14 @@ Ext.define('Ext.form.field.Hidden', {
         this.formItemCls += '-hidden';
         this.callParent();    
     },
+    
+    /**
+     * @private
+     * Override. Treat undefined and null values as equal to an empty string value.
+     */
+    isEqual: function(value1, value2) {
+        return this.isEqualAsString(value1, value2);
+    },
 
     // These are all private overrides
     initEvents: Ext.emptyFn,
@@ -84012,80 +87723,76 @@ Ext.define('Ext.form.field.Hidden', {
 });
 
 /**
- * @class Ext.picker.Color
- * @extends Ext.Component
- * <p>ColorPicker provides a simple color palette for choosing colors. The picker can be rendered to any container.
- * The available default to a standard 40-color palette; this can be customized with the {@link #colors} config.</p>
- * <p>Typically you will need to implement a handler function to be notified when the user chooses a color from the
- * picker; you can register the handler using the {@link #select} event, or by implementing the {@link #handler}
- * method.</p>
- * <p>Here's an example of typical usage:</p>
- * <pre><code>var cp = new Ext.picker.Color({
-    value: '993300',  // initial selected color
-    renderTo: 'my-div'
-});
-
-cp.on('select', function(picker, selColor){
-    // do something with selColor
-});
-</code></pre>
- * {@img Ext.picker.Color/Ext.picker.Color.png Ext.picker.Color component}
+ * Color picker provides a simple color palette for choosing colors. The picker can be rendered to any container. The
+ * available default to a standard 40-color palette; this can be customized with the {@link #colors} config.
+ *
+ * Typically you will need to implement a handler function to be notified when the user chooses a color from the picker;
+ * you can register the handler using the {@link #select} event, or by implementing the {@link #handler} method.
  *
+ *     @example
+ *     Ext.create('Ext.picker.Color', {
+ *         value: '993300',  // initial selected color
+ *         renderTo: Ext.getBody(),
+ *         listeners: {
+ *             select: function(picker, selColor) {
+ *                 alert(selColor);
+ *             }
+ *         }
+ *     });
  */
 Ext.define('Ext.picker.Color', {
     extend: 'Ext.Component',
     requires: 'Ext.XTemplate',
     alias: 'widget.colorpicker',
     alternateClassName: 'Ext.ColorPalette',
-    
+
     /**
-     * @cfg {String} componentCls
-     * The CSS class to apply to the containing element (defaults to 'x-color-picker')
+     * @cfg {String} [componentCls='x-color-picker']
+     * The CSS class to apply to the containing element.
      */
     componentCls : Ext.baseCSSPrefix + 'color-picker',
-    
+
     /**
-     * @cfg {String} selectedCls
+     * @cfg {String} [selectedCls='x-color-picker-selected']
      * The CSS class to apply to the selected element
      */
     selectedCls: Ext.baseCSSPrefix + 'color-picker-selected',
-    
+
     /**
      * @cfg {String} value
-     * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
-     * the hex codes are case-sensitive.
+     * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that the hex
+     * codes are case-sensitive.
      */
     value : null,
-    
+
     /**
      * @cfg {String} clickEvent
      * The DOM event that will cause a color to be selected. This can be any valid event name (dblclick, contextmenu).
-     * Defaults to <tt>'click'</tt>.
      */
     clickEvent :'click',
 
     /**
-     * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the {@link #select} event
+     * @cfg {Boolean} allowReselect
+     * If set to true then reselecting a color that is already selected fires the {@link #select} event
      */
     allowReselect : false,
 
     /**
-     * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
-     * of colors, and each hex code should be unique.  The width of the picker is controlled via CSS by adjusting
-     * the width property of the 'x-color-picker' class (or assigning a custom class), so you can balance the number
-     * of colors with the width setting until the box is symmetrical.</p>
-     * <p>You can override individual colors if needed:</p>
-     * <pre><code>
-var cp = new Ext.picker.Color();
-cp.colors[0] = 'FF0000';  // change the first box to red
-</code></pre>
-
-Or you can provide a custom array of your own for complete control:
-<pre><code>
-var cp = new Ext.picker.Color();
-cp.colors = ['000000', '993300', '333300'];
-</code></pre>
-     * @type Array
+     * @property {String[]} colors
+     * An array of 6-digit color hex code strings (without the # symbol). This array can contain any number of colors,
+     * and each hex code should be unique. The width of the picker is controlled via CSS by adjusting the width property
+     * of the 'x-color-picker' class (or assigning a custom class), so you can balance the number of colors with the
+     * width setting until the box is symmetrical.
+     *
+     * You can override individual colors if needed:
+     *
+     *     var cp = new Ext.picker.Color();
+     *     cp.colors[0] = 'FF0000';  // change the first box to red
+     *
+     * Or you can provide a custom array of your own for complete control:
+     *
+     *     var cp = new Ext.picker.Color();
+     *     cp.colors = ['000000', '993300', '333300'];
      */
     colors : [
         '000000', '993300', '333300', '003300', '003366', '000080', '333399', '333333',
@@ -84097,30 +87804,38 @@ cp.colors = ['000000', '993300', '333300'];
 
     /**
      * @cfg {Function} handler
-     * Optional. A function that will handle the select event of this picker.
-     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
-     * <li><code>picker</code> : ColorPicker<div class="sub-desc">The {@link #picker Ext.picker.Color}.</div></li>
-     * <li><code>color</code> : String<div class="sub-desc">The 6-digit color hex code (without the # symbol).</div></li>
-     * </ul></div>
+     * A function that will handle the select event of this picker. The handler is passed the following parameters:
+     *
+     * - `picker` : ColorPicker
+     *
+     *   The {@link Ext.picker.Color picker}.
+     *
+     * - `color` : String
+     *
+     *   The 6-digit color hex code (without the # symbol).
      */
+
     /**
      * @cfg {Object} scope
-     * The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
-     * function will be called.  Defaults to this ColorPicker instance.
+     * The scope (`this` reference) in which the `{@link #handler}` function will be called. Defaults to this
+     * Color picker instance.
      */
-    
+
     colorRe: /(?:^|\s)color-(.{6})(?:\s|$)/,
     
-    constructor: function() {
-        this.renderTpl = Ext.create('Ext.XTemplate', '<tpl for="colors"><a href="#" class="color-{.}" hidefocus="on"><em><span style="background:#{.}" unselectable="on">&#160;</span></em></a></tpl>');
-        this.callParent(arguments);
-    },
-    
+    renderTpl: [
+        '<tpl for="colors">',
+            '<a href="#" class="color-{.}" hidefocus="on">',
+                '<em><span style="background:#{.}" unselectable="on">&#160;</span></em>',
+            '</a>',
+        '</tpl>'
+    ],
+
     // private
     initComponent : function(){
         var me = this;
-        
-        this.callParent(arguments);
+
+        me.callParent(arguments);
         me.addEvents(
             /**
              * @event select
@@ -84141,12 +87856,12 @@ cp.colors = ['000000', '993300', '333300'];
     onRender : function(container, position){
         var me = this,
             clickEvent = me.clickEvent;
-            
+
         Ext.apply(me.renderData, {
             itemCls: me.itemCls,
-            colors: me.colors    
+            colors: me.colors
         });
-        this.callParent(arguments);
+        me.callParent(arguments);
 
         me.mon(me.el, clickEvent, me.handleClick, me, {delegate: 'a'});
         // always stop following the anchors
@@ -84159,8 +87874,8 @@ cp.colors = ['000000', '993300', '333300'];
     afterRender : function(){
         var me = this,
             value;
-            
-        this.callParent(arguments);
+
+        me.callParent(arguments);
         if (me.value) {
             value = me.value;
             me.value = null;
@@ -84172,7 +87887,7 @@ cp.colors = ['000000', '993300', '333300'];
     handleClick : function(event, target){
         var me = this,
             color;
-            
+
         event.stopEvent();
         if (!me.disabled) {
             color = target.className.match(me.colorRe)[1];
@@ -84183,22 +87898,22 @@ cp.colors = ['000000', '993300', '333300'];
     /**
      * Selects the specified color in the picker (fires the {@link #select} event)
      * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
-     * @param {Boolean} suppressEvent (optional) True to stop the select event from firing. Defaults to <tt>false</tt>.
+     * @param {Boolean} suppressEvent (optional) True to stop the select event from firing. Defaults to false.
      */
     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;
 
@@ -84212,7 +87927,7 @@ cp.colors = ['000000', '993300', '333300'];
             }
         }
     },
-    
+
     /**
      * Get the currently selected color value.
      * @return {String} value The selected value. Null if nothing is selected.
@@ -84261,36 +87976,33 @@ Ext.define('Ext.layout.component.field.HtmlEditor', {
     }
 });
 /**
- * @class Ext.form.field.HtmlEditor
- * @extends Ext.Component
- *
  * Provides a lightweight HTML Editor component. Some toolbar features are not supported by Safari and will be
  * automatically hidden when needed. These are noted in the config options where appropriate.
- * 
+ *
  * The editor's toolbar buttons have tooltips defined in the {@link #buttonTips} property, but they are not
- * enabled by default unless the global {@link Ext.tip.QuickTipManager} singleton is {@link Ext.tip.QuickTipManager#init initialized}.
- * 
- * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
- * any element that has display set to 'none' can cause problems in Safari and Firefox due to their default iframe reloading bugs.
+ * enabled by default unless the global {@link Ext.tip.QuickTipManager} singleton is
+ * {@link Ext.tip.QuickTipManager#init initialized}.
  *
- * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor1.png Ext.form.HtmlEditor component}
+ * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an
+ * Editor within any element that has display set to 'none' can cause problems in Safari and Firefox due to their
+ * default iframe reloading bugs.
  *
- * ## Example usage
+ * # Example usage
  *
- * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor2.png Ext.form.HtmlEditor component}
+ * Simple example rendered with default options:
  *
- *     // Simple example rendered with default options:
- *     Ext.tip.QuickTips.init();  // enable tooltips
+ *     @example
+ *     Ext.tip.QuickTipManager.init();  // enable tooltips
  *     Ext.create('Ext.form.HtmlEditor', {
  *         width: 580,
  *         height: 250,
- *         renderTo: Ext.getBody()        
+ *         renderTo: Ext.getBody()
  *     });
- * 
- * {@img Ext.form.HtmlEditor/Ext.form.HtmlEditor2.png Ext.form.HtmlEditor component}
- * 
- *     // Passed via xtype into a container and with custom options:
- *     Ext.tip.QuickTips.init();  // enable tooltips
+ *
+ * Passed via xtype into a container and with custom options:
+ *
+ *     @example
+ *     Ext.tip.QuickTipManager.init();  // enable tooltips
  *     new Ext.panel.Panel({
  *         title: 'HTML Editor',
  *         renderTo: Ext.getBody(),
@@ -84304,7 +88016,6 @@ Ext.define('Ext.layout.component.field.HtmlEditor', {
  *             enableAlignments: false
  *         }
  *     });
- *
  */
 Ext.define('Ext.form.field.HtmlEditor', {
     extend:'Ext.Component',
@@ -84324,10 +88035,10 @@ Ext.define('Ext.form.field.HtmlEditor', {
     ],
 
     fieldSubTpl: [
-        '<div class="{toolbarWrapCls}"></div>',
-        '<textarea id="{id}" name="{name}" tabIndex="-1" class="{textareaCls}" ',
+        '<div id="{cmpId}-toolbarWrap" class="{toolbarWrapCls}"></div>',
+        '<textarea id="{cmpId}-textareaEl" name="{name}" tabIndex="-1" class="{textareaCls}" ',
             'style="{size}" autocomplete="off"></textarea>',
-        '<iframe name="{iframeName}" frameBorder="0" style="overflow:auto;{size}" src="{iframeSrc}"></iframe>',
+        '<iframe id="{cmpId}-iframeEl" name="{iframeName}" frameBorder="0" style="overflow:auto;{size}" src="{iframeSrc}"></iframe>',
         {
             compiled: true,
             disableFormats: true
@@ -84335,47 +88046,58 @@ Ext.define('Ext.form.field.HtmlEditor', {
     ],
 
     /**
-     * @cfg {Boolean} enableFormat Enable the bold, italic and underline buttons (defaults to true)
+     * @cfg {Boolean} enableFormat
+     * Enable the bold, italic and underline buttons
      */
     enableFormat : true,
     /**
-     * @cfg {Boolean} enableFontSize Enable the increase/decrease font size buttons (defaults to true)
+     * @cfg {Boolean} enableFontSize
+     * Enable the increase/decrease font size buttons
      */
     enableFontSize : true,
     /**
-     * @cfg {Boolean} enableColors Enable the fore/highlight color buttons (defaults to true)
+     * @cfg {Boolean} enableColors
+     * Enable the fore/highlight color buttons
      */
     enableColors : true,
     /**
-     * @cfg {Boolean} enableAlignments Enable the left, center, right alignment buttons (defaults to true)
+     * @cfg {Boolean} enableAlignments
+     * Enable the left, center, right alignment buttons
      */
     enableAlignments : true,
     /**
-     * @cfg {Boolean} enableLists Enable the bullet and numbered list buttons. Not available in Safari. (defaults to true)
+     * @cfg {Boolean} enableLists
+     * Enable the bullet and numbered list buttons. Not available in Safari.
      */
     enableLists : true,
     /**
-     * @cfg {Boolean} enableSourceEdit Enable the switch to source edit button. Not available in Safari. (defaults to true)
+     * @cfg {Boolean} enableSourceEdit
+     * Enable the switch to source edit button. Not available in Safari.
      */
     enableSourceEdit : true,
     /**
-     * @cfg {Boolean} enableLinks Enable the create link button. Not available in Safari. (defaults to true)
+     * @cfg {Boolean} enableLinks
+     * Enable the create link button. Not available in Safari.
      */
     enableLinks : true,
     /**
-     * @cfg {Boolean} enableFont Enable font selection. Not available in Safari. (defaults to true)
+     * @cfg {Boolean} enableFont
+     * Enable font selection. Not available in Safari.
      */
     enableFont : true,
     /**
-     * @cfg {String} createLinkText The default text for the create link prompt
+     * @cfg {String} createLinkText
+     * The default text for the create link prompt
      */
     createLinkText : 'Please enter the URL for the link:',
     /**
-     * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
+     * @cfg {String} [defaultLinkValue='http://']
+     * The default value for the create link prompt
      */
     defaultLinkValue : 'http:/'+'/',
     /**
-     * @cfg {Array} fontFamilies An array of available font families
+     * @cfg {String[]} fontFamilies
+     * An array of available font families
      */
     fontFamilies : [
         'Arial',
@@ -84386,7 +88108,9 @@ Ext.define('Ext.form.field.HtmlEditor', {
     ],
     defaultFont: 'tahoma',
     /**
-     * @cfg {String} defaultValue A default value to be put into the editor to resolve focus issues (defaults to &#160; (Non-breaking space) in Opera and IE6, &#8203; (Zero-width space) in all other browsers).
+     * @cfg {String} defaultValue
+     * A default value to be put into the editor to resolve focus issues (defaults to (Non-breaking space) in Opera
+     * and IE6, â€‹(Zero-width space) in all other browsers).
      */
     defaultValue: (Ext.isOpera || Ext.isIE6) ? '&#160;' : '&#8203;',
 
@@ -84402,7 +88126,7 @@ Ext.define('Ext.form.field.HtmlEditor', {
     hideMode:'offsets',
 
     maskOnDisable: true,
-    
+
     // private
     initComponent : function(){
         var me = this;
@@ -84416,23 +88140,22 @@ Ext.define('Ext.form.field.HtmlEditor', {
             'initialize',
             /**
              * @event activate
-             * Fires when the editor is first receives the focus. Any insertion must wait
-             * until after this event.
+             * Fires when the editor is first receives the focus. Any insertion must wait until after this event.
              * @param {Ext.form.field.HtmlEditor} this
              */
             'activate',
              /**
              * @event beforesync
-             * Fires before the textarea is updated with content from the editor iframe. Return false
-             * to cancel the sync.
+             * Fires before the textarea is updated with content from the editor iframe. Return false to cancel the
+             * sync.
              * @param {Ext.form.field.HtmlEditor} this
              * @param {String} html
              */
             'beforesync',
              /**
              * @event beforepush
-             * Fires before the iframe editor is updated with content from the textarea. Return false
-             * to cancel the push.
+             * Fires before the iframe editor is updated with content from the textarea. Return false to cancel the
+             * push.
              * @param {Ext.form.field.HtmlEditor} this
              * @param {String} html
              */
@@ -84467,11 +88190,11 @@ Ext.define('Ext.form.field.HtmlEditor', {
         me.initField();
     },
 
-    /*
-     * Protected method that will not generally be called directly. It
-     * is called when the editor creates its toolbar. Override this method if you need to
+    /**
+     * Called when the editor creates its toolbar. Override this method if you need to
      * add custom toolbar buttons.
      * @param {Ext.form.field.HtmlEditor} editor
+     * @protected
      */
     createToolbar : function(editor){
         var me = this,
@@ -84499,7 +88222,7 @@ Ext.define('Ext.form.field.HtmlEditor', {
         if (me.enableFont && !Ext.isSafari2) {
             fontSelectItem = Ext.widget('component', {
                 renderTpl: [
-                    '<select class="{cls}">',
+                    '<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>',
@@ -84510,9 +88233,7 @@ Ext.define('Ext.form.field.HtmlEditor', {
                     fonts: me.fontFamilies,
                     defaultFont: me.defaultFont
                 },
-                renderSelectors: {
-                    selectEl: 'select'
-                },
+                childEls: ['selectEl'],
                 onDisable: function() {
                     var selectEl = this.selectEl;
                     if (selectEl) {
@@ -84712,14 +88433,14 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * Protected method that will not generally be called directly. It
-     * is called when the editor initializes the iframe with HTML contents. Override this method if you
+     * Called when the editor initializes the iframe with HTML contents. Override this method if you
      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
      *
-     * Note: IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility.
+     * **Note:** IE8-Standards has unwanted scroller behavior, so the default meta tag forces IE7 compatibility.
      * Also note that forcing IE7 mode works when the page is loaded normally, but if you are using IE's Web
      * Developer Tools to manually set the document mode, that will take precedence and override what this
      * code sets by default. This can be confusing when developing, but is not a user-facing issue.
+     * @protected
      */
     getDocMarkup: function() {
         var me = this,
@@ -84745,16 +88466,11 @@ Ext.define('Ext.form.field.HtmlEditor', {
 
     // private
     onRender: function() {
-        var me = this,
-            renderSelectors = me.renderSelectors;
+        var me = this;
 
-        Ext.applyIf(renderSelectors, me.getLabelableSelectors());
+        me.onLabelableRender();
 
-        Ext.applyIf(renderSelectors, {
-            toolbarWrap: 'div.' + Ext.baseCSSPrefix + 'html-editor-tb',
-            iframeEl: 'iframe',
-            textareaEl: 'textarea'
-        });
+        me.addChildEls('toolbarWrap', 'iframeEl', 'textareaEl');
 
         me.callParent(arguments);
 
@@ -84786,6 +88502,8 @@ Ext.define('Ext.form.field.HtmlEditor', {
     getSubTplData: function() {
         var cssPrefix = Ext.baseCSSPrefix;
         return {
+            cmpId: this.id,
+            id: this.getInputId(),
             toolbarWrapCls: cssPrefix + 'html-editor-tb',
             textareaCls: cssPrefix + 'hidden',
             iframeName: Ext.id(),
@@ -84795,7 +88513,8 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     getSubTplMarkup: function() {
-        return this.getTpl('fieldSubTpl').apply(this.getSubTplData());
+        var data = this.getSubTplData();
+        return this.getTpl('fieldSubTpl').apply(data);
     },
 
     getBodyNaturalWidth: function() {
@@ -84839,8 +88558,9 @@ Ext.define('Ext.form.field.HtmlEditor', {
         }
     },
 
-    /* private
-     * set current design mode. To enable, mode can be true or 'on', off otherwise
+    /**
+     * @private
+     * Sets current design mode. To enable, mode can be true or 'on', off otherwise
      */
     setDesignMode: function(mode) {
         var me = this,
@@ -84934,10 +88654,10 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * Protected method that will not generally be called directly. If you need/want
-     * custom HTML cleanup, this is the method you should override.
+     * If you need/want custom HTML cleanup, this is the method you should override.
      * @param {String} html The HTML to be cleaned
      * @return {String} The cleaned HTML
+     * @protected
      */
     cleanHtml: function(html) {
         html = String(html);
@@ -84957,8 +88677,8 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * @protected method that will not generally be called directly. Syncs the contents
-     * of the editor iframe with the textarea.
+     * Syncs the contents of the editor iframe with the textarea.
+     * @protected
      */
     syncValue : function(){
         var me = this,
@@ -84994,8 +88714,8 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * @protected method that will not generally be called directly. Pushes the value of the textarea
-     * into the iframe editor.
+     * Pushes the value of the textarea into the iframe editor.
+     * @protected
      */
     pushValue: function() {
         var me = this,
@@ -85041,7 +88761,7 @@ Ext.define('Ext.form.field.HtmlEditor', {
             ss['background-attachment'] = 'fixed'; // w3c
             dbody.bgProperties = 'fixed'; // ie
 
-            Ext.core.DomHelper.applyStyles(dbody, ss);
+            Ext.DomHelper.applyStyles(dbody, ss);
 
             doc = me.getDoc();
 
@@ -85124,7 +88844,7 @@ Ext.define('Ext.form.field.HtmlEditor', {
             } catch(e) {
                 // ignore (why?)
             }
-            Ext.destroyMembers('tb', 'toolbarWrap', 'iframeEl', 'textareaEl');
+            Ext.destroyMembers(me, 'tb', 'toolbarWrap', 'iframeEl', 'textareaEl');
         }
         me.callParent();
     },
@@ -85216,8 +88936,8 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * Protected method that will not generally be called directly. It triggers
-     * a toolbar update by reading the markup state of the current selection in the editor.
+     * Triggers a toolbar update by reading the markup state of the current selection in the editor.
+     * @protected
      */
     updateToolbar: function() {
         var me = this,
@@ -85269,10 +88989,10 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * Executes a Midas editor command on the editor document and performs necessary focus and
-     * toolbar updates. <b>This should only be called after the editor is initialized.</b>
+     * Executes a Midas editor command on the editor document and performs necessary focus and toolbar updates.
+     * **This should only be called after the editor is initialized.**
      * @param {String} cmd The Midas command
-     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
+     * @param {String/Boolean} [value=null] The value to pass to the command
      */
     relayCmd: function(cmd, value) {
         Ext.defer(function() {
@@ -85284,9 +89004,8 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * Executes a Midas editor command directly on the editor document.
-     * For visual commands, you should use {@link #relayCmd} instead.
-     * <b>This should only be called after the editor is initialized.</b>
+     * Executes a Midas editor command directly on the editor document. For visual commands, you should use
+     * {@link #relayCmd} instead. **This should only be called after the editor is initialized.**
      * @param {String} cmd The Midas command
      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
      */
@@ -85327,8 +89046,8 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
-     * to insert text.
+     * Inserts the passed text at the current cursor position.
+     * Note: the editor must be initialized and activated to insert text.
      * @param {String} text
      */
     insertAtCursor : function(text){
@@ -85416,7 +89135,7 @@ Ext.define('Ext.form.field.HtmlEditor', {
     }(),
 
     /**
-     * Returns the editor's toolbar. <b>This is only available after the editor has been rendered.</b>
+     * Returns the editor's toolbar. **This is only available after the editor has been rendered.**
      * @return {Ext.toolbar.Toolbar}
      */
     getToolbar : function(){
@@ -85424,24 +89143,22 @@ Ext.define('Ext.form.field.HtmlEditor', {
     },
 
     /**
-     * Object collection of toolbar tooltips for the buttons in the editor. The key
-     * is the command id associated with that button and the value is a valid QuickTips object.
-     * For example:
-<pre><code>
-{
-    bold : {
-        title: 'Bold (Ctrl+B)',
-        text: 'Make the selected text bold.',
-        cls: 'x-html-editor-tip'
-    },
-    italic : {
-        title: 'Italic (Ctrl+I)',
-        text: 'Make the selected text italic.',
-        cls: 'x-html-editor-tip'
-    },
-    ...
-</code></pre>
-    * @type Object
+     * @property {Object} buttonTips
+     * Object collection of toolbar tooltips for the buttons in the editor. The key is the command id associated with
+     * that button and the value is a valid QuickTips object. For example:
+     *
+     *     {
+     *         bold : {
+     *             title: 'Bold (Ctrl+B)',
+     *             text: 'Make the selected text bold.',
+     *             cls: 'x-html-editor-tip'
+     *         },
+     *         italic : {
+     *             title: 'Italic (Ctrl+I)',
+     *             text: 'Make the selected text italic.',
+     *             cls: 'x-html-editor-tip'
+     *         },
+     *         ...
      */
     buttonTips : {
         bold : {
@@ -85555,7 +89272,7 @@ Ext.define('Ext.form.field.HtmlEditor', {
      * @cfg {String} msgFx @hide
      */
     /**
-     * @cfg {Boolean} allowDomMove  @hide
+     * @cfg {Boolean} allowDomMove @hide
      */
     /**
      * @cfg {String} applyTo @hide
@@ -85573,178 +89290,177 @@ Ext.define('Ext.form.field.HtmlEditor', {
 });
 
 /**
- * @class Ext.form.field.Radio
- * @extends Ext.form.field.Checkbox
-
-Single radio field. Similar to checkbox, but automatically handles making sure only one radio is checked
-at a time within a group of radios with the same name.
-
-__Labeling:__
-In addition to the {@link Ext.form.Labelable standard field labeling options}, radio buttons
-may be given an optional {@link #boxLabel} which will be displayed immediately to the right of the input. Also
-see {@link Ext.form.RadioGroup} for a convenient method of grouping related radio buttons.
-
-__Values:__
-The main value of a Radio field is a boolean, indicating whether or not the radio is checked.
-
-The following values will check the radio:
-* `true`
-* `'true'`
-* `'1'`
-* `'on'`
-
-Any other value will uncheck it.
-
-In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be sent
-as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set this
-value if you have multiple radio buttons with the same {@link #name}, as is almost always the case.
-{@img Ext.form.Radio/Ext.form.Radio.png Ext.form.Radio component}
-__Example usage:__
-
-    Ext.create('Ext.form.Panel', {
-        title      : 'Order Form',
-        width      : 300,
-        bodyPadding: 10,
-        renderTo   : Ext.getBody(),
-        items: [
-            {
-                xtype      : 'fieldcontainer',
-                fieldLabel : 'Size',
-                defaultType: 'radiofield',
-                defaults: {
-                    flex: 1
-                },
-                layout: 'hbox',
-                items: [
-                    {
-                        boxLabel  : 'M',
-                        name      : 'size',
-                        inputValue: 'm',
-                        id        : 'radio1'
-                    }, {
-                        boxLabel  : 'L',
-                        name      : 'size',
-                        inputValue: 'l',
-                        id        : 'radio2'
-                    }, {
-                        boxLabel  : 'XL',
-                        name      : 'size',
-                        inputValue: 'xl',
-                        id        : 'radio3'
-                    }
-                ]
-            },
-            {
-                xtype      : 'fieldcontainer',
-                fieldLabel : 'Color',
-                defaultType: 'radiofield',
-                defaults: {
-                    flex: 1
-                },
-                layout: 'hbox',
-                items: [
-                    {
-                        boxLabel  : 'Blue',
-                        name      : 'color',
-                        inputValue: 'blue',
-                        id        : 'radio4'
-                    }, {
-                        boxLabel  : 'Grey',
-                        name      : 'color',
-                        inputValue: 'grey',
-                        id        : 'radio5'
-                    }, {
-                        boxLabel  : 'Black',
-                        name      : 'color',
-                        inputValue: 'black',
-                        id        : 'radio6'
-                    }
-                ]
-            }
-        ],
-        bbar: [
-            {
-                text: 'Smaller Size',
-                handler: function() {
-                    var radio1 = Ext.getCmp('radio1'),
-                        radio2 = Ext.getCmp('radio2'),
-                        radio3 = Ext.getCmp('radio3');
-
-                    //if L is selected, change to M
-                    if (radio2.getValue()) {
-                        radio1.setValue(true);
-                        return;
-                    }
-
-                    //if XL is selected, change to L
-                    if (radio3.getValue()) {
-                        radio2.setValue(true);
-                        return;
-                    }
-
-                    //if nothing is set, set size to S
-                    radio1.setValue(true);
-                }
-            },
-            {
-                text: 'Larger Size',
-                handler: function() {
-                    var radio1 = Ext.getCmp('radio1'),
-                        radio2 = Ext.getCmp('radio2'),
-                        radio3 = Ext.getCmp('radio3');
-
-                    //if M is selected, change to L
-                    if (radio1.getValue()) {
-                        radio2.setValue(true);
-                        return;
-                    }
-
-                    //if L is selected, change to XL
-                    if (radio2.getValue()) {
-                        radio3.setValue(true);
-                        return;
-                    }
-
-                    //if nothing is set, set size to XL
-                    radio3.setValue(true);
-                }
-            },
-            '-',
-            {
-                text: 'Select color',
-                menu: {
-                    indent: false,
-                    items: [
-                        {
-                            text: 'Blue',
-                            handler: function() {
-                                var radio = Ext.getCmp('radio4');
-                                radio.setValue(true);
-                            }
-                        },
-                        {
-                            text: 'Grey',
-                            handler: function() {
-                                var radio = Ext.getCmp('radio5');
-                                radio.setValue(true);
-                            }
-                        },
-                        {
-                            text: 'Black',
-                            handler: function() {
-                                var radio = Ext.getCmp('radio6');
-                                radio.setValue(true);
-                            }
-                        }
-                    ]
-                }
-            }
-        ]
-    });
-
-
  * @docauthor Robert Dougan <rob@sencha.com>
- * @markdown
+ *
+ * Single radio field. Similar to checkbox, but automatically handles making sure only one radio is checked
+ * at a time within a group of radios with the same name.
+ *
+ * # Labeling
+ *
+ * In addition to the {@link Ext.form.Labelable standard field labeling options}, radio buttons
+ * may be given an optional {@link #boxLabel} which will be displayed immediately to the right of the input. Also
+ * see {@link Ext.form.RadioGroup} for a convenient method of grouping related radio buttons.
+ *
+ * # Values
+ *
+ * The main value of a Radio field is a boolean, indicating whether or not the radio is checked.
+ *
+ * The following values will check the radio:
+ *
+ * - `true`
+ * - `'true'`
+ * - `'1'`
+ * - `'on'`
+ *
+ * Any other value will uncheck it.
+ *
+ * In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be sent
+ * as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set this
+ * value if you have multiple radio buttons with the same {@link #name}, as is almost always the case.
+ *
+ * # Example usage
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
+ *         title      : 'Order Form',
+ *         width      : 300,
+ *         bodyPadding: 10,
+ *         renderTo   : Ext.getBody(),
+ *         items: [
+ *             {
+ *                 xtype      : 'fieldcontainer',
+ *                 fieldLabel : 'Size',
+ *                 defaultType: 'radiofield',
+ *                 defaults: {
+ *                     flex: 1
+ *                 },
+ *                 layout: 'hbox',
+ *                 items: [
+ *                     {
+ *                         boxLabel  : 'M',
+ *                         name      : 'size',
+ *                         inputValue: 'm',
+ *                         id        : 'radio1'
+ *                     }, {
+ *                         boxLabel  : 'L',
+ *                         name      : 'size',
+ *                         inputValue: 'l',
+ *                         id        : 'radio2'
+ *                     }, {
+ *                         boxLabel  : 'XL',
+ *                         name      : 'size',
+ *                         inputValue: 'xl',
+ *                         id        : 'radio3'
+ *                     }
+ *                 ]
+ *             },
+ *             {
+ *                 xtype      : 'fieldcontainer',
+ *                 fieldLabel : 'Color',
+ *                 defaultType: 'radiofield',
+ *                 defaults: {
+ *                     flex: 1
+ *                 },
+ *                 layout: 'hbox',
+ *                 items: [
+ *                     {
+ *                         boxLabel  : 'Blue',
+ *                         name      : 'color',
+ *                         inputValue: 'blue',
+ *                         id        : 'radio4'
+ *                     }, {
+ *                         boxLabel  : 'Grey',
+ *                         name      : 'color',
+ *                         inputValue: 'grey',
+ *                         id        : 'radio5'
+ *                     }, {
+ *                         boxLabel  : 'Black',
+ *                         name      : 'color',
+ *                         inputValue: 'black',
+ *                         id        : 'radio6'
+ *                     }
+ *                 ]
+ *             }
+ *         ],
+ *         bbar: [
+ *             {
+ *                 text: 'Smaller Size',
+ *                 handler: function() {
+ *                     var radio1 = Ext.getCmp('radio1'),
+ *                         radio2 = Ext.getCmp('radio2'),
+ *                         radio3 = Ext.getCmp('radio3');
+ *
+ *                     //if L is selected, change to M
+ *                     if (radio2.getValue()) {
+ *                         radio1.setValue(true);
+ *                         return;
+ *                     }
+ *
+ *                     //if XL is selected, change to L
+ *                     if (radio3.getValue()) {
+ *                         radio2.setValue(true);
+ *                         return;
+ *                     }
+ *
+ *                     //if nothing is set, set size to S
+ *                     radio1.setValue(true);
+ *                 }
+ *             },
+ *             {
+ *                 text: 'Larger Size',
+ *                 handler: function() {
+ *                     var radio1 = Ext.getCmp('radio1'),
+ *                         radio2 = Ext.getCmp('radio2'),
+ *                         radio3 = Ext.getCmp('radio3');
+ *
+ *                     //if M is selected, change to L
+ *                     if (radio1.getValue()) {
+ *                         radio2.setValue(true);
+ *                         return;
+ *                     }
+ *
+ *                     //if L is selected, change to XL
+ *                     if (radio2.getValue()) {
+ *                         radio3.setValue(true);
+ *                         return;
+ *                     }
+ *
+ *                     //if nothing is set, set size to XL
+ *                     radio3.setValue(true);
+ *                 }
+ *             },
+ *             '-',
+ *             {
+ *                 text: 'Select color',
+ *                 menu: {
+ *                     indent: false,
+ *                     items: [
+ *                         {
+ *                             text: 'Blue',
+ *                             handler: function() {
+ *                                 var radio = Ext.getCmp('radio4');
+ *                                 radio.setValue(true);
+ *                             }
+ *                         },
+ *                         {
+ *                             text: 'Grey',
+ *                             handler: function() {
+ *                                 var radio = Ext.getCmp('radio5');
+ *                                 radio.setValue(true);
+ *                             }
+ *                         },
+ *                         {
+ *                             text: 'Black',
+ *                             handler: function() {
+ *                                 var radio = Ext.getCmp('radio6');
+ *                                 radio.setValue(true);
+ *                             }
+ *                         }
+ *                     ]
+ *                 }
+ *             }
+ *         ]
+ *     });
  */
 Ext.define('Ext.form.field.Radio', {
     extend:'Ext.form.field.Checkbox',
@@ -85782,9 +89498,9 @@ Ext.define('Ext.form.field.Radio', {
     },
 
     /**
-     * Sets either the checked/unchecked status of this Radio, or, if a string value
-     * is passed, checks a sibling Radio of the same name whose value is the value specified.
-     * @param value {String/Boolean} Checked value, or the value of the sibling radio button to check.
+     * Sets either the checked/unchecked status of this Radio, or, if a string value is passed, checks a sibling Radio
+     * of the same name whose value is the value specified.
+     * @param {String/Boolean} value Checked value, or the value of the sibling radio button to check.
      * @return {Ext.form.field.Radio} this
      */
     setValue: function(v) {
@@ -85804,7 +89520,7 @@ Ext.define('Ext.form.field.Radio', {
 
     /**
      * Returns the submit value for the checkbox which can be used when submitting forms.
-     * @return {Boolean/null} True if checked, null if not.
+     * @return {Boolean/Object} True if checked, null if not.
      */
     getSubmitValue: function() {
         return this.checked ? this.inputValue : null;
@@ -85828,12 +89544,6 @@ Ext.define('Ext.form.field.Radio', {
         }
     },
 
-    // inherit docs
-    beforeDestroy: function(){
-        this.callParent();
-        this.getManager().removeAtKey(this.id);
-    },
-
     // inherit docs
     getManager: function() {
         return Ext.form.RadioManager;
@@ -85841,28 +89551,23 @@ Ext.define('Ext.form.field.Radio', {
 });
 
 /**
- * @class Ext.picker.Time
- * @extends Ext.view.BoundList
- * <p>A time picker which provides a list of times from which to choose. This is used by the
- * {@link Ext.form.field.Time} class to allow browsing and selection of valid times, but could also be used
- * with other components.</p>
- * <p>By default, all times starting at midnight and incrementing every 15 minutes will be presented.
- * This list of available times can be controlled using the {@link #minValue}, {@link #maxValue}, and
- * {@link #increment} configuration properties. The format of the times presented in the list can be
- * customized with the {@link #format} config.</p>
- * <p>To handle when the user selects a time from the list, you can subscribe to the {@link #selectionchange}
- * event.</p>
- *
- * {@img Ext.picker.Time/Ext.picker.Time.png Ext.picker.Time component}
- *
- * ## Code
-     new Ext.create('Ext.picker.Time', {
-        width: 60,
-        minValue: Ext.Date.parse('04:30:00 AM', 'h:i:s A'),
-        maxValue: Ext.Date.parse('08:00:00 AM', 'h:i:s A'),
-        renderTo: Ext.getBody()
-    });
+ * A time picker which provides a list of times from which to choose. This is used by the Ext.form.field.Time
+ * class to allow browsing and selection of valid times, but could also be used with other components.
+ *
+ * By default, all times starting at midnight and incrementing every 15 minutes will be presented. This list of
+ * available times can be controlled using the {@link #minValue}, {@link #maxValue}, and {@link #increment}
+ * configuration properties. The format of the times presented in the list can be customized with the {@link #format}
+ * config.
  *
+ * To handle when the user selects a time from the list, you can subscribe to the {@link #selectionchange} event.
+ *
+ *     @example
+ *     Ext.create('Ext.picker.Time', {
+ *        width: 60,
+ *        minValue: Ext.Date.parse('04:30:00 AM', 'h:i:s A'),
+ *        maxValue: Ext.Date.parse('08:00:00 AM', 'h:i:s A'),
+ *        renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.picker.Time', {
     extend: 'Ext.view.BoundList',
@@ -85871,27 +89576,27 @@ Ext.define('Ext.picker.Time', {
 
     /**
      * @cfg {Date} minValue
-     * The minimum time to be shown in the list of times. This must be a Date object (only the time fields
-     * will be used); no parsing of String values will be done. Defaults to undefined.
+     * The minimum time to be shown in the list of times. This must be a Date object (only the time fields will be
+     * used); no parsing of String values will be done.
      */
 
     /**
      * @cfg {Date} maxValue
-     * The maximum time to be shown in the list of times. This must be a Date object (only the time fields
-     * will be used); no parsing of String values will be done. Defaults to undefined.
+     * The maximum time to be shown in the list of times. This must be a Date object (only the time fields will be
+     * used); no parsing of String values will be done.
      */
 
     /**
      * @cfg {Number} increment
-     * The number of minutes between each time value in the list (defaults to 15).
+     * The number of minutes between each time value in the list.
      */
     increment: 15,
 
     /**
      * @cfg {String} format
-     * The default time format string which can be overriden for localization support. The format must be
-     * valid according to {@link Ext.Date#parse} (defaults to 'g:i A', e.g., '3:15 PM'). For 24-hour time
-     * format try 'H:i' instead.
+     * The default time format string which can be overriden for localization support. The format must be valid
+     * according to {@link Ext.Date#parse} (defaults to 'g:i A', e.g., '3:15 PM'). For 24-hour time format try 'H:i'
+     * instead.
      */
     format : "g:i A",
 
@@ -85906,7 +89611,7 @@ Ext.define('Ext.picker.Time', {
      * @private
      * Year, month, and day that all times will be normalized into internally.
      */
-    initDate: [2008,1,1],
+    initDate: [2008,0,1],
 
     componentCls: Ext.baseCSSPrefix + 'timepicker',
 
@@ -85919,21 +89624,21 @@ Ext.define('Ext.picker.Time', {
         var me = this,
             dateUtil = Ext.Date,
             clearTime = dateUtil.clearTime,
-            initDate = me.initDate.join('/');
+            initDate = me.initDate;
 
         // Set up absolute min and max for the entire day
-        me.absMin = clearTime(new Date(initDate));
-        me.absMax = dateUtil.add(clearTime(new Date(initDate)), 'mi', (24 * 60) - 1);
+        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();
 
-        this.callParent();
+        me.callParent();
     },
 
     /**
-     * Set the {@link #minValue} and update the list of available times. This must be a Date
-     * object (only the time fields will be used); no parsing of String values will be done.
+     * Set the {@link #minValue} and update the list of available times. This must be a Date object (only the time
+     * fields will be used); no parsing of String values will be done.
      * @param {Date} value
      */
     setMinValue: function(value) {
@@ -85942,8 +89647,8 @@ Ext.define('Ext.picker.Time', {
     },
 
     /**
-     * Set the {@link #maxValue} and update the list of available times. This must be a Date
-     * object (only the time fields will be used); no parsing of String values will be done.
+     * Set the {@link #maxValue} and update the list of available times. This must be a Date object (only the time
+     * fields will be used); no parsing of String values will be done.
      * @param {Date} value
      */
     setMaxValue: function(value) {
@@ -85959,13 +89664,13 @@ Ext.define('Ext.picker.Time', {
      */
     normalizeDate: function(date) {
         var initDate = this.initDate;
-        date.setFullYear(initDate[0], initDate[1] - 1, initDate[2]);
+        date.setFullYear(initDate[0], initDate[1], initDate[2]);
         return date;
     },
 
     /**
-     * Update the list of available times in the list to be constrained within the
-     * {@link #minValue} and {@link #maxValue}.
+     * Update the list of available times in the list to be constrained within the {@link #minValue}
+     * and {@link #maxValue}.
      */
     updateList: function() {
         var me = this,
@@ -86008,42 +89713,42 @@ Ext.define('Ext.picker.Time', {
 });
 
 /**
- * @class Ext.form.field.Time
- * @extends Ext.form.field.Picker
- * <p>Provides a time input field with a time dropdown and automatic time validation.</p>
- * <p>This field recognizes and uses JavaScript Date objects as its main {@link #value} type (only the time
- * portion of the date is used; the month/day/year are ignored). In addition, it recognizes string values which
- * are parsed according to the {@link #format} and/or {@link #altFormats} configs. These may be reconfigured
- * to use time formats appropriate for the user's locale.</p>
- * <p>The field may be limited to a certain range of times by using the {@link #minValue} and {@link #maxValue}
- * configs, and the interval between time options in the dropdown can be changed with the {@link #increment} config.</p>
- * {@img Ext.form.Time/Ext.form.Time.png Ext.form.Time component}
- * <p>Example usage:</p>
- * <pre><code>
-Ext.create('Ext.form.Panel', {
-    title: 'Time Card',
   width: 300,
   bodyPadding: 10,
-    renderTo: Ext.getBody(),        
-    items: [{
-        xtype: 'timefield',
       name: 'in',
       fieldLabel: 'Time In',
       minValue: '6:00 AM',
       maxValue: '8:00 PM',
       increment: 30,
-        anchor: '100%'
-    }, {
-        xtype: 'timefield',
       name: 'out',
       fieldLabel: 'Time Out',
       minValue: '6:00 AM',
       maxValue: '8:00 PM',
       increment: 30,
-        anchor: '100%'
-   }]
-});
-</code></pre>
+ * Provides a time input field with a time dropdown and automatic time validation.
+ *
+ * This field recognizes and uses JavaScript Date objects as its main {@link #value} type (only the time portion of the
+ * date is used; the month/day/year are ignored). In addition, it recognizes string values which are parsed according to
+ * the {@link #format} and/or {@link #altFormats} configs. These may be reconfigured to use time formats appropriate for
+ * the user's locale.
+ *
+ * The field may be limited to a certain range of times by using the {@link #minValue} and {@link #maxValue} configs,
+ * and the interval between time options in the dropdown can be changed with the {@link #increment} config.
+ *
+ * Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
*         title: 'Time Card',
*         width: 300,
+ *         bodyPadding: 10,
+ *         renderTo: Ext.getBody(),
+ *         items: [{
*             xtype: 'timefield',
*             name: 'in',
*             fieldLabel: 'Time In',
*             minValue: '6:00 AM',
*             maxValue: '8:00 PM',
+ *             increment: 30,
+ *             anchor: '100%'
+ *         }, {
*             xtype: 'timefield',
*             name: 'out',
*             fieldLabel: 'Time Out',
*             minValue: '6:00 AM',
*             maxValue: '8:00 PM',
+ *             increment: 30,
+ *             anchor: '100%'
+ *        }]
+ *     });
  */
 Ext.define('Ext.form.field.Time', {
     extend:'Ext.form.field.Picker',
@@ -86053,80 +89758,78 @@ Ext.define('Ext.form.field.Time', {
 
     /**
      * @cfg {String} triggerCls
-     * An additional CSS class used to style the trigger button.  The trigger will always get the
-     * {@link #triggerBaseCls} by default and <tt>triggerCls</tt> will be <b>appended</b> if specified.
-     * Defaults to <tt>'x-form-time-trigger'</tt> for the Time field trigger.
+     * An additional CSS class used to style the trigger button. The trigger will always get the {@link #triggerBaseCls}
+     * by default and triggerCls will be **appended** if specified. Defaults to 'x-form-time-trigger' for the Time field
+     * trigger.
      */
     triggerCls: Ext.baseCSSPrefix + 'form-time-trigger',
 
     /**
      * @cfg {Date/String} minValue
-     * The minimum allowed time. Can be either a Javascript date object with a valid time value or a string
-     * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
+     * The minimum allowed time. Can be either a Javascript date object with a valid time value or a string time in a
+     * valid format -- see {@link #format} and {@link #altFormats}.
      */
 
     /**
      * @cfg {Date/String} maxValue
-     * The maximum allowed time. Can be either a Javascript date object with a valid time value or a string
-     * time in a valid format -- see {@link #format} and {@link #altFormats} (defaults to undefined).
+     * The maximum allowed time. Can be either a Javascript date object with a valid time value or a string time in a
+     * valid format -- see {@link #format} and {@link #altFormats}.
      */
 
     /**
      * @cfg {String} minText
-     * The error text to display when the entered time is before {@link #minValue} (defaults to
-     * 'The time in this field must be equal to or after {0}').
+     * The error text to display when the entered time is before {@link #minValue}.
      */
     minText : "The time in this field must be equal to or after {0}",
 
     /**
      * @cfg {String} maxText
-     * The error text to display when the entered time is after {@link #maxValue} (defaults to
-     * 'The time in this field must be equal to or before {0}').
+     * The error text to display when the entered time is after {@link #maxValue}.
      */
     maxText : "The time in this field must be equal to or before {0}",
 
     /**
      * @cfg {String} invalidText
-     * The error text to display when the time in the field is invalid (defaults to
-     * '{value} is not a valid time').
+     * The error text to display when the time in the field is invalid.
      */
     invalidText : "{0} is not a valid time",
 
     /**
      * @cfg {String} format
-     * The default time format string which can be overriden for localization support.  The format must be
-     * valid according to {@link Ext.Date#parse} (defaults to 'g:i A', e.g., '3:15 PM').  For 24-hour time
-     * format try 'H:i' instead.
+     * The default time format string which can be overriden for localization support. The format must be valid
+     * according to {@link Ext.Date#parse} (defaults to 'g:i A', e.g., '3:15 PM'). For 24-hour time format try 'H:i'
+     * instead.
      */
     format : "g:i A",
 
     /**
-     * @cfg {String} submitFormat The date format string which will be submitted to the server.
-     * The format must be valid according to {@link Ext.Date#parse} (defaults to <tt>{@link #format}</tt>).
+     * @cfg {String} submitFormat
+     * The date format string which will be submitted to the server. The format must be valid according to {@link
+     * Ext.Date#parse} (defaults to {@link #format}).
      */
 
     /**
      * @cfg {String} altFormats
      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
-     * format (defaults to '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').
+     * format.
      */
     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",
 
     /**
      * @cfg {Number} increment
-     * The number of minutes between each time value in the list (defaults to 15).
+     * The number of minutes between each time value in the list.
      */
     increment: 15,
 
     /**
      * @cfg {Number} pickerMaxHeight
-     * The maximum height of the {@link Ext.picker.Time} dropdown. Defaults to 300.
+     * The maximum height of the {@link Ext.picker.Time} dropdown.
      */
     pickerMaxHeight: 300,
 
     /**
      * @cfg {Boolean} selectOnTab
-     * Whether the Tab key should select the currently highlighted item. Defaults to <tt>true</tt>.
+     * Whether the Tab key should select the currently highlighted item.
      */
     selectOnTab: true,
 
@@ -86221,12 +89924,12 @@ Ext.define('Ext.form.field.Time', {
     },
 
     /**
-     * Runs all of Time's validations and returns an array of any errors. Note that this first
-     * runs Text's validations, so the returned array is an amalgamation of all field errors.
-     * The additional validation checks are testing that the time format is valid, that the chosen
-     * time is within the {@link #minValue} and {@link #maxValue} constraints set.
-     * @param {Mixed} value The value to get errors for (defaults to the current field value)
-     * @return {Array} All validation errors for this field
+     * Runs all of Time's validations and returns an array of any errors. Note that this first runs Text's validations,
+     * so the returned array is an amalgamation of all field errors. The additional validation checks are testing that
+     * the time format is valid, that the chosen time is within the {@link #minValue} and {@link #maxValue} constraints
+     * set.
+     * @param {Object} [value] The value to get errors for (defaults to the current field value)
+     * @return {String[]} All validation errors for this field
      */
     getErrors: function(value) {
         var me = this,
@@ -86325,6 +90028,7 @@ Ext.define('Ext.form.field.Time', {
     createPicker: function() {
         var me = this,
             picker = Ext.create('Ext.picker.Time', {
+                pickerField: me,
                 selModel: {
                     mode: 'SINGLE'
                 },
@@ -86529,15 +90233,11 @@ Ext.define('Ext.grid.CellEditor', {
  *
  * <p>This class is used only by the grid's HeaderContainer docked child.</p>
  *
- * <p>This class adds the ability to shrink the vertical size of the inner container element back if a grouped
+ * <p>It adds the ability to shrink the vertical size of the inner container element back if a grouped
  * column header has all its child columns dragged out, and the whole HeaderContainer needs to shrink back down.</p>
  *
- * <p>It also enforces the grid's HeaderContainer's forceFit config by, after every calaculateChildBoxes call, converting
- * all pixel widths into flex values, so that propertions are maintained upon width change of the grid.</p>
- *
  * <p>Also, after every layout, after all headers have attained their 'stretchmax' height, it goes through and calls
- * <code>setPadding</code> on the columns so that they lay out correctly. TODO: implement a ColumnHeader component
- * layout which takes responsibility for this, and will run upon resize.</p>
+ * <code>setPadding</code> on the columns so that they lay out correctly.</p>
  */
 Ext.define('Ext.grid.ColumnLayout', {
     extend: 'Ext.layout.container.HBox',
@@ -86546,8 +90246,10 @@ Ext.define('Ext.grid.ColumnLayout', {
 
     reserveOffset: false,
 
+    shrinkToFit: false,
+
     // Height-stretched innerCt must be able to revert back to unstretched height
-    clearInnerCtOnLayout: false,
+    clearInnerCtOnLayout: true,
 
     beforeLayout: function() {
         var me = this,
@@ -86569,19 +90271,17 @@ Ext.define('Ext.grid.ColumnLayout', {
         me.innerCt.setHeight(23);
 
         // Unstretch child items before the layout which stretches them.
-        if (me.align == 'stretchmax') {
-            for (; i < len; i++) {
-                item = items[i];
-                item.el.setStyle({
-                    height: 'auto'
-                });
-                item.titleContainer.setStyle({
-                    height: 'auto',
-                    paddingTop: '0'
-                });
-                if (item.componentLayout && item.componentLayout.lastComponentSize) {
-                    item.componentLayout.lastComponentSize.height = item.el.dom.offsetHeight;
-                }
+        for (; i < len; i++) {
+            item = items[i];
+            item.el.setStyle({
+                height: 'auto'
+            });
+            item.titleContainer.setStyle({
+                height: 'auto',
+                paddingTop: '0'
+            });
+            if (item.componentLayout && item.componentLayout.lastComponentSize) {
+                item.componentLayout.lastComponentSize.height = item.el.dom.offsetHeight;
             }
         }
         return returnValue;
@@ -86595,7 +90295,7 @@ Ext.define('Ext.grid.ColumnLayout', {
             metaData = calculations.meta,
             len = boxes.length, i = 0, box, item;
 
-        if (targetSize.width && !me.isColumn) {
+        if (targetSize.width && !me.isHeader) {
             // If configured forceFit then all columns will be flexed
             if (me.owner.forceFit) {
 
@@ -86624,16 +90324,84 @@ Ext.define('Ext.grid.ColumnLayout', {
 
     afterLayout: function() {
         var me = this,
+            owner = me.owner,
+            topGrid,
+            bothHeaderCts,
+            otherHeaderCt,
+            thisHeight,
+            otherHeight,
+            modifiedGrid,
             i = 0,
-            items = me.getLayoutItems(),
-            len = items.length;
+            items,
+            len,
+            headerHeight;
 
         me.callParent(arguments);
 
         // Set up padding in items
-        if (!me.owner.hideHeaders && me.align == 'stretchmax') {
+        if (!me.owner.hideHeaders) {
+
+            // If this is one HeaderContainer of a pair in a side-by-side locking view, then find the height
+            // of the highest one, and sync the other one to that height.
+            if (owner.lockableInjected) {
+                topGrid = owner.up('tablepanel').up('tablepanel');
+                bothHeaderCts = topGrid.query('headercontainer:not([isHeader])');
+                otherHeaderCt = (bothHeaderCts[0] === owner) ? bothHeaderCts[1] : bothHeaderCts[0];
+
+                // Both sides must be rendered for this syncing operation to work.
+                if (!otherHeaderCt.rendered) {
+                    return;
+                }
+
+                // Get the height of the highest of both HeaderContainers
+                otherHeight = otherHeaderCt.layout.getRenderTarget().getViewSize().height;
+                if (!otherHeight) {
+                    return;
+                }
+                thisHeight = this.getRenderTarget().getViewSize().height;
+                if (!thisHeight) {
+                    return;
+                }
+
+                // Prevent recursion back into here when the "other" grid, after adjusting to the new hight of its headerCt, attempts to inform its ownerCt
+                // Block the upward notification by flagging the top grid's component layout as busy.
+                topGrid.componentLayout.layoutBusy = true;
+
+                // Assume that the correct header height is the height of this HeaderContainer
+                headerHeight = thisHeight;
+
+                // Synch the height of the smaller HeaderContainer to the height of the highest one.
+                if (thisHeight > otherHeight) {
+                    otherHeaderCt.layout.align = 'stretch';
+                    otherHeaderCt.setCalculatedSize(otherHeaderCt.getWidth(), owner.getHeight(), otherHeaderCt.ownerCt);
+                    delete otherHeaderCt.layout.align;
+                    modifiedGrid = otherHeaderCt.up('tablepanel');
+                } else if (otherHeight > thisHeight) {
+                    headerHeight = otherHeight;
+                    this.align = 'stretch';
+                    owner.setCalculatedSize(owner.getWidth(), otherHeaderCt.getHeight(), owner.ownerCt);
+                    delete this.align;
+                    modifiedGrid = owner.up('tablepanel');
+                }
+                topGrid.componentLayout.layoutBusy = false;
+
+                // Gather all Header items across both Grids.
+                items = bothHeaderCts[0].layout.getLayoutItems().concat(bothHeaderCts[1].layout.getLayoutItems());
+            } else {
+                headerHeight = this.getRenderTarget().getViewSize().height;
+                items = me.getLayoutItems();
+            }
+
+            len = items.length;
             for (; i < len; i++) {
-                items[i].setPadding();
+                items[i].setPadding(headerHeight);
+            }
+
+            // Size the View within the grid which has had its HeaderContainer entallened (That's a perfectly cromulent word BTW)
+            if (modifiedGrid) {
+                setTimeout(function() {
+                    modifiedGrid.doLayout();
+                }, 1);
             }
         }
     },
@@ -86645,7 +90413,7 @@ Ext.define('Ext.grid.ColumnLayout', {
             extra;
 
         // Columns must not account for scroll offset
-        if (!me.isColumn) {
+        if (!me.isHeader) {
             me.tooNarrow = calcs.meta.tooNarrow;
             extra = (me.reserveOffset ? me.availableSpaceOffset : 0);
 
@@ -86669,18 +90437,18 @@ Ext.define('Ext.grid.ColumnLayout', {
 /**
  * @class Ext.grid.LockingView
  * This class is used internally to provide a single interface when using
- * a locking grid. Internally, the locking grid creates 2 separate grids,
+ * a locking grid. Internally, the locking grid creates two separate grids,
  * so this class is used to map calls appropriately.
  * @ignore
  */
 Ext.define('Ext.grid.LockingView', {
-    
+
     mixins: {
         observable: 'Ext.util.Observable'
     },
-    
+
     eventRelayRe: /^(beforeitem|beforecontainer|item|container|cell)/,
-    
+
     constructor: function(config){
         var me = this,
             eventNames = [],
@@ -86689,7 +90457,7 @@ Ext.define('Ext.grid.LockingView', {
             normal = config.normal.getView(),
             events,
             event;
-        
+
         Ext.apply(me, {
             lockedView: locked,
             normalView: normal,
@@ -86698,7 +90466,7 @@ Ext.define('Ext.grid.LockingView', {
             panel: config.panel
         });
         me.mixins.observable.constructor.call(me, config);
-        
+
         // relay events
         events = locked.events;
         for (event in events) {
@@ -86708,49 +90476,49 @@ Ext.define('Ext.grid.LockingView', {
         }
         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;
@@ -86759,12 +90527,12 @@ Ext.define('Ext.grid.LockingView', {
             other.highlightItem(item);
         }
     },
-    
+
     onItemMouseLeave: function(view, record){
         var me = this,
             locked = me.lockedView,
             other = me.normalView;
-            
+
         if (view.trackOver) {
             if (view !== locked) {
                 other = locked;
@@ -86772,37 +90540,37 @@ Ext.define('Ext.grid.LockingView', {
             other.clearHighlight();
         }
     },
-    
+
     relayFn: function(name, args){
         args = args || [];
-        
+
         var view = this.lockedView;
-        view[name].apply(view, args || []);    
+        view[name].apply(view, args || []);
         view = this.normalView;
-        view[name].apply(view, args || []);   
+        view[name].apply(view, args || []);
     },
-    
+
     getSelectionModel: function(){
-        return this.panel.getSelectionModel();    
+        return this.panel.getSelectionModel();
     },
-    
+
     getStore: function(){
         return this.panel.store;
     },
-    
+
     getNode: function(nodeInfo){
         // default to the normal view
         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) {
@@ -86810,31 +90578,31 @@ Ext.define('Ext.grid.LockingView', {
         }
         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);
     }
-       
+
 });
 /**
  * @class Ext.grid.Lockable
@@ -86844,24 +90612,25 @@ Ext.define('Ext.grid.LockingView', {
  * TablePanel subclass such as GridPanel or TreePanel. TablePanel will
  * automatically inject the Ext.grid.Lockable mixin in when one of the
  * these conditions are met:
- * - The TablePanel has the lockable configuration set to true
- * - One of the columns in the TablePanel has locked set to true/false
  *
- * Each TablePanel subclass *must* register an alias. It should have an array
+ *  - The TablePanel has the lockable configuration set to true
+ *  - One of the columns in the TablePanel has locked set to true/false
+ *
+ * Each TablePanel subclass must register an alias. It should have an array
  * of configurations to copy to the 2 separate tablepanel's that will be generated
  * to note what configurations should be copied. These are named normalCfgCopy and
  * lockedCfgCopy respectively.
  *
- * Columns which are locked must specify a fixed width. They do *NOT* support a
+ * Columns which are locked must specify a fixed width. They do NOT support a
  * flex width.
  *
  * Configurations which are specified in this class will be available on any grid or
  * tree which is using the lockable functionality.
  */
 Ext.define('Ext.grid.Lockable', {
-    
+
     requires: ['Ext.grid.LockingView'],
-    
+
     /**
      * @cfg {Boolean} syncRowHeight Synchronize rowHeight between the normal and
      * locked grid view. This is turned on by default. If your grid is guaranteed
@@ -86869,14 +90638,14 @@ Ext.define('Ext.grid.Lockable', {
      * optimize performance.
      */
     syncRowHeight: true,
-    
+
     /**
      * @cfg {String} subGridXType The xtype of the subgrid to specify. If this is
      * not specified lockable will determine the subgrid xtype to create by the
      * following rule. Use the superclasses xtype if the superclass is NOT
      * tablepanel, otherwise use the xtype itself.
      */
-    
+
     /**
      * @cfg {Object} lockedViewConfig A view configuration to be applied to the
      * locked side of the grid. Any conflicting configurations between lockedViewConfig
@@ -86888,14 +90657,16 @@ Ext.define('Ext.grid.Lockable', {
      * normal/unlocked side of the grid. Any conflicting configurations between normalViewConfig
      * and viewConfig will be overwritten by the normalViewConfig.
      */
-    
+
     // private variable to track whether or not the spacer is hidden/visible
     spacerHidden: true,
-    
+
+    headerCounter: 0,
+
     // i8n text
     unlockText: 'Unlock',
     lockText: 'Lock',
-    
+
     determineXTypeToCreate: function() {
         var me = this,
             typeToCreate;
@@ -86907,17 +90678,17 @@ Ext.define('Ext.grid.Lockable', {
                 xtypesLn   = xtypes.length,
                 xtype      = xtypes[xtypesLn - 1],
                 superxtype = xtypes[xtypesLn - 2];
-                
+
             if (superxtype !== 'tablepanel') {
                 typeToCreate = superxtype;
             } else {
                 typeToCreate = xtype;
             }
         }
-        
+
         return typeToCreate;
     },
-    
+
     // injectLockable will be invoked before initComponent's parent class implementation
     // is called, so throughout this method this. are configurations
     injectLockable: function() {
@@ -86955,9 +90726,9 @@ Ext.define('Ext.grid.Lockable', {
             columns,
             lockedHeaderCt,
             normalHeaderCt;
-        
+
         me.addCls(Ext.baseCSSPrefix + 'grid-locked');
-        
+
         // copy appropriate configurations to the respective
         // aggregated tablepanel instances and then delete them
         // from the master tablepanel.
@@ -86969,59 +90740,79 @@ Ext.define('Ext.grid.Lockable', {
         for (i = 0; i < me.lockedCfgCopy.length; i++) {
             delete me[me.lockedCfgCopy[i]];
         }
-        
+
+        me.addEvents(
+            /**
+             * @event lockcolumn
+             * Fires when a column is locked.
+             * @param {Ext.grid.Panel} this The gridpanel.
+             * @param {Ext.grid.column.Column} column The column being locked.
+             */
+            'lockcolumn',
+
+            /**
+             * @event unlockcolumn
+             * Fires when a column is unlocked.
+             * @param {Ext.grid.Panel} this The gridpanel.
+             * @param {Ext.grid.column.Column} column The column being unlocked.
+             */
+            'unlockcolumn'
+        );
+
+        me.addStateEvents(['lockcolumn', 'unlockcolumn']);
+
         me.lockedHeights = [];
         me.normalHeights = [];
-        
+
         columns = me.processColumns(me.columns);
 
-        lockedGrid.width = columns.lockedWidth;
+        lockedGrid.width = columns.lockedWidth + Ext.num(selModel.headerWidth, 0);
         lockedGrid.columns = columns.locked;
         normalGrid.columns = columns.normal;
-        
+
         me.store = Ext.StoreManager.lookup(me.store);
         lockedGrid.store = me.store;
         normalGrid.store = me.store;
-        
+
         // normal grid should flex the rest of the width
         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.normalGrid = Ext.ComponentManager.create(normalGrid);
         me.lockedGrid = Ext.ComponentManager.create(lockedGrid);
-        
+
         me.view = Ext.create('Ext.grid.LockingView', {
             locked: me.lockedGrid,
             normal: me.normalGrid,
-            panel: me    
+            panel: me
         });
-        
+
         if (me.syncRowHeight) {
             me.lockedGrid.getView().on({
                 refresh: me.onLockedGridAfterRefresh,
                 itemupdate: me.onLockedGridAfterUpdate,
                 scope: me
             });
-            
+
             me.normalGrid.getView().on({
                 refresh: me.onNormalGridAfterRefresh,
                 itemupdate: me.onNormalGridAfterUpdate,
                 scope: me
             });
         }
-        
+
         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,
@@ -87030,39 +90821,42 @@ Ext.define('Ext.grid.Lockable', {
             columnresize: me.onLockedHeaderResize,
             scope: me
         });
-        
+
         normalHeaderCt.on({
             columnmove: me.onNormalHeaderMove,
             sortchange: me.onNormalHeaderSortChange,
             scope: me
         });
-        
+
         me.normalGrid.on({
             scrollershow: me.onScrollerShow,
             scrollerhide: me.onScrollerHide,
             scope: me
         });
-        
+
         me.lockedGrid.on('afterlayout', me.onLockedGridAfterLayout, me, {single: true});
-        
+
         me.modifyHeaderCt();
         me.items = [me.lockedGrid, me.normalGrid];
 
+        me.relayHeaderCtEvents(lockedHeaderCt);
+        me.relayHeaderCtEvents(normalHeaderCt);
+
         me.layout = {
             type: 'hbox',
             align: 'stretch'
         };
     },
-    
+
     processColumns: function(columns){
         // split apart normal and lockedWidths
         var i = 0,
             len = columns.length,
-            lockedWidth = 0,
+            lockedWidth = 1,
             lockedHeaders = [],
             normalHeaders = [],
             column;
-            
+
         for (; i < len; ++i) {
             column = columns[i];
             // mark the column as processed so that the locked attribute does not
@@ -87074,60 +90868,71 @@ Ext.define('Ext.grid.Lockable', {
                     Ext.Error.raise("Columns which are locked do NOT support a flex width. You must set a width on the " + columns[i].text + "column.");
                 }
                 // </debug>
-                lockedWidth += column.width;
+                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: lockedHeaders,
-            normal: normalHeaders    
+            normal: normalHeaders
         };
     },
-    
+
     // create a new spacer after the table is refreshed
     onLockedGridAfterLayout: function() {
         var me         = this,
             lockedView = me.lockedGrid.getView();
         lockedView.on({
-            refresh: me.createSpacer,
             beforerefresh: me.destroySpacer,
             scope: me
         });
     },
-    
+
     // trigger a pseudo refresh on the normal side
     onLockedHeaderMove: function() {
         if (this.syncRowHeight) {
             this.onNormalGridAfterRefresh();
         }
     },
-    
+
     // trigger a pseudo refresh on the locked side
     onNormalHeaderMove: function() {
         if (this.syncRowHeight) {
             this.onLockedGridAfterRefresh();
         }
     },
-    
+
     // create a spacer in lockedsection and store a reference
     // TODO: Should destroy before refreshing content
-    createSpacer: function() {
+    getSpacerEl: function() {
         var me   = this,
+            w,
+            view,
+            el;
+
+        if (!me.spacerEl) {
             // This affects scrolling all the way to the bottom of a locked grid
             // additional test, sort a column and make sure it synchronizes
-            w    = Ext.getScrollBarWidth() + (Ext.isIE ? 2 : 0),
-            view = me.lockedGrid.getView(),
+            w    = Ext.getScrollBarWidth() + (Ext.isIE ? 2 : 0);
+            view = me.lockedGrid.getView();
             el   = view.el;
 
-        me.spacerEl = Ext.core.DomHelper.append(el, {
-            cls: me.spacerHidden ? (Ext.baseCSSPrefix + 'hidden') : '',
-            style: 'height: ' + w + 'px;'
-        }, true);
+            me.spacerEl = Ext.DomHelper.append(el, {
+                cls: me.spacerHidden ? (Ext.baseCSSPrefix + 'hidden') : '',
+                style: 'height: ' + w + 'px;'
+            }, true);
+        }
+        return me.spacerEl;
     },
-    
+
     destroySpacer: function() {
         var me = this;
         if (me.spacerEl) {
@@ -87135,7 +90940,7 @@ Ext.define('Ext.grid.Lockable', {
             delete me.spacerEl;
         }
     },
-    
+
     // cache the heights of all locked rows and sync rowheights
     onLockedGridAfterRefresh: function() {
         var me     = this,
@@ -87144,16 +90949,16 @@ Ext.define('Ext.grid.Lockable', {
             rowEls = el.query(view.getItemSelector()),
             ln     = rowEls.length,
             i = 0;
-            
+
         // reset heights each time.
         me.lockedHeights = [];
-        
+
         for (; i < ln; i++) {
             me.lockedHeights[i] = rowEls[i].clientHeight;
         }
         me.syncRowHeights();
     },
-    
+
     // cache the heights of all normal rows and sync rowheights
     onNormalGridAfterRefresh: function() {
         var me     = this,
@@ -87162,28 +90967,28 @@ Ext.define('Ext.grid.Lockable', {
             rowEls = el.query(view.getItemSelector()),
             ln     = rowEls.length,
             i = 0;
-            
+
         // reset heights each time.
         me.normalHeights = [];
-        
+
         for (; i < ln; i++) {
             me.normalHeights[i] = rowEls[i].clientHeight;
         }
         me.syncRowHeights();
     },
-    
+
     // rows can get bigger/smaller
     onLockedGridAfterUpdate: function(record, index, node) {
         this.lockedHeights[index] = node.clientHeight;
         this.syncRowHeights();
     },
-    
+
     // rows can get bigger/smaller
     onNormalGridAfterUpdate: function(record, index, node) {
         this.normalHeights[index] = node.clientHeight;
         this.syncRowHeights();
     },
-    
+
     // match the rowheights to the biggest rowheight on either
     // side
     syncRowHeights: function() {
@@ -87220,9 +91025,9 @@ Ext.define('Ext.grid.Lockable', {
 
             // invalidate the scroller and sync the scrollers
             me.normalGrid.invalidateScroller();
-            
+
             // synchronize the view with the scroller, if we have a virtualScrollTop
-            // then the user is using a PagingScroller 
+            // then the user is using a PagingScroller
             if (vertScroller && vertScroller.setViewScrollTop) {
                 vertScroller.setViewScrollTop(me.virtualScrollTop);
             } else {
@@ -87233,55 +91038,56 @@ Ext.define('Ext.grid.Lockable', {
                 normalView.el.dom.scrollTop = scrollTop;
                 lockedView.el.dom.scrollTop = scrollTop;
             }
-            
+
             // reset the heights
             me.lockedHeights = [];
             me.normalHeights = [];
         }
     },
-    
+
     // track when scroller is shown
     onScrollerShow: function(scroller, direction) {
         if (direction === 'horizontal') {
             this.spacerHidden = false;
-            this.spacerEl.removeCls(Ext.baseCSSPrefix + 'hidden');
+            this.getSpacerEl().removeCls(Ext.baseCSSPrefix + 'hidden');
         }
     },
-    
+
     // track when scroller is hidden
     onScrollerHide: function(scroller, direction) {
         if (direction === 'horizontal') {
             this.spacerHidden = true;
-            this.spacerEl.addCls(Ext.baseCSSPrefix + 'hidden');
+            if (this.spacerEl) {
+                this.spacerEl.addCls(Ext.baseCSSPrefix + 'hidden');
+            }
         }
     },
 
-    
+
     // inject Lock and Unlock text
     modifyHeaderCt: function() {
         var me = this;
         me.lockedGrid.headerCt.getMenuItems = me.getMenuItems(true);
         me.normalGrid.headerCt.getMenuItems = me.getMenuItems(false);
     },
-    
+
     onUnlockMenuClick: function() {
         this.unlock();
     },
-    
+
     onLockMenuClick: function() {
         this.lock();
     },
-    
+
     getMenuItems: function(locked) {
         var me            = this,
             unlockText    = me.unlockText,
             lockText      = me.lockText,
-            // TODO: Refactor to use Ext.baseCSSPrefix
-            unlockCls     = 'xg-hmenu-unlock',
-            lockCls       = 'xg-hmenu-lock',
+            unlockCls     = Ext.baseCSSPrefix + 'hmenu-unlock',
+            lockCls       = Ext.baseCSSPrefix + 'hmenu-lock',
             unlockHandler = Ext.Function.bind(me.onUnlockMenuClick, me),
             lockHandler   = Ext.Function.bind(me.onLockMenuClick, me);
-        
+
         // runs in the scope of headerCt
         return function() {
             var o = Ext.grid.header.Container.prototype.getMenuItems.call(this);
@@ -87300,7 +91106,7 @@ Ext.define('Ext.grid.Lockable', {
             return o;
         };
     },
-    
+
     // going from unlocked section to locked
     /**
      * Locks the activeHeader as determined by which menu is open OR a header
@@ -87315,18 +91121,19 @@ Ext.define('Ext.grid.Lockable', {
             lockedGrid = me.lockedGrid,
             normalHCt  = normalGrid.headerCt,
             lockedHCt  = lockedGrid.headerCt;
-            
+
         activeHd = activeHd || normalHCt.getMenu().activeHeader;
-        
+
         // if column was previously flexed, get/set current width
         // and remove the flex
         if (activeHd.flex) {
             activeHd.width = activeHd.getWidth();
             delete activeHd.flex;
         }
-        
+
         normalHCt.remove(activeHd, false);
         lockedHCt.suspendLayout = true;
+        activeHd.locked = true;
         if (Ext.isDefined(toIdx)) {
             lockedHCt.insert(toIdx, activeHd);
         } else {
@@ -87334,35 +91141,38 @@ Ext.define('Ext.grid.Lockable', {
         }
         lockedHCt.suspendLayout = false;
         me.syncLockedSection();
+
+        me.fireEvent('lockcolumn', me, activeHd);
     },
-    
+
     syncLockedSection: function() {
         var me = this;
         me.syncLockedWidth();
         me.lockedGrid.getView().refresh();
         me.normalGrid.getView().refresh();
     },
-    
+
     // adjust the locked section to the width of its respective
     // headerCt
     syncLockedWidth: function() {
         var me = this,
             width = me.lockedGrid.headerCt.getFullWidth(true);
-        me.lockedGrid.setWidth(width);
+        me.lockedGrid.setWidth(width+1); // +1 for border pixel
+        me.doComponentLayout();
     },
-    
+
     onLockedHeaderResize: function() {
         this.syncLockedWidth();
     },
-    
+
     onLockedHeaderHide: function() {
         this.syncLockedWidth();
     },
-    
+
     onLockedHeaderShow: function() {
         this.syncLockedWidth();
     },
-    
+
     onLockedHeaderSortChange: function(headerCt, header, sortState) {
         if (sortState) {
             // no real header, and silence the event so we dont get into an
@@ -87370,7 +91180,7 @@ Ext.define('Ext.grid.Lockable', {
             this.normalGrid.headerCt.clearOtherSortStates(null, true);
         }
     },
-    
+
     onNormalHeaderSortChange: function(headerCt, header, sortState) {
         if (sortState) {
             // no real header, and silence the event so we dont get into an
@@ -87378,7 +91188,7 @@ Ext.define('Ext.grid.Lockable', {
             this.lockedGrid.headerCt.clearOtherSortStates(null, true);
         }
     },
-    
+
     // going from locked section to unlocked
     /**
      * Unlocks the activeHeader as determined by which menu is open OR a header
@@ -87398,30 +91208,97 @@ Ext.define('Ext.grid.Lockable', {
             toIdx = 0;
         }
         activeHd = activeHd || lockedHCt.getMenu().activeHeader;
-        
+
         lockedHCt.remove(activeHd, false);
         me.syncLockedWidth();
         me.lockedGrid.getView().refresh();
+        activeHd.locked = false;
         normalHCt.insert(toIdx, activeHd);
         me.normalGrid.getView().refresh();
+
+        me.fireEvent('unlockcolumn', me, activeHd);
     },
-    
+
+    applyColumnsState: function (columns) {
+        var me = this,
+            lockedGrid = me.lockedGrid,
+            lockedHeaderCt = lockedGrid.headerCt,
+            normalHeaderCt = me.normalGrid.headerCt,
+            lockedCols = lockedHeaderCt.items,
+            normalCols = normalHeaderCt.items,
+            existing,
+            locked = [],
+            normal = [],
+            lockedDefault,
+            lockedWidth = 1;
+
+        Ext.each(columns, function (col) {
+            function matches (item) {
+                return item.headerId == col.id;
+            }
+
+            lockedDefault = true;
+            if (!(existing = lockedCols.findBy(matches))) {
+                existing = normalCols.findBy(matches);
+                lockedDefault = false;
+            }
+
+            if (existing) {
+                if (existing.applyColumnState) {
+                    existing.applyColumnState(col);
+                }
+                if (!Ext.isDefined(existing.locked)) {
+                    existing.locked = lockedDefault;
+                }
+                if (existing.locked) {
+                    locked.push(existing);
+                    if (!existing.hidden && Ext.isNumber(existing.width)) {
+                        lockedWidth += existing.width;
+                    }
+                } else {
+                    normal.push(existing);
+                }
+            }
+        });
+
+        // state and config must have the same columns (compare counts for now):
+        if (locked.length + normal.length == lockedCols.getCount() + normalCols.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);
+    },
+
     // we want to totally override the reconfigure behaviour here, since we're creating 2 sub-grids
     reconfigureLockable: function(store, columns) {
         var me = this,
             lockedGrid = me.lockedGrid,
             normalGrid = me.normalGrid;
-        
+
         if (columns) {
+            lockedGrid.headerCt.suspendLayout = true;
+            normalGrid.headerCt.suspendLayout = true;
             lockedGrid.headerCt.removeAll();
             normalGrid.headerCt.removeAll();
-            
+
             columns = me.processColumns(columns);
             lockedGrid.setWidth(columns.lockedWidth);
             lockedGrid.headerCt.add(columns.locked);
             normalGrid.headerCt.add(columns.normal);
         }
-        
+
         if (store) {
             store = Ext.data.StoreManager.lookup(store);
             me.store = store;
@@ -87431,23 +91308,25 @@ Ext.define('Ext.grid.Lockable', {
             lockedGrid.getView().refresh();
             normalGrid.getView().refresh();
         }
+
+        if (columns) {
+            lockedGrid.headerCt.suspendLayout = false;
+            normalGrid.headerCt.suspendLayout = false;
+            lockedGrid.headerCt.forceComponentLayout();
+            normalGrid.headerCt.forceComponentLayout();
+        }
     }
 });
 
 /**
- * @class Ext.grid.Scroller
- * @extends Ext.Component
- *
  * Docked in an Ext.grid.Panel, controls virtualized scrolling and synchronization
  * across different sections.
- *
- * @private
  */
 Ext.define('Ext.grid.Scroller', {
     extend: 'Ext.Component',
     alias: 'widget.gridscroller',
     weight: 110,
-    cls: Ext.baseCSSPrefix + 'scroller',
+    baseCls: Ext.baseCSSPrefix + 'scroller',
     focusable: false,
     reservedSpace: 0,
 
@@ -87460,23 +91339,21 @@ Ext.define('Ext.grid.Scroller', {
     initComponent: function() {
         var me       = this,
             dock     = me.dock,
-            cls      = Ext.baseCSSPrefix + 'scroller-vertical',
-            sizeProp = 'width';
+            cls      = Ext.baseCSSPrefix + 'scroller-vertical';
 
         me.offsets = {bottom: 0};
         me.scrollProp = 'scrollTop';
         me.vertical = true;
+        me.sizeProp = 'width';
 
         if (dock === 'top' || dock === 'bottom') {
             cls = Ext.baseCSSPrefix + 'scroller-horizontal';
-            sizeProp = 'height';
+            me.sizeProp = 'height';
             me.scrollProp = 'scrollLeft';
             me.vertical = false;
             me.weight += 5;
         }
 
-        me[sizeProp] = me.scrollerSize = Ext.getScrollbarSize()[sizeProp];
-
         me.cls += (' ' + cls);
 
         Ext.applyIf(me.renderSelectors, {
@@ -87485,6 +91362,13 @@ Ext.define('Ext.grid.Scroller', {
         });
         me.callParent();
     },
+    
+    ensureDimension: function(){
+        var me = this,
+            sizeProp = me.sizeProp;
+            
+        me[sizeProp] = me.scrollerSize = Ext.getScrollbarSize()[sizeProp];  
+    },
 
     initRenderData: function () {
         var me = this,
@@ -87712,8 +91596,6 @@ Ext.define('Ext.grid.Scroller', {
 /**
  * @class Ext.grid.PagingScroller
  * @extends Ext.grid.Scroller
- *
- * @private
  */
 Ext.define('Ext.grid.PagingScroller', {
     extend: 'Ext.grid.Scroller',
@@ -87749,8 +91631,8 @@ Ext.define('Ext.grid.PagingScroller', {
         var me = this,
             ds = me.store;
 
-        ds.on('guaranteedrange', this.onGuaranteedRange, this);
-        this.callParent(arguments);
+        ds.on('guaranteedrange', me.onGuaranteedRange, me);
+        me.callParent(arguments);
     },
 
     onGuaranteedRange: function(range, start, end) {
@@ -87768,12 +91650,15 @@ Ext.define('Ext.grid.PagingScroller', {
             if (me.rendered) {
                 me.invalidate();
             } else {
-                me.on('afterrender', this.invalidate, this, {single: true});
+                me.on('afterrender', me.invalidate, me, {single: true});
             }
             me.firstLoad = true;
         } else {
             // adjust to visible
-            me.syncTo();
+            // only sync if there is a paging scrollbar element and it has a scroll height (meaning it's currently in the DOM)
+            if (me.scrollEl && me.scrollEl.dom && me.scrollEl.dom.scrollHeight) {
+                me.syncTo();
+            }
         }
     },
 
@@ -87788,6 +91673,7 @@ Ext.define('Ext.grid.PagingScroller', {
             clientHeight  = scrollerElDom.clientHeight,
             scrollTop     = scrollerElDom.scrollTop,
             useMaximum;
+            
 
         // BrowserBug: clientHeight reports 0 in IE9 StrictMode
         // Instead we are using offsetHeight and hardcoding borders
@@ -87823,7 +91709,7 @@ Ext.define('Ext.grid.PagingScroller', {
             guaranteedStart = store.guaranteedStart,
             guaranteedEnd = store.guaranteedEnd,
             totalCount = store.getTotalCount(),
-            numFromEdge = Math.ceil(me.percentageFromEdge * store.pageSize),
+            numFromEdge = Math.ceil(me.percentageFromEdge * pageSize),
             position = t.scrollTop,
             visibleStart = Math.floor(position / me.rowHeight),
             view = panel.down('tableview'),
@@ -87831,30 +91717,41 @@ Ext.define('Ext.grid.PagingScroller', {
             visibleHeight = viewEl.getHeight(),
             visibleAhead = Math.ceil(visibleHeight / me.rowHeight),
             visibleEnd = visibleStart + visibleAhead,
-            prevPage = Math.floor(visibleStart / store.pageSize),
-            nextPage = Math.floor(visibleEnd / store.pageSize) + 2,
-            lastPage = Math.ceil(totalCount / store.pageSize),
-            //requestStart = visibleStart,
-            requestStart = Math.floor(visibleStart / me.snapIncrement) * me.snapIncrement,
+            prevPage = Math.floor(visibleStart / pageSize),
+            nextPage = Math.floor(visibleEnd / pageSize) + 2,
+            lastPage = Math.ceil(totalCount / pageSize),
+            snap = me.snapIncrement,
+            requestStart = Math.floor(visibleStart / snap) * snap,
             requestEnd = requestStart + pageSize - 1,
             activePrefetch = me.activePrefetch;
 
         me.visibleStart = visibleStart;
         me.visibleEnd = visibleEnd;
-
+        
+        
         me.syncScroll = true;
         if (totalCount >= pageSize) {
             // end of request was past what the total is, grab from the end back a pageSize
             if (requestEnd > totalCount - 1) {
-                this.cancelLoad();
+                me.cancelLoad();
                 if (store.rangeSatisfied(totalCount - pageSize, totalCount - 1)) {
                     me.syncScroll = true;
                 }
                 store.guaranteeRange(totalCount - pageSize, totalCount - 1);
             // Out of range, need to reset the current data set
-            } else if (visibleStart < guaranteedStart || visibleEnd > guaranteedEnd) {
+            } else if (visibleStart <= guaranteedStart || visibleEnd > guaranteedEnd) {
+                if (visibleStart <= guaranteedStart) {
+                    // need to scroll up
+                    requestStart -= snap;
+                    requestEnd -= snap;
+                    
+                    if (requestStart < 0) {
+                        requestStart = 0;
+                        requestEnd = pageSize;
+                    }
+                }
                 if (store.rangeSatisfied(requestStart, requestEnd)) {
-                    this.cancelLoad();
+                    me.cancelLoad();
                     store.guaranteeRange(requestStart, requestEnd);
                 } else {
                     store.mask();
@@ -87879,20 +91776,21 @@ Ext.define('Ext.grid.PagingScroller', {
     getSizeCalculation: function() {
         // Use the direct ownerCt here rather than the scrollerOwner
         // because we are calculating widths/heights.
-        var owner = this.ownerGrid,
+        var me     = this,
+            owner  = me.ownerGrid,
             view   = owner.getView(),
-            store  = this.store,
-            dock   = this.dock,
-            elDom  = this.el.dom,
+            store  = me.store,
+            dock   = me.dock,
+            elDom  = me.el.dom,
             width  = 1,
             height = 1;
 
-        if (!this.rowHeight) {
-            this.rowHeight = view.el.down(view.getItemSelector()).getHeight(false, true);
+        if (!me.rowHeight) {
+            me.rowHeight = view.el.down(view.getItemSelector()).getHeight(false, true);
         }
 
         // If the Store is *locally* filtered, use the filtered count from getCount.
-        height = store[(!store.remoteFilter && store.isFiltered()) ? 'getCount' : 'getTotalCount']() * this.rowHeight;
+        height = store[(!store.remoteFilter && store.isFiltered()) ? 'getCount' : 'getTotalCount']() * me.rowHeight;
 
         if (isNaN(width)) {
             width = 1;
@@ -87926,7 +91824,8 @@ Ext.define('Ext.grid.PagingScroller', {
     },
 
     setViewScrollTop: function(scrollTop, useMax) {
-        var owner = this.getPanel(),
+        var me = this,
+            owner = me.getPanel(),
             items = owner.query('tableview'),
             i = 0,
             len = items.length,
@@ -87934,15 +91833,15 @@ Ext.define('Ext.grid.PagingScroller', {
             centerEl,
             calcScrollTop,
             maxScrollTop,
-            scrollerElDom = this.el.dom;
+            scrollerElDom = me.el.dom;
 
         owner.virtualScrollTop = scrollTop;
 
         center = items[1] || items[0];
         centerEl = center.el.dom;
 
-        maxScrollTop = ((owner.store.pageSize * this.rowHeight) - centerEl.clientHeight);
-        calcScrollTop = (scrollTop % ((owner.store.pageSize * this.rowHeight) + 1));
+        maxScrollTop = ((owner.store.pageSize * me.rowHeight) - centerEl.clientHeight);
+        calcScrollTop = (scrollTop % ((owner.store.pageSize * me.rowHeight) + 1));
         if (useMax) {
             calcScrollTop = maxScrollTop;
         }
@@ -87956,11 +91855,11 @@ Ext.define('Ext.grid.PagingScroller', {
         }
     }
 });
+
 /**
- * @class Ext.panel.Table
- * @extends Ext.panel.Panel
  * @author Nicolas Ferrero
- * TablePanel is the basis of both TreePanel and GridPanel.
+ *
+ * TablePanel is the basis of both {@link Ext.tree.Panel TreePanel} and {@link Ext.grid.Panel GridPanel}.
  *
  * TablePanel aggregates:
  *
@@ -87969,7 +91868,6 @@ Ext.define('Ext.grid.PagingScroller', {
  *  - a Store
  *  - Scrollers
  *  - Ext.grid.header.Container
- *
  */
 Ext.define('Ext.panel.Table', {
     extend: 'Ext.panel.Panel',
@@ -87983,64 +91881,124 @@ Ext.define('Ext.panel.Table', {
         'Ext.grid.Lockable'
     ],
 
-    cls: Ext.baseCSSPrefix + 'grid',
+    extraBaseCls: Ext.baseCSSPrefix + 'grid',
     extraBodyCls: Ext.baseCSSPrefix + 'grid-body',
 
     layout: 'fit',
     /**
-     * Boolean to indicate that a view has been injected into the panel.
-     * @property hasView
+     * @property {Boolean} hasView
+     * True to indicate that a view has been injected into the panel.
      */
     hasView: false,
 
     // each panel should dictate what viewType and selType to use
+    /**
+     * @cfg {String} viewType
+     * An xtype of view to use. This is automatically set to 'gridview' by {@link Ext.grid.Panel Grid}
+     * and to 'treeview' by {@link Ext.tree.Panel Tree}.
+     */
     viewType: null,
+
+    /**
+     * @cfg {Object} viewConfig
+     * A config object that will be applied to the grid's UI view. Any of the config options available for
+     * {@link Ext.view.Table} can be specified here. This option is ignored if {@link #view} is specified.
+     */
+
+    /**
+     * @cfg {Ext.view.Table} view
+     * The {@link Ext.view.Table} used by the grid. Use {@link #viewConfig} to just supply some config options to
+     * view (instead of creating an entire View instance).
+     */
+
+    /**
+     * @cfg {String} selType
+     * An xtype of selection model to use. Defaults to 'rowmodel'. This is used to create selection model if just
+     * a config object or nothing at all given in {@link #selModel} config.
+     */
     selType: 'rowmodel',
 
+    /**
+     * @cfg {Ext.selection.Model/Object} selModel
+     * A {@link Ext.selection.Model selection model} instance or config object.  In latter case the {@link #selType}
+     * config option determines to which type of selection model this config is applied.
+     */
+
+    /**
+     * @cfg {Boolean} multiSelect
+     * True to enable 'MULTI' selection mode on selection model. See {@link Ext.selection.Model#mode}.
+     */
+
+    /**
+     * @cfg {Boolean} simpleSelect
+     * True to enable 'SIMPLE' selection mode on selection model. See {@link Ext.selection.Model#mode}.
+     */
+
+    /**
+     * @cfg {Ext.data.Store} store (required)
+     * The {@link Ext.data.Store Store} the grid should use as its data source.
+     */
+
     /**
      * @cfg {Number} scrollDelta
      * Number of pixels to scroll when scrolling with mousewheel.
-     * Defaults to 40.
      */
     scrollDelta: 40,
 
     /**
      * @cfg {String/Boolean} scroll
-     * Valid values are 'both', 'horizontal' or 'vertical'. true implies 'both'. false implies 'none'.
-     * Defaults to true.
+     * Scrollers configuration. Valid values are 'both', 'horizontal' or 'vertical'.
+     * True implies 'both'. False implies 'none'.
      */
     scroll: true,
 
     /**
-     * @cfg {Array} columns
-     * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this grid. Each
-     * column definition provides the header text for the column, and a definition of where the data for that column comes from.
+     * @cfg {Ext.grid.column.Column[]} columns
+     * An array of {@link Ext.grid.column.Column column} definition objects which define all columns that appear in this
+     * grid. Each column definition provides the header text for the column, and a definition of where the data for that
+     * column comes from.
      */
 
     /**
      * @cfg {Boolean} forceFit
-     * Specify as <code>true</code> to force the columns to fit into the available width. Headers are first sized according to configuration, whether that be
-     * a specific width, or flex. Then they are all proportionally changed in width so that the entire content width is used..
+     * Ttrue to force the columns to fit into the available width. Headers are first sized according to configuration,
+     * whether that be a specific width, or flex. Then they are all proportionally changed in width so that the entire
+     * content width is used.
+     */
+
+    /**
+     * @cfg {Ext.grid.feature.Feature[]} features
+     * An array of grid Features to be added to this grid. See {@link Ext.grid.feature.Feature} for usage.
      */
 
     /**
-     * @cfg {Boolean} hideHeaders
-     * Specify as <code>true</code> to hide the headers.
+     * @cfg {Boolean} [hideHeaders=false]
+     * True to hide column headers.
      */
 
     /**
-     * @cfg {Boolean} deferRowRender <P>Defaults to <code>true</code> to enable deferred row rendering.</p>
-     * <p>This allows the GridView to execute a refresh quickly, with the expensive update of the row
-     * structure deferred so that layouts with GridPanels appear, and lay out more quickly.</p>
+     * @cfg {Boolean} deferRowRender
+     * Defaults to true to enable deferred row rendering.
+     *
+     * This allows the View to execute a refresh quickly, with the expensive update of the row structure deferred so
+     * that layouts with GridPanels appear, and lay out more quickly.
      */
 
+     deferRowRender: true,
+     
     /**
      * @cfg {Boolean} sortableColumns
-     * Defaults to <code>true</code>. Set to <code>false</code> to disable column sorting via clicking the
-     * header and via the Sorting menu items.
+     * False to disable column sorting via clicking the header and via the Sorting menu items.
      */
     sortableColumns: true,
 
+    /**
+     * @cfg {Boolean} [enableLocking=false]
+     * True to enable locking support for this grid. Alternatively, locking will also be automatically
+     * enabled if any of the columns in the column configuration contain the locked config option.
+     */
+    enableLocking: false,
+
     verticalScrollDock: 'right',
     verticalScrollerType: 'gridscroller',
 
@@ -88055,19 +92013,19 @@ Ext.define('Ext.panel.Table', {
 
     /**
      * @cfg {Boolean} enableColumnMove
-     * Defaults to <code>true</code>. Set to <code>false</code> to disable column dragging within this grid.
+     * False to disable column dragging within this grid.
      */
     enableColumnMove: true,
 
     /**
      * @cfg {Boolean} enableColumnResize
-     * Defaults to <code>true</code>. Set to <code>false</code> to disable column resizing within this grid.
+     * False to disable column resizing within this grid.
      */
     enableColumnResize: true,
 
     /**
      * @cfg {Boolean} enableColumnHide
-     * Defaults to <code>true</code>. Set to <code>false</code> to disable column hiding within this grid.
+     * False to disable column hiding within this grid.
      */
     enableColumnHide: true,
 
@@ -88076,9 +92034,6 @@ Ext.define('Ext.panel.Table', {
         if (!this.viewType) {
             Ext.Error.raise("You must specify a viewType config.");
         }
-        if (!this.store) {
-            Ext.Error.raise("You must specify a store config");
-        }
         if (this.headers) {
             Ext.Error.raise("The headers config is not supported. Please specify columns instead.");
         }
@@ -88093,19 +92048,13 @@ Ext.define('Ext.panel.Table', {
             view,
             border = me.border;
 
-        // We cannot buffer this because that will wait for the 30msec from afterLayout (or what
-        // ever event triggers it) and we may be in the middle of an animation; that is a bad
-        // time to injectView because it causes a layout (by calling add on the container). A
-        // throttled func will be called immediately on first call and then block subsequent
-        // (rapid fire) calls for 30msec before allowing another call to go through. Similar
-        // results, but the action moves from the trailing edge of the interval to the leading
-        // edge.
-        me.injectView = Ext.Function.createThrottled(me.injectView, 30, me);
-
         if (me.hideHeaders) {
             border = false;
         }
 
+        // Look up the configured Store. If none configured, use the fieldless, empty Store defined in Ext.data.Store.
+        me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store');
+
         // The columns/colModel config may be either a fully instantiated HeaderContainer, or an array of Column definitions, or a config object of a HeaderContainer
         // Either way, we extract a columns property referencing an array of Column definitions.
         if (headerCtCfg instanceof Ext.grid.header.Container) {
@@ -88131,30 +92080,35 @@ Ext.define('Ext.panel.Table', {
 
              // If any of the Column objects contain a locked property, and are not processed, this is a lockable TablePanel, a
              // special view will be injected by the Ext.grid.Lockable mixin, so no processing of .
-             if (Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
+             if (me.enableLocking || Ext.ComponentQuery.query('{locked !== undefined}{processed != true}', me.columns).length) {
                  me.self.mixin('lockable', Ext.grid.Lockable);
                  me.injectLockable();
              }
         }
 
-        me.store = Ext.data.StoreManager.lookup(me.store);
         me.addEvents(
             /**
              * @event reconfigure
-             * Fires after a reconfigure
+             * Fires after a reconfigure.
              * @param {Ext.panel.Table} this
              */
             'reconfigure',
+            /**
+             * @event viewready
+             * Fires when the grid view is available (use this for selecting a default row).
+             * @param {Ext.panel.Table} this
+             */
+            'viewready',
             /**
              * @event scrollerhide
-             * Fires when a scroller is hidden
+             * Fires when a scroller is hidden.
              * @param {Ext.grid.Scroller} scroller
              * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
              */
             'scrollerhide',
             /**
              * @event scrollershow
-             * Fires when a scroller is shown
+             * Fires when a scroller is shown.
              * @param {Ext.grid.Scroller} scroller
              * @param {String} orientation Orientation, can be 'vertical' or 'horizontal'
              */
@@ -88163,6 +92117,9 @@ Ext.define('Ext.panel.Table', {
 
         me.bodyCls = me.bodyCls || '';
         me.bodyCls += (' ' + me.extraBodyCls);
+        
+        me.cls = me.cls || '';
+        me.cls += (' ' + me.extraBaseCls);
 
         // autoScroll is not a valid configuration
         delete me.autoScroll;
@@ -88222,9 +92179,12 @@ Ext.define('Ext.panel.Table', {
                 });
             }
 
-            me.headerCt.on('columnresize', me.onHeaderResize, me);
-            me.relayEvents(me.headerCt, ['columnresize', 'columnmove', 'columnhide', 'columnshow', 'sortchange']);
+            me.headerCt.on('resize', me.onHeaderResize, me);
+            me.relayHeaderCtEvents(me.headerCt);
             me.features = me.features || [];
+            if (!Ext.isArray(me.features)) {
+                me.features = [me.features];
+            }
             me.dockedItems = me.dockedItems || [];
             me.dockedItems.unshift(me.headerCt);
             me.viewConfig = me.viewConfig || {};
@@ -88234,268 +92194,215 @@ Ext.define('Ext.panel.Table', {
             // getView converts viewConfig into a View instance
             view = me.getView();
 
-            if (view) {
-                me.mon(view.store, {
-                    load: me.onStoreLoad,
-                    scope: me
-                });
-                me.mon(view, {
-                    refresh: me.onViewRefresh,
-                    scope: me
-                });
-                this.relayEvents(view, [
-                    /**
-                     * @event beforeitemmousedown
-                     * Fires before the mousedown event on an item is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforeitemmousedown',
-                    /**
-                     * @event beforeitemmouseup
-                     * Fires before the mouseup event on an item is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforeitemmouseup',
-                    /**
-                     * @event beforeitemmouseenter
-                     * Fires before the mouseenter event on an item is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforeitemmouseenter',
-                    /**
-                     * @event beforeitemmouseleave
-                     * Fires before the mouseleave event on an item is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforeitemmouseleave',
-                    /**
-                     * @event beforeitemclick
-                     * Fires before the click event on an item is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforeitemclick',
-                    /**
-                     * @event beforeitemdblclick
-                     * Fires before the dblclick event on an item is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforeitemdblclick',
-                    /**
-                     * @event beforeitemcontextmenu
-                     * Fires before the contextmenu event on an item is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforeitemcontextmenu',
-                    /**
-                     * @event itemmousedown
-                     * Fires when there is a mouse down on an item
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'itemmousedown',
-                    /**
-                     * @event itemmouseup
-                     * Fires when there is a mouse up on an item
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'itemmouseup',
-                    /**
-                     * @event itemmouseenter
-                     * Fires when the mouse enters an item.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'itemmouseenter',
-                    /**
-                     * @event itemmouseleave
-                     * Fires when the mouse leaves an item.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'itemmouseleave',
-                    /**
-                     * @event itemclick
-                     * Fires when an item is clicked.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'itemclick',
-                    /**
-                     * @event itemdblclick
-                     * Fires when an item is double clicked.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'itemdblclick',
-                    /**
-                     * @event itemcontextmenu
-                     * Fires when an item is right clicked.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.data.Model} record The record that belongs to the item
-                     * @param {HTMLElement} item The item's element
-                     * @param {Number} index The item's index
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'itemcontextmenu',
-                    /**
-                     * @event beforecontainermousedown
-                     * Fires before the mousedown event on the container is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforecontainermousedown',
-                    /**
-                     * @event beforecontainermouseup
-                     * Fires before the mouseup event on the container is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforecontainermouseup',
-                    /**
-                     * @event beforecontainermouseover
-                     * Fires before the mouseover event on the container is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforecontainermouseover',
-                    /**
-                     * @event beforecontainermouseout
-                     * Fires before the mouseout event on the container is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforecontainermouseout',
-                    /**
-                     * @event beforecontainerclick
-                     * Fires before the click event on the container is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforecontainerclick',
-                    /**
-                     * @event beforecontainerdblclick
-                     * Fires before the dblclick event on the container is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforecontainerdblclick',
-                    /**
-                     * @event beforecontainercontextmenu
-                     * Fires before the contextmenu event on the container is processed. Returns false to cancel the default action.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'beforecontainercontextmenu',
-                    /**
-                     * @event containermouseup
-                     * Fires when there is a mouse up on the container
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'containermouseup',
-                    /**
-                     * @event containermouseover
-                     * Fires when you move the mouse over the container.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'containermouseover',
-                    /**
-                     * @event containermouseout
-                     * Fires when you move the mouse out of the container.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'containermouseout',
-                    /**
-                     * @event containerclick
-                     * Fires when the container is clicked.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'containerclick',
-                    /**
-                     * @event containerdblclick
-                     * Fires when the container is double clicked.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'containerdblclick',
-                    /**
-                     * @event containercontextmenu
-                     * Fires when the container is right clicked.
-                     * @param {Ext.view.View} this
-                     * @param {Ext.EventObject} e The raw event object
-                     */
-                    'containercontextmenu',
+            view.on({
+                afterrender: function () {
+                    // hijack the view el's scroll method
+                    view.el.scroll = Ext.Function.bind(me.elScroll, me);
+                    // We use to listen to document.body wheel events, but that's a
+                    // little much. We scope just to the view now.
+                    me.mon(view.el, {
+                        mousewheel: me.onMouseWheel,
+                        scope: me
+                    });
+                },
+                single: true
+            });
+            me.items = [view];
+            me.hasView = true;
 
-                    /**
-                     * @event selectionchange
-                     * Fires when the selected nodes change. Relayed event from the underlying selection model.
-                     * @param {Ext.view.View} this
-                     * @param {Array} selections Array of the selected nodes
-                     */
-                    'selectionchange',
-                    /**
-                     * @event beforeselect
-                     * Fires before a selection is made. If any handlers return false, the selection is cancelled.
-                     * @param {Ext.view.View} this
-                     * @param {HTMLElement} node The node to be selected
-                     * @param {Array} selections Array of currently selected nodes
-                     */
-                    'beforeselect'
-                ]);
-            }
+            me.mon(view.store, {
+                load: me.onStoreLoad,
+                scope: me
+            });
+            me.mon(view, {
+                viewReady: me.onViewReady,
+                resize: me.onViewResize,
+                refresh: {
+                    fn: me.onViewRefresh,
+                    scope: me,
+                    buffer: 50
+                },
+                scope: me
+            });
+            this.relayEvents(view, [
+                /**
+                 * @event beforeitemmousedown
+                 * @alias Ext.view.View#beforeitemmousedown
+                 */
+                'beforeitemmousedown',
+                /**
+                 * @event beforeitemmouseup
+                 * @alias Ext.view.View#beforeitemmouseup
+                 */
+                'beforeitemmouseup',
+                /**
+                 * @event beforeitemmouseenter
+                 * @alias Ext.view.View#beforeitemmouseenter
+                 */
+                'beforeitemmouseenter',
+                /**
+                 * @event beforeitemmouseleave
+                 * @alias Ext.view.View#beforeitemmouseleave
+                 */
+                'beforeitemmouseleave',
+                /**
+                 * @event beforeitemclick
+                 * @alias Ext.view.View#beforeitemclick
+                 */
+                'beforeitemclick',
+                /**
+                 * @event beforeitemdblclick
+                 * @alias Ext.view.View#beforeitemdblclick
+                 */
+                'beforeitemdblclick',
+                /**
+                 * @event beforeitemcontextmenu
+                 * @alias Ext.view.View#beforeitemcontextmenu
+                 */
+                'beforeitemcontextmenu',
+                /**
+                 * @event itemmousedown
+                 * @alias Ext.view.View#itemmousedown
+                 */
+                'itemmousedown',
+                /**
+                 * @event itemmouseup
+                 * @alias Ext.view.View#itemmouseup
+                 */
+                'itemmouseup',
+                /**
+                 * @event itemmouseenter
+                 * @alias Ext.view.View#itemmouseenter
+                 */
+                'itemmouseenter',
+                /**
+                 * @event itemmouseleave
+                 * @alias Ext.view.View#itemmouseleave
+                 */
+                'itemmouseleave',
+                /**
+                 * @event itemclick
+                 * @alias Ext.view.View#itemclick
+                 */
+                'itemclick',
+                /**
+                 * @event itemdblclick
+                 * @alias Ext.view.View#itemdblclick
+                 */
+                'itemdblclick',
+                /**
+                 * @event itemcontextmenu
+                 * @alias Ext.view.View#itemcontextmenu
+                 */
+                'itemcontextmenu',
+                /**
+                 * @event beforecontainermousedown
+                 * @alias Ext.view.View#beforecontainermousedown
+                 */
+                'beforecontainermousedown',
+                /**
+                 * @event beforecontainermouseup
+                 * @alias Ext.view.View#beforecontainermouseup
+                 */
+                'beforecontainermouseup',
+                /**
+                 * @event beforecontainermouseover
+                 * @alias Ext.view.View#beforecontainermouseover
+                 */
+                'beforecontainermouseover',
+                /**
+                 * @event beforecontainermouseout
+                 * @alias Ext.view.View#beforecontainermouseout
+                 */
+                'beforecontainermouseout',
+                /**
+                 * @event beforecontainerclick
+                 * @alias Ext.view.View#beforecontainerclick
+                 */
+                'beforecontainerclick',
+                /**
+                 * @event beforecontainerdblclick
+                 * @alias Ext.view.View#beforecontainerdblclick
+                 */
+                'beforecontainerdblclick',
+                /**
+                 * @event beforecontainercontextmenu
+                 * @alias Ext.view.View#beforecontainercontextmenu
+                 */
+                'beforecontainercontextmenu',
+                /**
+                 * @event containermouseup
+                 * @alias Ext.view.View#containermouseup
+                 */
+                'containermouseup',
+                /**
+                 * @event containermouseover
+                 * @alias Ext.view.View#containermouseover
+                 */
+                'containermouseover',
+                /**
+                 * @event containermouseout
+                 * @alias Ext.view.View#containermouseout
+                 */
+                'containermouseout',
+                /**
+                 * @event containerclick
+                 * @alias Ext.view.View#containerclick
+                 */
+                'containerclick',
+                /**
+                 * @event containerdblclick
+                 * @alias Ext.view.View#containerdblclick
+                 */
+                'containerdblclick',
+                /**
+                 * @event containercontextmenu
+                 * @alias Ext.view.View#containercontextmenu
+                 */
+                'containercontextmenu',
+                /**
+                 * @event selectionchange
+                 * @alias Ext.selection.Model#selectionchange
+                 */
+                'selectionchange',
+                /**
+                 * @event beforeselect
+                 * @alias Ext.selection.RowModel#beforeselect
+                 */
+                'beforeselect',
+                /**
+                 * @event select
+                 * @alias Ext.selection.RowModel#select
+                 */
+                'select',
+                /**
+                 * @event beforedeselect
+                 * @alias Ext.selection.RowModel#beforedeselect
+                 */
+                'beforedeselect',
+                /**
+                 * @event deselect
+                 * @alias Ext.selection.RowModel#deselect
+                 */
+                'deselect'
+            ]);
         }
+
         me.callParent(arguments);
     },
+    
+    onRender: function(){
+        var vScroll = this.verticalScroller,
+            hScroll = this.horizontalScroller;
+
+        if (vScroll) {
+            vScroll.ensureDimension();
+        }
+        if (hScroll) {
+            hScroll.ensureDimension();
+        }
+        this.callParent(arguments);    
+    },
 
     // state management
     initStateEvents: function(){
@@ -88540,40 +92447,42 @@ Ext.define('Ext.panel.Table', {
         return ret;
     },
 
-    getState: function(){
-        var state = this.callParent(),
-            sorter = this.store.sorters.first(),
-            headers = this.headerCt.items.items,
-            header,
-            len = headers.length,
-            i = 0;
+    relayHeaderCtEvents: function (headerCt) {
+        this.relayEvents(headerCt, [
+            /**
+             * @event columnresize
+             * @alias Ext.grid.header.Container#columnresize
+             */
+            'columnresize',
+            /**
+             * @event columnmove
+             * @alias Ext.grid.header.Container#columnmove
+             */
+            'columnmove',
+            /**
+             * @event columnhide
+             * @alias Ext.grid.header.Container#columnhide
+             */
+            'columnhide',
+            /**
+             * @event columnshow
+             * @alias Ext.grid.header.Container#columnshow
+             */
+            'columnshow',
+            /**
+             * @event sortchange
+             * @alias Ext.grid.header.Container#sortchange
+             */
+            'sortchange'
+        ]);
+    },
 
-        state.columns = [];
-        for (; i < len; i++) {
-            header = headers[i];
-            state.columns[i] = {
-                id: header.headerId
-            };
+    getState: function(){
+        var me = this,
+            state = me.callParent(),
+            sorter = me.store.sorters.first();
 
-            // We only store state which has changed from the initial state.
-            // So that current software settings do not override future software settings.
-            // Only user-changed state should be saved.
-            if (header.hidden !== (header.initialConfig.hidden||header.self.prototype.hidden)) {
-                state.columns[i].hidden = header.hidden;
-            }
-            if (header.sortable !== header.initialConfig.sortable) {
-                state.columns[i].sortable = header.sortable;
-            }
-            if (header.flex) {
-                if (header.flex !== header.initialConfig.flex) {
-                    state.columns[i].flex = header.flex;
-                }
-            } else {
-                if (header.width !== header.initialConfig.width) {
-                    state.columns[i].width = header.width;
-                }
-            }
-        }
+        state.columns = (me.headerCt || me).getColumnsState();
 
         if (sorter) {
             state.sort = {
@@ -88581,60 +92490,25 @@ Ext.define('Ext.panel.Table', {
                 direction: sorter.direction
             };
         }
+
         return state;
     },
 
     applyState: function(state) {
-        var headers = state.columns,
-            length = headers ? headers.length : 0,
-            headerCt = this.headerCt,
-            items = headerCt.items,
+        var me = this,
             sorter = state.sort,
-            store = this.store,
-            i = 0,
-            index,
-            headerState,
-            header;
+            store = me.store,
+            columns = state.columns;
 
-        headerCt.suspendLayout = true;
+        delete state.columns;
 
         // Ensure superclass has applied *its* state.
         // AbstractComponent saves dimensions (and anchor/flex) plus collapsed state.
-        this.callParent(arguments);
+        me.callParent(arguments);
 
-        for (; i < length; ++i) {
-            headerState = headers[i];
-            header = headerCt.down('gridcolumn[headerId=' + headerState.id + ']');
-            index = items.indexOf(header);
-            if (i !== index) {
-                headerCt.moveHeader(index, i);
-            }
-
-            // Only state properties which were saved should be restored.
-            // (Only user-changed properties were saved by getState)
-            if (Ext.isDefined(headerState.hidden)) {
-                header.hidden = headerState.hidden;
-            }
-            if (Ext.isDefined(headerState.sortable)) {
-                header.sortable = headerState.sortable;
-            }
-            if (Ext.isDefined(headerState.flex)) {
-                delete header.width;
-                header.flex = headerState.flex;
-            } else if (Ext.isDefined(headerState.width)) {
-                delete header.flex;
-                header.minWidth = headerState.width;
-                if (header.rendered) {
-                    header.setWidth(headerState.width);
-                } else {
-                    header.width = headerState.width;
-                }
-            }
+        if (columns) {
+            (me.headerCt || me).applyColumnsState(columns);
         }
-        headerCt.suspendLayout = false;
-
-        // After setting width and flexes while layout is suspended, column Container's Container layout needs running.
-        headerCt.doLayout();
 
         if (sorter) {
             if (store.remoteSort) {
@@ -88668,7 +92542,7 @@ Ext.define('Ext.panel.Table', {
         if (!me.view) {
             sm = me.getSelectionModel();
             me.view = me.createComponent(Ext.apply({}, me.viewConfig, {
-                deferRowRender: me.deferRowRender,
+                deferInitialRefresh: me.deferRowRender,
                 xtype: me.viewType,
                 store: me.store,
                 headerCt: me.headerCt,
@@ -88704,71 +92578,33 @@ Ext.define('Ext.panel.Table', {
         if (direction === "up" || direction === "left") {
             distance = -distance;
         }
-
+        
         if (direction === "down" || direction === "up") {
             scroller = me.getVerticalScroller();
-            scroller.scrollByDeltaY(distance);
+            
+            //if the grid does not currently need a vertical scroller don't try to update it (EXTJSIV-3891)
+            if (scroller) {
+                scroller.scrollByDeltaY(distance);
+            }
         } else {
             scroller = me.getHorizontalScroller();
-            scroller.scrollByDeltaX(distance);
-        }
-    },
-
-    /**
-     * @private
-     * Called after this Component has achieved its correct initial size, after all layouts have done their thing.
-     * This is so we can add the View only after the initial size is known. This method is throttled 30ms.
-     */
-    injectView: function() {
-        if (!this.hasView && !this.collapsed) {
-            var me   = this,
-                view = me.getView();
-
-            me.hasView = true;
-            me.add(view);
-
-            function viewReady () {
-                // hijack the view el's scroll method
-                view.el.scroll = Ext.Function.bind(me.elScroll, me);
-                // We use to listen to document.body wheel events, but that's a
-                // little much. We scope just to the view now.
-                me.mon(view.el, {
-                    mousewheel: me.onMouseWheel,
-                    scope: me
-                });
-                if (!me.height) {
-                    me.doComponentLayout();
-                }
-            }
-
-            if (view.rendered) {
-                viewReady();
-            } else {
-                view.on({
-                    afterrender: viewReady,
-                    single: true
-                });
+            
+            //if the grid does not currently need a horizontal scroller don't try to update it (EXTJSIV-3891)
+            if (scroller) {
+                scroller.scrollByDeltaX(distance);
             }
         }
     },
 
-    afterExpand: function() {
-        // TODO - this is *not* called when part of an accordion!
-        this.callParent(arguments);
-        if (!this.hasView) {
-            this.injectView();
-        }
-    },
-
     /**
      * @private
-     * Process UI events from the view. Propagate them to whatever internal Components need to process them
+     * Processes UI events from the view. Propagates them to whatever internal Components need to process them.
      * @param {String} type Event type, eg 'click'
-     * @param {TableView} view TableView Component
-     * @param {HtmlElement} cell Cell HtmlElement the event took place within
+     * @param {Ext.view.Table} view TableView Component
+     * @param {HTMLElement} cell Cell HtmlElement the event took place within
      * @param {Number} recordIndex Index of the associated Store Model (-1 if none)
      * @param {Number} cellIndex Cell index within the row
-     * @param {EventObject} e Original event
+     * @param {Ext.EventObject} e Original event
      */
     processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
         var me = this,
@@ -88781,10 +92617,16 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Request a recalculation of scrollbars and put them in if they are needed.
+     * Requests a recalculation of scrollbars and puts them in if they are needed.
      */
     determineScrollbars: function() {
+        // Set a flag so that afterComponentLayout does not recurse back into here.
+        if (this.determineScrollbarsRunning) {
+            return;
+        }
+        this.determineScrollbarsRunning = true;
         var me = this,
+            view = me.view,
             box,
             tableEl,
             scrollWidth,
@@ -88798,11 +92640,12 @@ Ext.define('Ext.panel.Table', {
             reqScrollbars = 0; // 1 = vertical, 2 = horizontal, 3 = both
 
         // If we are not collapsed, and the view has been rendered AND filled, then we can determine scrollbars
-        if (!me.collapsed && me.view && me.view.el && me.view.el.dom.firstChild) {
+        if (!me.collapsed && view && view.viewReady) {
 
             // Calculate maximum, *scrollbarless* space which the view has available.
             // It will be the Fit Layout's calculated size, plus the widths of any currently shown scrollbars
-            box = me.layout.getLayoutTargetSize();
+            box = view.el.getSize();
+
             clientWidth  = box.width  + ((curScrollbars & 1) ? verticalScroller.width : 0);
             clientHeight = box.height + ((curScrollbars & 2) ? horizontalScroller.height : 0);
 
@@ -88815,7 +92658,7 @@ Ext.define('Ext.panel.Table', {
             if (verticalScroller && verticalScroller.el) {
                 scrollHeight = verticalScroller.getSizeCalculation().height;
             } else {
-                tableEl = me.view.el.child('table', true);
+                tableEl = view.el.child('table', true);
                 scrollHeight = tableEl ? tableEl.offsetHeight : 0;
             }
 
@@ -88861,31 +92704,27 @@ Ext.define('Ext.panel.Table', {
                 }
                 me.suspendLayout = false;
 
-                // After docked scrollers are correctly configured, lay out the Component.
-                // Set a flag so that afterComponentLayout does not recurse back into here.
-                me.changingScrollBars = true;
-                me.doComponentLayout(me.getWidth(), me.getHeight(), false, me.ownerCt);
-                me.changingScrollBars = false;
+                // Lay out the Component.
+                me.doComponentLayout();
+                // Lay out me.items
+                me.getLayout().layout();
             }
         }
+        delete me.determineScrollbarsRunning;
     },
 
-    afterComponentLayout: function() {
-        var me = this;
-        me.callParent(arguments);
-
-        // Insert the View the first time the Panel has a Component layout performed.
-        me.injectView();
+    onViewResize: function() {
+        this.determineScrollbars();
+    },
 
-        // Avoid recursion
-        if (!me.changingScrollBars) {
-            me.determineScrollbars();
-        }
-        me.invalidateScroller();
+    afterComponentLayout: function() {
+        this.callParent(arguments);
+        this.determineScrollbars();
+        this.invalidateScroller();
     },
 
     onHeaderResize: function() {
-        if (this.view && this.view.rendered) {
+        if (!this.componentLayout.layoutBusy && this.view && this.view.rendered) {
             this.determineScrollbars();
             this.invalidateScroller();
         }
@@ -88914,7 +92753,7 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Hide the verticalScroller and remove the horizontalScrollerPresentCls.
+     * Hides the verticalScroller and removes the horizontalScrollerPresentCls.
      */
     hideHorizontalScroller: function() {
         var me = this;
@@ -88929,7 +92768,7 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Show the horizontalScroller and add the horizontalScrollerPresentCls.
+     * Shows the horizontalScroller and add the horizontalScrollerPresentCls.
      */
     showHorizontalScroller: function() {
         var me = this;
@@ -88945,7 +92784,7 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Hide the verticalScroller and remove the verticalScrollerPresentCls.
+     * Hides the verticalScroller and removes the verticalScrollerPresentCls.
      */
     hideVerticalScroller: function() {
         var me = this;
@@ -88959,7 +92798,7 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Show the verticalScroller and add the verticalScrollerPresentCls.
+     * Shows the verticalScroller and adds the verticalScrollerPresentCls.
      */
     showVerticalScroller: function() {
         var me = this;
@@ -88979,13 +92818,14 @@ Ext.define('Ext.panel.Table', {
         // only trigger a layout when reserveOffset is changing
         if (layout && layout.reserveOffset !== reserveOffset) {
             layout.reserveOffset = reserveOffset;
-            headerCt.doLayout();
+            if (!this.suspendLayout) {
+                headerCt.doLayout();
+            }
         }
     },
 
     /**
-     * Invalides scrollers that are present and forces a recalculation.
-     * (Not related to showing/hiding the scrollers)
+     * Invalides scrollers that are present and forces a recalculation. (Not related to showing/hiding the scrollers)
      */
     invalidateScroller: function() {
         var me = this,
@@ -89026,7 +92866,7 @@ Ext.define('Ext.panel.Table', {
         var me = this,
             vertScroller = me.getVerticalScroller(),
             horizScroller = me.getHorizontalScroller(),
-            scrollDelta = me.scrollDelta / -5,
+            scrollDelta = -me.scrollDelta,
             deltas = e.getWheelDeltas(),
             deltaX = scrollDelta * deltas.x,
             deltaY = scrollDelta * deltas.y,
@@ -89069,18 +92909,36 @@ Ext.define('Ext.panel.Table', {
 
     /**
      * @private
-     * Determine and invalidate scrollers on view refresh
+     * Fires the TablePanel's viewready event when the view declares that its internal DOM is ready
+     */
+    onViewReady: function() {
+        var me = this;
+        me.fireEvent('viewready', me);
+        if (me.deferRowRender) {
+            me.determineScrollbars();
+            me.invalidateScroller();
+        }
+    },
+
+    /**
+     * @private
+     * Determines and invalidates scrollers on view refresh
      */
     onViewRefresh: function() {
-        this.determineScrollbars();
-        if (this.invalidateScrollerOnRefresh) {
-            this.invalidateScroller();
+        var me = this;
+
+        // Refresh *during* render must be ignored.
+        if (!me.rendering) {
+            this.determineScrollbars();
+            if (this.invalidateScrollerOnRefresh) {
+                this.invalidateScroller();
+            }
         }
     },
 
     /**
      * Sets the scrollTop of the TablePanel.
-     * @param {Number} deltaY
+     * @param {Number} top
      */
     setScrollTop: function(top) {
         var me               = this,
@@ -89115,10 +92973,10 @@ Ext.define('Ext.panel.Table', {
 
     /**
      * Scrolls the TablePanel by deltaX
-     * @param {Number} deltaY
+     * @param {Number} deltaX
      */
     scrollByDeltaX: function(deltaX) {
-        var horizontalScroller = this.getVerticalScroller();
+        var horizontalScroller = this.getHorizontalScroller();
 
         if (horizontalScroller) {
             horizontalScroller.scrollByDeltaX(deltaX);
@@ -89126,14 +92984,14 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Get left hand side marker for header resizing.
+     * Gets left hand side marker for header resizing.
      * @private
      */
     getLhsMarker: function() {
         var me = this;
 
         if (!me.lhsMarker) {
-            me.lhsMarker = Ext.core.DomHelper.append(me.el, {
+            me.lhsMarker = Ext.DomHelper.append(me.el, {
                 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
             }, true);
         }
@@ -89141,14 +92999,14 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Get right hand side marker for header resizing.
+     * Gets right hand side marker for header resizing.
      * @private
      */
     getRhsMarker: function() {
         var me = this;
 
         if (!me.rhsMarker) {
-            me.rhsMarker = Ext.core.DomHelper.append(me.el, {
+            me.rhsMarker = Ext.DomHelper.append(me.el, {
                 cls: Ext.baseCSSPrefix + 'grid-resize-marker'
             }, true);
         }
@@ -89156,8 +93014,7 @@ Ext.define('Ext.panel.Table', {
     },
 
     /**
-     * Returns the selection model being used and creates it via the configuration
-     * if it has not been created already.
+     * Returns the selection model being used and creates it via the configuration if it has not been created already.
      * @return {Ext.selection.Model} selModel
      */
     getSelectionModel: function(){
@@ -89230,12 +93087,20 @@ Ext.define('Ext.panel.Table', {
         me.store = store;
         me.getView().bindStore(store);
     },
+    
+    beforeDestroy: function(){
+        // may be some duplication here since the horizontal and vertical
+        // scroller may be part of the docked items, but we need to clean
+        // them up in case they aren't visible.
+        Ext.destroy(this.horizontalScroller, this.verticalScroller);
+        this.callParent();
+    },
 
     /**
-     * Reconfigure the table with a new store/column.
-     * Either the store or the column can be ommitted if you don't wish to change them.
-     * @param {Ext.data.Store} store The new store.
-     * @param {Array} columns An array of column configs
+     * Reconfigures the table with a new store/columns. Either the store or the columns can be ommitted if you don't wish
+     * to change them.
+     * @param {Ext.data.Store} store (Optional) The new store.
+     * @param {Object[]} columns (Optional) An array of column configs
      */
     reconfigure: function(store, columns) {
         var me = this,
@@ -89244,12 +93109,10 @@ Ext.define('Ext.panel.Table', {
         if (me.lockable) {
             me.reconfigureLockable(store, columns);
         } else {
-            headerCt.suspendLayout = true;
-            headerCt.removeAll();
             if (columns) {
+                headerCt.suspendLayout = true;
+                headerCt.removeAll();
                 headerCt.add(columns);
-            } else {
-                headerCt.doLayout();
             }
             if (store) {
                 store = Ext.StoreManager.lookup(store);
@@ -89258,6 +93121,7 @@ Ext.define('Ext.panel.Table', {
                 me.getView().refresh();
             }
             if (columns) {
+                headerCt.suspendLayout = false;
                 me.forceComponentLayout();
             }
         }
@@ -89265,24 +93129,17 @@ Ext.define('Ext.panel.Table', {
     }
 });
 /**
- * @class Ext.view.Table
- * @extends Ext.view.View
-
-This class encapsulates the user interface for a tabular data set.
-It acts as a centralized manager for controlling the various interface
-elements of the view. This includes handling events, such as row and cell
-level based DOM events. It also reacts to events from the underlying {@link Ext.selection.Model}
-to provide visual feedback to the user.
-
-This class does not provide ways to manipulate the underlying data of the configured
-{@link Ext.data.Store}.
-
-This is the base class for both {@link Ext.grid.View} and {@link Ext.tree.View} and is not
-to be used directly.
-
- * @markdown
- * @abstract
- * @author Nicolas Ferrero
+ * This class encapsulates the user interface for a tabular data set.
+ * It acts as a centralized manager for controlling the various interface
+ * elements of the view. This includes handling events, such as row and cell
+ * level based DOM events. It also reacts to events from the underlying {@link Ext.selection.Model}
+ * to provide visual feedback to the user.
+ *
+ * This class does not provide ways to manipulate the underlying data of the configured
+ * {@link Ext.data.Store}.
+ *
+ * This is the base class for both {@link Ext.grid.View} and {@link Ext.tree.View} and is not
+ * to be used directly.
  */
 Ext.define('Ext.view.Table', {
     extend: 'Ext.view.View',
@@ -89293,7 +93150,7 @@ Ext.define('Ext.view.Table', {
         'Ext.util.MixedCollection'
     ],
 
-    cls: Ext.baseCSSPrefix + 'grid-view',
+    baseCls: Ext.baseCSSPrefix + 'grid-view',
 
     // row
     itemSelector: '.' + Ext.baseCSSPrefix + 'grid-row',
@@ -89312,58 +93169,30 @@ Ext.define('Ext.view.Table', {
     trackOver: true,
 
     /**
-     * Override this function to apply custom CSS classes to rows during rendering.  You can also supply custom
-     * parameters to the row template for the current row to customize how it is rendered using the <b>rowParams</b>
-     * parameter.  This function should return the CSS class name (or empty string '' for none) that will be added
-     * to the row's wrapping div.  To apply multiple class names, simply return them space-delimited within the string
-     * (e.g., 'my-class another-class'). Example usage:
-    <pre><code>
-viewConfig: {
-    forceFit: true,
-    showPreview: true, // custom property
-    enableRowBody: true, // required to create a second, full-width row to show expanded Record data
-    getRowClass: function(record, rowIndex, rp, ds){ // rp = rowParams
-        if(this.showPreview){
-            rp.body = '&lt;p>'+record.data.excerpt+'&lt;/p>';
-            return 'x-grid3-row-expanded';
-        }
-        return 'x-grid3-row-collapsed';
-    }
-},
-    </code></pre>
-     * @param {Model} model The {@link Ext.data.Model} corresponding to the current row.
+     * Override this function to apply custom CSS classes to rows during rendering. This function should return the
+     * CSS class name (or empty string '' for none) that will be added to the row's wrapping div. To apply multiple
+     * class names, simply return them space-delimited within the string (e.g. 'my-class another-class').
+     * Example usage:
+     *
+     *     viewConfig: {
+     *         getRowClass: function(record, rowIndex, rowParams, store){
+     *             return record.get("valid") ? "row-valid" : "row-error";
+     *         }
+     *     }
+     *
+     * @param {Ext.data.Model} record The record corresponding to the current row.
      * @param {Number} index The row index.
-     * @param {Object} rowParams (DEPRECATED) A config object that is passed to the row template during rendering that allows
-     * customization of various aspects of a grid row.
-     * <p>If {@link #enableRowBody} is configured <b><tt></tt>true</b>, then the following properties may be set
-     * by this function, and will be used to render a full-width expansion row below each grid row:</p>
-     * <ul>
-     * <li><code>body</code> : String <div class="sub-desc">An HTML fragment to be used as the expansion row's body content (defaults to '').</div></li>
-     * <li><code>bodyStyle</code> : String <div class="sub-desc">A CSS style specification that will be applied to the expansion row's &lt;tr> element. (defaults to '').</div></li>
-     * </ul>
-     * The following property will be passed in, and may be appended to:
-     * <ul>
-     * <li><code>tstyle</code> : String <div class="sub-desc">A CSS style specification that willl be applied to the &lt;table> element which encapsulates
-     * both the standard grid row, and any expansion row.</div></li>
-     * </ul>
-     * @param {Store} store The {@link Ext.data.Store} this grid is bound to
-     * @method getRowClass
+     * @param {Object} rowParams **DEPRECATED.** For row body use the
+     * {@link Ext.grid.feature.RowBody#getAdditionalData getAdditionalData} method of the rowbody feature.
+     * @param {Ext.data.Store} store The store this grid is bound to
      * @return {String} a CSS class name to add to the row.
+     * @method
      */
     getRowClass: null,
 
     initComponent: function() {
         var me = this;
 
-        if (me.deferRowRender !== false) {
-            me.refresh = function() {
-                delete me.refresh;
-                setTimeout(function() {
-                    me.refresh();
-                }, 0);
-            };
-        }
-
         me.scrollState = {};
         me.selModel.view = me;
         me.headerCt.view = me;
@@ -89378,7 +93207,7 @@ viewConfig: {
         // this.addEvents(
         //     /**
         //      * @event rowfocus
-        //      * @param {Ext.data.Record} record
+        //      * @param {Ext.data.Model} record
         //      * @param {HTMLElement} row
         //      * @param {Number} rowIdx
         //      */
@@ -89437,7 +93266,7 @@ viewConfig: {
     /**
      * Get the cell (td) for a particular record and column.
      * @param {Ext.data.Model} record
-     * @param {Ext.grid.column.Colunm} column
+     * @param {Ext.grid.column.Column} column
      * @private
      */
     getCell: function(record, column) {
@@ -89628,7 +93457,9 @@ viewConfig: {
             el.select('.' + Ext.baseCSSPrefix + 'grid-col-resizer-'+header.id).setWidth(w);
             el.select('.' + Ext.baseCSSPrefix + 'grid-table-resizer').setWidth(me.headerCt.getFullWidth());
             me.restoreScrollState();
-            me.setNewTemplate();
+            if (!me.ignoreTemplate) {
+                me.setNewTemplate();
+            }
             if (!suppressFocus) {
                 me.el.focus();
             }
@@ -89640,17 +93471,20 @@ viewConfig: {
      * @private
      */
     onHeaderShow: function(headerCt, header, suppressFocus) {
+        var me = this;
+        me.ignoreTemplate = true;
         // restore headers that were dynamically hidden
         if (header.oldWidth) {
-            this.onHeaderResize(header, header.oldWidth, suppressFocus);
+            me.onHeaderResize(header, header.oldWidth, suppressFocus);
             delete header.oldWidth;
         // flexed headers will have a calculated size set
         // this additional check has to do with the fact that
         // defaults: {width: 100} will fight with a flex value
         } else if (header.width && !header.flex) {
-            this.onHeaderResize(header, header.width, suppressFocus);
+            me.onHeaderResize(header, header.width, suppressFocus);
         }
-        this.setNewTemplate();
+        delete me.ignoreTemplate;
+        me.setNewTemplate();
     },
 
     /**
@@ -89677,15 +93511,16 @@ viewConfig: {
     },
 
     /**
-     * Get the configured chunker or default of Ext.view.TableChunker
+     * Returns the configured chunker or default of Ext.view.TableChunker
      */
     getTableChunker: function() {
         return this.chunker || Ext.view.TableChunker;
     },
 
     /**
-     * Add a CSS Class to a specific row.
-     * @param {HTMLElement/String/Number/Ext.data.Model} rowInfo An HTMLElement, index or instance of a model representing this row
+     * Adds a CSS Class to a specific row.
+     * @param {HTMLElement/String/Number/Ext.data.Model} rowInfo An HTMLElement, index or instance of a model
+     * representing this row
      * @param {String} cls
      */
     addRowCls: function(rowInfo, cls) {
@@ -89696,8 +93531,9 @@ viewConfig: {
     },
 
     /**
-     * Remove a CSS Class from a specific row.
-     * @param {HTMLElement/String/Number/Ext.data.Model} rowInfo An HTMLElement, index or instance of a model representing this row
+     * Removes a CSS Class from a specific row.
+     * @param {HTMLElement/String/Number/Ext.data.Model} rowInfo An HTMLElement, index or instance of a model
+     * representing this row
      * @param {String} cls
      */
     removeRowCls: function(rowInfo, cls) {
@@ -89774,9 +93610,10 @@ viewConfig: {
     },
 
     /**
-     * Focus a particular row and bring it into view. Will fire the rowfocus event.
-     * @param {Mixed} rowIdx An HTMLElement template node, index of a template node, the
-     * id of a template node or the record associated with the node.
+     * Focuses a particular row and brings it into view. Will fire the rowfocus event.
+     * @param {HTMLElement/String/Number/Ext.data.Model} rowIdx
+     * An HTMLElement template node, index of a template node, the id of a template node or the
+     * record associated with the node.
      */
     focusRow: function(rowIdx) {
         var me         = this,
@@ -89851,7 +93688,7 @@ viewConfig: {
     },
 
     /**
-     * Scroll by delta. This affects this individual view ONLY and does not
+     * Scrolls by delta. This affects this individual view ONLY and does not
      * synchronize across views or scrollers.
      * @param {Number} delta
      * @param {String} dir (optional) Valid values are scrollTop and scrollLeft. Defaults to scrollTop.
@@ -89868,35 +93705,37 @@ viewConfig: {
     },
 
     /**
-     * Save the scrollState in a private variable.
-     * Must be used in conjunction with restoreScrollState
+     * Saves the scrollState in a private variable. Must be used in conjunction with restoreScrollState
      */
     saveScrollState: function() {
-        var dom = this.el.dom,
-            state = this.scrollState;
-
-        state.left = dom.scrollLeft;
-        state.top = dom.scrollTop;
+        if (this.rendered) {
+            var dom = this.el.dom, 
+                state = this.scrollState;
+            
+            state.left = dom.scrollLeft;
+            state.top = dom.scrollTop;
+        }
     },
 
     /**
-     * Restore the scrollState.
+     * Restores the scrollState.
      * Must be used in conjunction with saveScrollState
      * @private
      */
     restoreScrollState: function() {
-        var dom = this.el.dom,
-            state = this.scrollState,
-            headerEl = this.headerCt.el.dom;
-
-        headerEl.scrollLeft = dom.scrollLeft = state.left;
-        dom.scrollTop = state.top;
+        if (this.rendered) {
+            var dom = this.el.dom, 
+                state = this.scrollState, 
+                headerEl = this.headerCt.el.dom;
+            
+            headerEl.scrollLeft = dom.scrollLeft = state.left;
+            dom.scrollTop = state.top;
+        }
     },
 
     /**
-     * Refresh the grid view.
-     * Saves and restores the scroll state, generates a new template, stripes rows
-     * and invalidates the scrollers.
+     * Refreshes the grid view. Saves and restores the scroll state, generates a new template, stripes rows and
+     * invalidates the scrollers.
      */
     refresh: function() {
         this.setNewTemplate();
@@ -90000,7 +93839,7 @@ viewConfig: {
     onBeforeCellKeyDown: Ext.emptyFn,
 
     /**
-     * Expand a particular header to fit the max content width.
+     * Expands a particular header to fit the max content width.
      * This will ONLY expand, not contract.
      * @private
      */
@@ -90013,7 +93852,7 @@ viewConfig: {
     },
 
     /**
-     * Get the max contentWidth of the header's text and all cells
+     * Returns the max contentWidth of the header's text and all cells
      * in the grid under this header.
      * @private
      */
@@ -90055,19 +93894,22 @@ viewConfig: {
     },
 
     /**
-     * @param {Object} position The current row and column: an object containing the following properties:<ul>
-     * <li>row<div class="sub-desc"> The row <b>index</b></div></li>
-     * <li>column<div class="sub-desc">The column <b>index</b></div></li>
-     * </ul>
+     * @param {Object} position The current row and column: an object containing the following properties:
+     *
+     * - row - The row index
+     * - column - The column index
+     *
      * @param {String} direction 'up', 'down', 'right' and 'left'
      * @param {Ext.EventObject} e event
      * @param {Boolean} preventWrap Set to true to prevent wrap around to the next or previous row.
-     * @param {Function} verifierFn A function to verify the validity of the calculated position. When using this function, you must return true to allow the newPosition to be returned.
-     * @param {Scope} scope Scope to run the verifierFn in
-     * @returns {Object} newPosition An object containing the following properties:<ul>
-     * <li>row<div class="sub-desc"> The row <b>index</b></div></li>
-     * <li>column<div class="sub-desc">The column <b>index</b></div></li>
-     * </ul>
+     * @param {Function} verifierFn A function to verify the validity of the calculated position.
+     * When using this function, you must return true to allow the newPosition to be returned.
+     * @param {Object} scope Scope to run the verifierFn in
+     * @returns {Object} newPosition An object containing the following properties:
+     *
+     * - row - The row index
+     * - column - The column index
+     *
      * @private
      */
     walkCells: function(pos, direction, e, preventWrap, verifierFn, scope) {
@@ -90254,50 +94096,49 @@ viewConfig: {
 /**
  * @class Ext.grid.View
  * @extends Ext.view.Table
-
-The grid View class provides extra {@link Ext.grid.Panel} specific functionality to the
-{@link Ext.view.Table}. In general, this class is not instanced directly, instead a viewConfig
-option is passed to the grid:
-
-    Ext.create('Ext.grid.Panel', {
-        // other options
-        viewConfig: {
-            stripeRows: false
-        }
-    });
-    
-__Drag Drop__
-Drag and drop functionality can be achieved in the grid by attaching a {@link Ext.grid.plugin.DragDrop} plugin
-when creating the view.
-
-    Ext.create('Ext.grid.Panel', {
-        // other options
-        viewConfig: {
-            plugins: {
-                ddGroup: 'people-group',
-                ptype: 'gridviewdragdrop',
-                enableDrop: false
-            }
-        }
-    });
-
- * @markdown
+ *
+ * The grid View class provides extra {@link Ext.grid.Panel} specific functionality to the
+ * {@link Ext.view.Table}. In general, this class is not instanced directly, instead a viewConfig
+ * option is passed to the grid:
+ *
+ *     Ext.create('Ext.grid.Panel', {
+ *         // other options
+ *         viewConfig: {
+ *             stripeRows: false
+ *         }
+ *     });
+ *
+ * ## Drag Drop
+ *
+ * Drag and drop functionality can be achieved in the grid by attaching a {@link Ext.grid.plugin.DragDrop} plugin
+ * when creating the view.
+ *
+ *     Ext.create('Ext.grid.Panel', {
+ *         // other options
+ *         viewConfig: {
+ *             plugins: {
+ *                 ddGroup: 'people-group',
+ *                 ptype: 'gridviewdragdrop',
+ *                 enableDrop: false
+ *             }
+ *         }
+ *     });
  */
 Ext.define('Ext.grid.View', {
     extend: 'Ext.view.Table',
     alias: 'widget.gridview',
 
     /**
-     * @cfg {Boolean} stripeRows <tt>true</tt> to stripe the rows. Default is <tt>false</tt>.
+     * @cfg {Boolean} stripeRows <tt>true</tt> to stripe the rows. Default is <tt>true</tt>.
      * <p>This causes the CSS class <tt><b>x-grid-row-alt</b></tt> to be added to alternate rows of
      * the grid. A default CSS rule is provided which sets a background color, but you can override this
      * with a rule which either overrides the <b>background-color</b> style using the '!important'
      * modifier, or which uses a CSS selector of higher specificity.</p>
      */
     stripeRows: true,
-    
+
     invalidateScrollerOnRefresh: true,
-    
+
     /**
      * Scroll the GridView to the top by scrolling the scroller.
      * @private
@@ -90306,7 +94147,7 @@ Ext.define('Ext.grid.View', {
         if (this.rendered) {
             var section = this.ownerCt,
                 verticalScroller = section.verticalScroller;
-                
+
             if (verticalScroller) {
                 verticalScroller.scrollToTop();
             }
@@ -90318,23 +94159,23 @@ Ext.define('Ext.grid.View', {
         this.callParent(arguments);
         this.doStripeRows(index);
     },
-    
+
     // after removing a row stripe rows from then on
     onRemove: function(ds, records, index) {
         this.callParent(arguments);
         this.doStripeRows(index);
     },
-    
+
     onUpdate: function(ds, record, operation) {
         var index = ds.indexOf(record);
         this.callParent(arguments);
         this.doStripeRows(index, index);
     },
-    
+
     /**
      * Stripe rows from a particular row index
      * @param {Number} startRow
-     * @param {Number} endRow Optional argument specifying the last row to process. By default process up to the last row.
+     * @param {Number} endRow (Optional) argument specifying the last row to process. By default process up to the last row.
      * @private
      */
     doStripeRows: function(startRow, endRow) {
@@ -90344,7 +94185,7 @@ Ext.define('Ext.grid.View', {
                 rowsLn = rows.length,
                 i      = 0,
                 row;
-                
+
             for (; i < rowsLn; i++) {
                 row = rows[i];
                 // Remove prior applied row classes.
@@ -90357,7 +94198,7 @@ Ext.define('Ext.grid.View', {
             }
         }
     },
-    
+
     refresh: function(firstPass) {
         this.callParent(arguments);
         this.doStripeRows(0);
@@ -90371,26 +94212,24 @@ Ext.define('Ext.grid.View', {
 
 /**
  * @author Aaron Conran
- * @class Ext.grid.Panel
- * @extends Ext.panel.Table
+ * @docauthor Ed Spencer
  *
- * Grids are an excellent way of showing large amounts of tabular data on the client side. Essentially a supercharged 
+ * Grids are an excellent way of showing large amounts of tabular data on the client side. Essentially a supercharged
  * `<table>`, GridPanel makes it easy to fetch, sort and filter large amounts of data.
- * 
- * Grids are composed of 2 main pieces - a {@link Ext.data.Store Store} full of data and a set of columns to render.
  *
- * {@img Ext.grid.Panel/Ext.grid.Panel1.png Ext.grid.Panel component}
+ * Grids are composed of two main pieces - a {@link Ext.data.Store Store} full of data and a set of columns to render.
  *
  * ## Basic GridPanel
  *
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *         storeId:'simpsonsStore',
  *         fields:['name', 'email', 'phone'],
  *         data:{'items':[
- *             {"name":"Lisa", "email":"lisa@simpsons.com", "phone":"555-111-1224"},
- *             {"name":"Bart", "email":"bart@simpsons.com", "phone":"555--222-1234"},
- *             {"name":"Homer", "email":"home@simpsons.com", "phone":"555-222-1244"},                        
- *             {"name":"Marge", "email":"marge@simpsons.com", "phone":"555-222-1254"}            
+ *             { 'name': 'Lisa',  "email":"lisa@simpsons.com",  "phone":"555-111-1224"  },
+ *             { 'name': 'Bart',  "email":"bart@simpsons.com",  "phone":"555-222-1234" },
+ *             { 'name': 'Homer', "email":"home@simpsons.com",  "phone":"555-222-1244"  },
+ *             { 'name': 'Marge', "email":"marge@simpsons.com", "phone":"555-222-1254"  }
  *         ]},
  *         proxy: {
  *             type: 'memory',
@@ -90400,34 +94239,34 @@ Ext.define('Ext.grid.View', {
  *             }
  *         }
  *     });
- *     
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Simpsons',
  *         store: Ext.data.StoreManager.lookup('simpsonsStore'),
  *         columns: [
- *             {header: 'Name',  dataIndex: 'name'},
- *             {header: 'Email', dataIndex: 'email', flex:1},
- *             {header: 'Phone', dataIndex: 'phone'}
+ *             { header: 'Name',  dataIndex: 'name' },
+ *             { header: 'Email', dataIndex: 'email', flex: 1 },
+ *             { header: 'Phone', dataIndex: 'phone' }
  *         ],
  *         height: 200,
  *         width: 400,
  *         renderTo: Ext.getBody()
  *     });
- * 
- * The code above produces a simple grid with three columns. We specified a Store which will load JSON data inline. 
+ *
+ * The code above produces a simple grid with three columns. We specified a Store which will load JSON data inline.
  * In most apps we would be placing the grid inside another container and wouldn't need to use the
  * {@link #height}, {@link #width} and {@link #renderTo} configurations but they are included here to make it easy to get
  * up and running.
- * 
+ *
  * The grid we created above will contain a header bar with a title ('Simpsons'), a row of column headers directly underneath
  * and finally the grid rows under the headers.
- * 
+ *
  * ## Configuring columns
- * 
+ *
  * By default, each column is sortable and will toggle between ASC and DESC sorting when you click on its header. Each
  * column header is also reorderable by default, and each gains a drop-down menu with options to hide and show columns.
  * It's easy to configure each column - here we use the same example as above and just modify the columns config:
- * 
+ *
  *     columns: [
  *         {
  *             header: 'Name',
@@ -90447,18 +94286,18 @@ Ext.define('Ext.grid.View', {
  *             width: 100
  *         }
  *     ]
- * 
+ *
  * We turned off sorting and hiding on the 'Name' column so clicking its header now has no effect. We also made the Email
  * column hidden by default (it can be shown again by using the menu on any other column). We also set the Phone column to
- * a fixed with of 100px and flexed the Name column, which means it takes up all remaining width after the other columns 
+ * a fixed with of 100px and flexed the Name column, which means it takes up all remaining width after the other columns
  * have been accounted for. See the {@link Ext.grid.column.Column column docs} for more details.
- * 
+ *
  * ## Renderers
- * 
- * As well as customizing columns, it's easy to alter the rendering of individual cells using renderers. A renderer is 
+ *
+ * As well as customizing columns, it's easy to alter the rendering of individual cells using renderers. A renderer is
  * tied to a particular column and is passed the value that would be rendered into each cell in that column. For example,
  * we could define a renderer function for the email column to turn each email address into a mailto link:
- * 
+ *
  *     columns: [
  *         {
  *             header: 'Email',
@@ -90468,48 +94307,46 @@ Ext.define('Ext.grid.View', {
  *             }
  *         }
  *     ]
- * 
+ *
  * See the {@link Ext.grid.column.Column column docs} for more information on renderers.
- * 
+ *
  * ## Selection Models
- * 
- * Sometimes all you want is to render data onto the screen for viewing, but usually it's necessary to interact with or 
+ *
+ * Sometimes all you want is to render data onto the screen for viewing, but usually it's necessary to interact with or
  * update that data. Grids use a concept called a Selection Model, which is simply a mechanism for selecting some part of
  * the data in the grid. The two main types of Selection Model are RowSelectionModel, where entire rows are selected, and
  * CellSelectionModel, where individual cells are selected.
- * 
+ *
  * Grids use a Row Selection Model by default, but this is easy to customise like so:
- * 
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         selType: 'cellmodel',
  *         store: ...
  *     });
- * 
+ *
  * Specifying the `cellmodel` changes a couple of things. Firstly, clicking on a cell now
  * selects just that cell (using a {@link Ext.selection.RowModel rowmodel} will select the entire row), and secondly the
  * keyboard navigation will walk from cell to cell instead of row to row. Cell-based selection models are usually used in
  * conjunction with editing.
- * 
- * {@img Ext.grid.Panel/Ext.grid.Panel2.png Ext.grid.Panel cell editing}
  *
  * ## Editing
- * 
+ *
  * Grid has built-in support for in-line editing. There are two chief editing modes - cell editing and row editing. Cell
  * editing is easy to add to your existing column setup - here we'll just modify the example above to include an editor
  * on both the name and the email columns:
- * 
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Simpsons',
  *         store: Ext.data.StoreManager.lookup('simpsonsStore'),
  *         columns: [
- *             {header: 'Name',  dataIndex: 'name', field: 'textfield'},
- *             {header: 'Email', dataIndex: 'email', flex:1, 
- *                 field:{
- *                     xtype:'textfield',
- *                     allowBlank:false
+ *             { header: 'Name',  dataIndex: 'name', field: 'textfield' },
+ *             { header: 'Email', dataIndex: 'email', flex: 1,
+ *                 field: {
+ *                     xtype: 'textfield',
+ *                     allowBlank: false
  *                 }
  *             },
- *             {header: 'Phone', dataIndex: 'phone'}
+ *             { header: 'Phone', dataIndex: 'phone' }
  *         ],
  *         selType: 'cellmodel',
  *         plugins: [
@@ -90521,36 +94358,34 @@ Ext.define('Ext.grid.View', {
  *         width: 400,
  *         renderTo: Ext.getBody()
  *     });
- * 
- * This requires a little explanation. We're passing in {@link #store store} and {@link #columns columns} as normal, but 
- * this time we've also specified a {@link #field field} on two of our columns. For the Name column we just want a default
- * textfield to edit the value, so we specify 'textfield'. For the Email column we customized the editor slightly by 
- * passing allowBlank: false, which will provide inline validation.
- * 
+ *
+ * This requires a little explanation. We're passing in {@link #store store} and {@link #columns columns} as normal, but
+ * this time we've also specified a {@link Ext.grid.column.Column#field field} on two of our columns. For the Name column
+ * we just want a default textfield to edit the value, so we specify 'textfield'. For the Email column we customized the
+ * editor slightly by passing allowBlank: false, which will provide inline validation.
+ *
  * To support cell editing, we also specified that the grid should use the 'cellmodel' {@link #selType}, and created an
  * instance of the {@link Ext.grid.plugin.CellEditing CellEditing plugin}, which we configured to activate each editor after a
  * single click.
- * 
- * {@img Ext.grid.Panel/Ext.grid.Panel3.png Ext.grid.Panel row editing}
  *
  * ## Row Editing
- * 
+ *
  * The other type of editing is row-based editing, using the RowEditor component. This enables you to edit an entire row
  * at a time, rather than editing cell by cell. Row Editing works in exactly the same way as cell editing, all we need to
  * do is change the plugin type to {@link Ext.grid.plugin.RowEditing}, and set the selType to 'rowmodel':
- * 
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Simpsons',
  *         store: Ext.data.StoreManager.lookup('simpsonsStore'),
  *         columns: [
- *             {header: 'Name',  dataIndex: 'name', field: 'textfield'},
- *             {header: 'Email', dataIndex: 'email', flex:1, 
- *                 field:{
- *                     xtype:'textfield',
- *                     allowBlank:false
+ *             { header: 'Name',  dataIndex: 'name', field: 'textfield' },
+ *             { header: 'Email', dataIndex: 'email', flex:1,
+ *                 field: {
+ *                     xtype: 'textfield',
+ *                     allowBlank: false
  *                 }
  *             },
- *             {header: 'Phone', dataIndex: 'phone'}
+ *             { header: 'Phone', dataIndex: 'phone' }
  *         ],
  *         selType: 'rowmodel',
  *         plugins: [
@@ -90562,51 +94397,52 @@ Ext.define('Ext.grid.View', {
  *         width: 400,
  *         renderTo: Ext.getBody()
  *     });
- * 
+ *
  * Again we passed some configuration to our {@link Ext.grid.plugin.RowEditing} plugin, and now when we click each row a row
  * editor will appear and enable us to edit each of the columns we have specified an editor for.
- * 
+ *
  * ## Sorting & Filtering
- * 
+ *
  * Every grid is attached to a {@link Ext.data.Store Store}, which provides multi-sort and filtering capabilities. It's
  * easy to set up a grid to be sorted from the start:
- * 
+ *
  *     var myGrid = Ext.create('Ext.grid.Panel', {
  *         store: {
  *             fields: ['name', 'email', 'phone'],
  *             sorters: ['name', 'phone']
  *         },
  *         columns: [
- *             {text: 'Name',  dataIndex: 'name'},
- *             {text: 'Email', dataIndex: 'email'}
+ *             { text: 'Name',  dataIndex: 'name' },
+ *             { text: 'Email', dataIndex: 'email' }
  *         ]
  *     });
- * 
- * Sorting at run time is easily accomplished by simply clicking each column header. If you need to perform sorting on 
+ *
+ * Sorting at run time is easily accomplished by simply clicking each column header. If you need to perform sorting on
  * more than one field at run time it's easy to do so by adding new sorters to the store:
- * 
+ *
  *     myGrid.store.sort([
- *         {property: 'name',  direction: 'ASC'},
- *         {property: 'email', direction: 'DESC'},
+ *         { property: 'name',  direction: 'ASC' },
+ *         { property: 'email', direction: 'DESC' }
  *     ]);
- * 
- * {@img Ext.grid.Panel/Ext.grid.Panel4.png Ext.grid.Panel grouping}
- * 
+ *
+ * See {@link Ext.data.Store} for examples of filtering.
+ *
  * ## Grouping
- * 
- * Grid supports the grouping of rows by any field. For example if we had a set of employee records, we might want to 
+ *
+ * Grid supports the grouping of rows by any field. For example if we had a set of employee records, we might want to
  * group by the department that each employee works in. Here's how we might set that up:
- * 
+ *
+ *     @example
  *     var store = Ext.create('Ext.data.Store', {
  *         storeId:'employeeStore',
  *         fields:['name', 'senority', 'department'],
  *         groupField: 'department',
- *         data:{'employees':[
- *             {"name":"Michael Scott", "senority":7, "department":"Manangement"},
- *             {"name":"Dwight Schrute", "senority":2, "department":"Sales"},
- *             {"name":"Jim Halpert", "senority":3, "department":"Sales"},
- *             {"name":"Kevin Malone", "senority":4, "department":"Accounting"},
- *             {"name":"Angela Martin", "senority":5, "department":"Accounting"}                        
+ *         data: {'employees':[
+ *             { "name": "Michael Scott",  "senority": 7, "department": "Manangement" },
+ *             { "name": "Dwight Schrute", "senority": 2, "department": "Sales" },
+ *             { "name": "Jim Halpert",    "senority": 3, "department": "Sales" },
+ *             { "name": "Kevin Malone",   "senority": 4, "department": "Accounting" },
+ *             { "name": "Angela Martin",  "senority": 5, "department": "Accounting" }
  *         ]},
  *         proxy: {
  *             type: 'memory',
@@ -90616,20 +94452,20 @@ Ext.define('Ext.grid.View', {
  *             }
  *         }
  *     });
- *     
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Employees',
  *         store: Ext.data.StoreManager.lookup('employeeStore'),
  *         columns: [
- *             {header: 'Name',  dataIndex: 'name'},
- *             {header: 'Senority', dataIndex: 'senority'}
- *         ],        
+ *             { header: 'Name',     dataIndex: 'name' },
+ *             { header: 'Senority', dataIndex: 'senority' }
+ *         ],
  *         features: [{ftype:'grouping'}],
  *         width: 200,
  *         height: 275,
  *         renderTo: Ext.getBody()
  *     });
- * 
+ *
  * ## Infinite Scrolling
  *
  * Grid supports infinite scrolling as an alternative to using a paging toolbar. Your users can scroll through thousands
@@ -90645,14 +94481,15 @@ Ext.define('Ext.grid.View', {
  *         disableSelection: true,
  *         // ...
  *     });
- * 
+ *
  * ## Paging
  *
  * Grid supports paging through large sets of data via a PagingToolbar or PagingGridScroller (see the Infinite Scrolling section above).
  * To leverage paging via a toolbar or scroller, you need to set a pageSize configuration on the Store.
  *
+ *     @example
  *     var itemsPerPage = 2;   // set the number of items you want per page
- *     
+ *
  *     var store = Ext.create('Ext.data.Store', {
  *         id:'simpsonsStore',
  *         autoLoad: false,
@@ -90668,15 +94505,15 @@ Ext.define('Ext.grid.View', {
  *             }
  *         }
  *     });
- *     
+ *
  *     // specify segment of data you want to load using params
  *     store.load({
  *         params:{
- *             start:0,    
+ *             start:0,
  *             limit: itemsPerPage
  *         }
  *     });
- *     
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Simpsons',
  *         store: store,
@@ -90694,11 +94531,7 @@ Ext.define('Ext.grid.View', {
  *             displayInfo: true
  *         }],
  *         renderTo: Ext.getBody()
- *     }); 
- * 
- * {@img Ext.grid.Panel/Ext.grid.Panel5.png Ext.grid.Panel grouping}
- * 
- * @docauthor Ed Spencer
+ *     });
  */
 Ext.define('Ext.grid.Panel', {
     extend: 'Ext.panel.Table',
@@ -90706,35 +94539,36 @@ Ext.define('Ext.grid.Panel', {
     alias: ['widget.gridpanel', 'widget.grid'],
     alternateClassName: ['Ext.list.ListView', 'Ext.ListView', 'Ext.grid.GridPanel'],
     viewType: 'gridview',
-    
+
     lockable: false,
-    
+
     // Required for the Lockable Mixin. These are the configurations which will be copied to the
     // normal and locked sub tablepanels
     normalCfgCopy: ['invalidateScrollerOnRefresh', 'verticalScroller', 'verticalScrollDock', 'verticalScrollerType', 'scroll'],
     lockedCfgCopy: ['invalidateScrollerOnRefresh'],
-    
+
     /**
-     * @cfg {Boolean} columnLines Adds column line styling
+     * @cfg {Boolean} [columnLines=false] Adds column line styling
      */
-    
+
     initComponent: function() {
         var me = this;
 
         if (me.columnLines) {
             me.setColumnLines(me.columnLines);
         }
-        
+
         me.callParent();
     },
-    
+
     setColumnLines: function(show) {
         var me = this,
             method = (show) ? 'addClsWithUI' : 'removeClsWithUI';
-        
-        me[method]('with-col-lines')
+
+        me[method]('with-col-lines');
     }
 });
+
 // Currently has the following issues:
 // - Does not handle postEditValue
 // - Fields without editors need to sync with their values in Store
@@ -91165,7 +94999,9 @@ Ext.define('Ext.grid.RowEditor', {
         // Maintain mapping of fields-to-columns
         // This will fire events that maintain our container items
         me.columns.add(field.id, column);
-        
+        if (column.hidden) {
+            me.onColumnHide(column);
+        }
         if (me.isVisible() && me.context) {
             me.renderColumnData(field, me.context.record);
         }
@@ -91229,8 +95065,8 @@ Ext.define('Ext.grid.RowEditor', {
 
     /**
      * Start editing the specified grid at the specified position.
-     * @param {Model} record The Store data record which backs the row to be edited.
-     * @param {Model} columnHeader The Column object defining the column to be edited.
+     * @param {Ext.data.Model} record The Store data record which backs the row to be edited.
+     * @param {Ext.data.Model} columnHeader The Column object defining the column to be edited.
      */
     startEdit: function(record, columnHeader) {
         var me = this,
@@ -91584,6 +95420,61 @@ Ext.define('Ext.grid.header.Container', {
         Ext.destroy(this.resizer, this.reorderer);
         this.callParent();
     },
+    
+    applyDefaults: function(config){
+        /*
+         * Ensure header.Container defaults don't get applied to a RowNumberer 
+         * if an xtype is supplied. This isn't an ideal solution however it's 
+         * much more likely that a RowNumberer with no options will be created, 
+         * wanting to use the defaults specified on the class as opposed to 
+         * those setup on the Container.
+         */
+        if (config && !config.isComponent && config.xtype == 'rownumberer') {
+            return config;
+        }
+        return this.callParent([config]);
+    },
+
+    applyColumnsState: function(columns) {
+        if (!columns || !columns.length) {
+            return;
+        }
+
+        var me = this,
+            i = 0,
+            index,
+            col;
+
+        Ext.each(columns, function (columnState) {
+            col = me.down('gridcolumn[headerId=' + columnState.id + ']');
+            if (col) {
+                index = me.items.indexOf(col);
+                if (i !== index) {
+                    me.moveHeader(index, i);
+                }
+
+                if (col.applyColumnState) {
+                    col.applyColumnState(columnState);
+                }
+                ++i;
+            }
+        });
+    },
+
+    getColumnsState: function () {
+        var me = this,
+            columns = [],
+            state;
+
+        me.items.each(function (col) {
+            state = col.getColumnState && col.getColumnState();
+            if (state) {
+                columns.push(state);
+            }
+        });
+
+        return columns;
+    },
 
     // Invalidate column cache on add
     // We cannot refresh the View on every add because this method is called
@@ -91591,8 +95482,17 @@ Ext.define('Ext.grid.header.Container', {
     onAdd: function(c) {
         var me = this;
         if (!c.headerId) {
-            c.headerId = 'h' + (++me.headerCounter);
+            c.headerId = c.initialConfig.id || ('h' + (++me.headerCounter));
         }
+        //<debug warn>
+        if (Ext.global.console && Ext.global.console.warn) {
+            if (!me._usedIDs) me._usedIDs = {};
+            if (me._usedIDs[c.headerId]) {
+                Ext.global.console.warn(this.$className, 'attempted to reuse an existing id', c.headerId);
+            }
+            me._usedIDs[c.headerId] = true;
+        }
+        //</debug>
         me.callParent(arguments);
         me.purgeCache();
     },
@@ -91647,14 +95547,14 @@ Ext.define('Ext.grid.header.Container', {
                         me.pastLastHeaderEl.removeCls(me.lastHeaderCls);
                     }
                     lastHeaderEl.addCls(me.lastHeaderCls);
-                    me.pastLastHeaderEl = lastHeaderEl
+                    me.pastLastHeaderEl = lastHeaderEl;
                 }
             }
         }
 
     },
 
-    onHeaderShow: function(header) {
+    onHeaderShow: function(header, preventLayout) {
         // Pass up to the GridSection
         var me = this,
             gridSection = me.ownerCt,
@@ -91705,7 +95605,20 @@ Ext.define('Ext.grid.header.Container', {
         me.fireEvent('columnshow', me, header);
 
         // The header's own hide suppresses cascading layouts, so lay the headers out now
-        me.doLayout();
+        if (preventLayout !== true) {
+            me.doLayout();
+        }
+    },
+
+    doComponentLayout: function(){
+        var me = this;
+        if (me.view && me.view.saveScrollState) {
+            me.view.saveScrollState();
+        }
+        me.callParent(arguments);
+        if (me.view && me.view.restoreScrollState) {
+            me.view.restoreScrollState();
+        }
     },
 
     onHeaderHide: function(header, suppressLayout) {
@@ -91797,7 +95710,6 @@ Ext.define('Ext.grid.header.Container', {
         if (this.view && this.view.rendered) {
             this.view.onHeaderResize(header, w, suppressFocus);
         }
-        this.fireEvent('columnresize', this, header, w);
     },
 
     onHeaderClick: function(header, e, t) {
@@ -91851,6 +95763,7 @@ Ext.define('Ext.grid.header.Container', {
         var me = this;
         // Delete column cache - column order has changed.
         delete me.gridDataColumns;
+        delete me.hideableColumns;
 
         // Menu changes when columns are moved. It will be recreated.
         if (me.menu) {
@@ -91863,7 +95776,7 @@ Ext.define('Ext.grid.header.Container', {
         var me = this,
             gridSection = me.ownerCt;
 
-        if (gridSection) {
+        if (gridSection && gridSection.onHeaderMove) {
             gridSection.onHeaderMove(me, header, fromIdx, toIdx);
         }
         me.fireEvent("columnmove", me, header, fromIdx, toIdx);
@@ -91905,17 +95818,17 @@ Ext.define('Ext.grid.header.Container', {
             menuItems = [{
                 itemId: 'ascItem',
                 text: me.sortAscText,
-                cls: 'xg-hmenu-sort-asc',
+                cls: Ext.baseCSSPrefix + 'hmenu-sort-asc',
                 handler: me.onSortAscClick,
                 scope: me
             },{
                 itemId: 'descItem',
                 text: me.sortDescText,
-                cls: 'xg-hmenu-sort-desc',
+                cls: Ext.baseCSSPrefix + 'hmenu-sort-desc',
                 handler: me.onSortDescClick,
                 scope: me
             }];
-        };
+        }
         if (hideableColumns && hideableColumns.length) {
             menuItems.push('-', {
                 itemId: 'columnItem',
@@ -92006,14 +95919,14 @@ Ext.define('Ext.grid.header.Container', {
         for (; i < headersLn; i++) {
             header = headers[i];
 
-            if (header.hidden) {
+            if (header.hidden || header.up('headercontainer[hidden=true]')) {
                 width = 0;
             } else {
                 width = header.getDesiredWidth();
                 // IE6 and IE7 bug.
                 // Setting the width of the first TD does not work - ends up with a 1 pixel discrepancy.
                 // We need to increment the passed with in this case.
-                if ((i == 0) && (Ext.isIE6 || Ext.isIE7)) {
+                if ((i === 0) && (Ext.isIE6 || Ext.isIE7)) {
                     width += 1;
                 }
             }
@@ -92112,6 +96025,21 @@ Ext.define('Ext.grid.header.Container', {
         return result;
     },
 
+    /**
+     * @private
+     * For use by column headers in determining whether there are any hideable columns when deciding whether or not
+     * the header menu should be disabled.
+     */
+    getHideableColumns: function(refreshCache) {
+        var me = this,
+            result = refreshCache ? null : me.hideableColumns;
+
+        if (!result) {
+            result = me.hideableColumns = me.query('[hideable]');
+        }
+        return result;
+    },
+
     /**
      * Get the index of a leaf level header regardless of what the nesting
      * structure is.
@@ -92207,19 +96135,13 @@ Ext.define('Ext.grid.header.Container', {
 });
 
 /**
- * @class Ext.grid.column.Column
- * @extends Ext.grid.header.Container
- *
  * This class specifies the definition for a column inside a {@link Ext.grid.Panel}. It encompasses
  * both the grid header configuration as well as displaying data within the grid itself. If the
  * {@link #columns} configuration is specified, this column will become a column group and can
- * container other columns inside. In general, this class will not be created directly, rather
+ * contain other columns inside. In general, this class will not be created directly, rather
  * an array of column configurations will be passed to the grid:
  *
- * {@img Ext.grid.column.Column/Ext.grid.column.Column.png Ext.grid.column.Column grid column}
- *
- * ## Code
- *
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *         storeId:'employeeStore',
  *         fields:['firstname', 'lastname', 'senority', 'dep', 'hired'],
@@ -92239,13 +96161,14 @@ Ext.define('Ext.grid.header.Container', {
  *             {text: 'First Name',  dataIndex:'firstname'},
  *             {text: 'Last Name',  dataIndex:'lastname'},
  *             {text: 'Hired Month',  dataIndex:'hired', xtype:'datecolumn', format:'M'},
- *             {text: 'Deparment (Yrs)', xtype:'templatecolumn', tpl:'{dep} ({senority})'}
+ *             {text: 'Department (Yrs)', xtype:'templatecolumn', tpl:'{dep} ({senority})'}
  *         ],
  *         width: 400,
  *         renderTo: Ext.getBody()
  *     });
  *
- * ## Convenience Subclasses
+ * # Convenience Subclasses
+ *
  * There are several column subclasses that provide default rendering for various data types
  *
  *  - {@link Ext.grid.column.Action}: Renders icons that can respond to click events inline
@@ -92254,13 +96177,15 @@ Ext.define('Ext.grid.header.Container', {
  *  - {@link Ext.grid.column.Number}: Renders for numeric values
  *  - {@link Ext.grid.column.Template}: Renders a value using an {@link Ext.XTemplate} using the record data
  *
- * ## Setting Sizes
+ * # Setting Sizes
+ *
  * The columns are laid out by a {@link Ext.layout.container.HBox} layout, so a column can either
  * be given an explicit width value or a flex configuration. If no width is specified the grid will
  * automatically the size the column to 100px. For column groups, the size is calculated by measuring
  * the width of the child columns, so a width option should not be specified in that case.
  *
- * ## Header Options
+ * # Header Options
+ *
  *  - {@link #text}: Sets the header text for the column
  *  - {@link #sortable}: Specifies whether the column can be sorted by clicking the header or using the column menu
  *  - {@link #hideable}: Specifies whether the column can be hidden using the column menu
@@ -92268,7 +96193,8 @@ Ext.define('Ext.grid.header.Container', {
  *  - {@link #draggable}: Specifies whether the column header can be reordered by dragging
  *  - {@link #groupable}: Specifies whether the grid can be grouped by the column dataIndex. See also {@link Ext.grid.feature.Grouping}
  *
- * ## Data Options
+ * # Data Options
+ *
  *  - {@link #dataIndex}: The dataIndex is the field in the underlying {@link Ext.data.Store} to use as the value for the column.
  *  - {@link #renderer}: Allows the underlying store value to be transformed before being displayed in the grid
  */
@@ -92290,102 +96216,110 @@ Ext.define('Ext.grid.column.Column', {
     possibleSortStates: ['ASC', 'DESC'],
 
     renderTpl:
-        '<div class="' + Ext.baseCSSPrefix + 'column-header-inner">' +
-            '<span class="' + Ext.baseCSSPrefix + 'column-header-text">' +
+        '<div id="{id}-titleContainer" class="' + Ext.baseCSSPrefix + 'column-header-inner">' +
+            '<span id="{id}-textEl" class="' + Ext.baseCSSPrefix + 'column-header-text">' +
                 '{text}' +
             '</span>' +
-            '<tpl if="!values.menuDisabled"><div class="' + Ext.baseCSSPrefix + 'column-header-trigger"></div></tpl>' +
+            '<tpl if="!values.menuDisabled">'+
+                '<div id="{id}-triggerEl" class="' + Ext.baseCSSPrefix + 'column-header-trigger"></div>'+
+            '</tpl>' +
         '</div>',
 
     /**
-     * @cfg {Array} columns
-     * <p>An optional array of sub-column definitions. This column becomes a group, and houses the columns defined in the <code>columns</code> config.</p>
-     * <p>Group columns may not be sortable. But they may be hideable and moveable. And you may move headers into and out of a group. Note that
-     * if all sub columns are dragged out of a group, the group is destroyed.
+     * @cfg {Object[]} columns
+     * An optional array of sub-column definitions. This column becomes a group, and houses the columns defined in the
+     * `columns` config.
+     *
+     * Group columns may not be sortable. But they may be hideable and moveable. And you may move headers into and out
+     * of a group. Note that if all sub columns are dragged out of a group, the group is destroyed.
      */
 
     /**
-     * @cfg {String} dataIndex <p><b>Required</b>. The name of the field in the
-     * grid's {@link Ext.data.Store}'s {@link Ext.data.Model} definition from
-     * which to draw the column's value.</p>
+     * @cfg {String} dataIndex
+     * The name of the field in the grid's {@link Ext.data.Store}'s {@link Ext.data.Model} definition from
+     * which to draw the column's value. **Required.**
      */
     dataIndex: null,
 
     /**
-     * @cfg {String} text Optional. The header text to be used as innerHTML
-     * (html tags are accepted) to display in the Grid.  <b>Note</b>: to
-     * have a clickable header with no text displayed you can use the
-     * default of <tt>'&#160;'</tt>.
+     * @cfg {String} text
+     * The header text to be used as innerHTML (html tags are accepted) to display in the Grid.
+     * **Note**: to have a clickable header with no text displayed you can use the default of `&#160;` aka `&nbsp;`.
      */
-    text: '&#160',
+    text: '&#160;',
 
     /**
-     * @cfg {Boolean} sortable Optional. <tt>true</tt> if sorting is to be allowed on this column.
-     * Whether local/remote sorting is used is specified in <code>{@link Ext.data.Store#remoteSort}</code>.
+     * @cfg {Boolean} sortable
+     * False to disable sorting of this column. Whether local/remote sorting is used is specified in
+     * `{@link Ext.data.Store#remoteSort}`. Defaults to true.
      */
     sortable: true,
 
     /**
-     * @cfg {Boolean} groupable Optional. If the grid uses a {@link Ext.grid.feature.Grouping}, this option
-     * may be used to disable the header menu item to group by the column selected. By default,
-     * the header menu group option is enabled. Set to false to disable (but still show) the
-     * group option in the header menu for the column.
+     * @cfg {Boolean} groupable
+     * If the grid uses a {@link Ext.grid.feature.Grouping}, this option may be used to disable the header menu
+     * item to group by the column selected. By default, the header menu group option is enabled. Set to false to
+     * disable (but still show) the group option in the header menu for the column.
      */
 
     /**
-     * @cfg {Boolean} fixed Prevents the column from being resizable
+     * @cfg {Boolean} fixed
+     * @deprecated.
+     * True to prevent the column from being resizable.
      */
-     
+
     /**
-     * @cfg {Boolean} resizable This config has no effect on a grid column, please see {@link #fixed} instead.
+     * @cfg {Boolean} resizable
+     * Set to <code>false</code> to prevent the column from being resizable. Defaults to <code>true</code>
      */
 
     /**
-     * @cfg {Boolean} hideable Optional. Specify as <tt>false</tt> to prevent the user from hiding this column
-     * (defaults to true).
+     * @cfg {Boolean} hideable
+     * False to prevent the user from hiding this column. Defaults to true.
      */
     hideable: true,
 
     /**
      * @cfg {Boolean} menuDisabled
-     * True to disabled the column header menu containing sort/hide options. Defaults to false.
+     * True to disable the column header menu containing sort/hide options. Defaults to false.
      */
     menuDisabled: false,
 
     /**
-     * @method
-     * <p>A renderer is an 'interceptor' method which can be used transform data (value, appearance, etc.) before it
-     * is rendered. Example:</p>
-     * <pre><code>{
-    renderer: function(value){
-        if (value === 1) {
-            return '1 person';
-        }
-        return value + ' people';
-    }
-}
-     * </code></pre>
-     * @param {Mixed} value The data value for the current cell
-     * @param {Object} metaData A collection of metadata about the current cell; can be used or modified by
-     * the renderer. Recognized properties are: <tt>tdCls</tt>, <tt>tdAttr</tt>, and <tt>style</tt>.
-     * @param {Ext.data.Model} record The record for the current row
-     * @param {Number} rowIndex The index of the current row
-     * @param {Number} colIndex The index of the current column
-     * @param {Ext.data.Store} store The data store
-     * @param {Ext.view.View} view The current view
-     * @return {String} The HTML to be rendered
+     * @cfg {Function} renderer
+     * A renderer is an 'interceptor' method which can be used transform data (value, appearance, etc.)
+     * before it is rendered. Example:
+     *
+     *     {
+     *         renderer: function(value){
+     *             if (value === 1) {
+     *                 return '1 person';
+     *             }
+     *             return value + ' people';
+     *         }
+     *     }
+     *
+     * @cfg {Object} renderer.value The data value for the current cell
+     * @cfg {Object} renderer.metaData A collection of metadata about the current cell; can be used or modified
+     * by the renderer. Recognized properties are: tdCls, tdAttr, and style.
+     * @cfg {Ext.data.Model} renderer.record The record for the current row
+     * @cfg {Number} renderer.rowIndex The index of the current row
+     * @cfg {Number} renderer.colIndex The index of the current column
+     * @cfg {Ext.data.Store} renderer.store The data store
+     * @cfg {Ext.view.View} renderer.view The current view
+     * @cfg {String} renderer.return The HTML string to be rendered.
      */
     renderer: false,
 
     /**
-     * @cfg {String} align Sets the alignment of the header and rendered columns.
-     * Defaults to 'left'.
+     * @cfg {String} align
+     * Sets the alignment of the header and rendered columns. Defaults to 'left'.
      */
     align: 'left',
 
     /**
-     * @cfg {Boolean} draggable Indicates whether or not the header can be drag and drop re-ordered.
-     * Defaults to true.
+     * @cfg {Boolean} draggable
+     * False to disable drag-drop reordering of this column. Defaults to true.
      */
     draggable: true,
 
@@ -92394,15 +96328,30 @@ Ext.define('Ext.grid.column.Column', {
     initDraggable: Ext.emptyFn,
 
     /**
-     * @cfg {String} tdCls <p>Optional. A CSS class names to apply to the table cells for this column.</p>
+     * @cfg {String} tdCls
+     * A CSS class names to apply to the table cells for this column.
+     */
+
+    /**
+     * @cfg {Object/String} editor
+     * An optional xtype or config object for a {@link Ext.form.field.Field Field} to use for editing.
+     * Only applicable if the grid is using an {@link Ext.grid.plugin.Editing Editing} plugin.
+     */
+
+    /**
+     * @cfg {Object/String} field
+     * Alias for {@link #editor}.
+     * @deprecated 4.0.5 Use {@link #editor} instead.
      */
 
     /**
-     * @property {Ext.core.Element} triggerEl
+     * @property {Ext.Element} triggerEl
+     * Element that acts as button for column header dropdown menu.
      */
 
     /**
-     * @property {Ext.core.Element} textEl
+     * @property {Ext.Element} textEl
+     * Element that contains the text in column header.
      */
 
     /**
@@ -92415,7 +96364,8 @@ Ext.define('Ext.grid.column.Column', {
     initComponent: function() {
         var me = this,
             i,
-            len;
+            len,
+            item;
 
         if (Ext.isDefined(me.header)) {
             me.text = me.header;
@@ -92459,9 +96409,12 @@ Ext.define('Ext.grid.column.Column', {
 
             // Acquire initial width from sub headers
             for (i = 0, len = me.items.length; i < len; i++) {
-                me.width += me.items[i].width || Ext.grid.header.Container.prototype.defaultWidth;
+                item = me.items[i];
+                if (!item.hidden) {
+                    me.width += item.width || Ext.grid.header.Container.prototype.defaultWidth;
+                }
                 //<debug>
-                if (me.items[i].flex) {
+                if (item.flex) {
                     Ext.Error.raise('Ext.grid.column.Column: items of a grouped header do not support flexed values. Each item must explicitly define its width.');
                 }
                 //</debug>
@@ -92470,15 +96423,11 @@ Ext.define('Ext.grid.column.Column', {
 
             me.cls = (me.cls||'') + ' ' + Ext.baseCSSPrefix + 'group-header';
             me.sortable = false;
-            me.fixed = true;
+            me.resizable = false;
             me.align = 'center';
         }
 
-        Ext.applyIf(me.renderSelectors, {
-            titleContainer: '.' + Ext.baseCSSPrefix + 'column-header-inner',
-            triggerEl: '.' + Ext.baseCSSPrefix + 'column-header-trigger',
-            textEl: '.' + Ext.baseCSSPrefix + 'column-header-text'
-        });
+        me.addChildEls('titleContainer', 'triggerEl', 'textEl');
 
         // Initialize as a HeaderContainer
         me.callParent(arguments);
@@ -92487,11 +96436,13 @@ Ext.define('Ext.grid.column.Column', {
     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() {
@@ -92504,9 +96455,63 @@ Ext.define('Ext.grid.column.Column', {
         return me.callParent(arguments);
     },
 
+    applyColumnState: function (state) {
+        var me = this,
+            defined = Ext.isDefined;
+            
+        // apply any columns
+        me.applyColumnsState(state.columns);
+
+        // Only state properties which were saved should be restored.
+        // (Only user-changed properties were saved by getState)
+        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,
+            columns = [],
+            state = {
+                id: me.headerId
+            };
+
+        me.savePropsToState(['hidden', 'sortable', 'locked', 'flex', 'width'], state);
+        
+        if (me.isGroupHeader) {
+            me.items.each(function(column){
+                columns.push(column.getColumnState());
+            });
+            if (columns.length) {
+                state.columns = columns;
+            }
+        } else if (me.isSubHeader && me.ownerCt.hidden) {
+            // don't set hidden on the children so they can auto height
+            delete me.hidden;
+        }
+
+        if ('width' in state) {
+            delete state.flex; // width wins
+        }
+        return state;
+    },
+
     /**
      * Sets the header text for this Column.
-     * @param text The header to display on this Column.
+     * @param {String} text The header to display on this Column.
      */
     setText: function(text) {
         this.text = text;
@@ -92522,13 +96527,26 @@ Ext.define('Ext.grid.column.Column', {
     },
 
     /**
-     * Returns the true grid column index assiciated with this Column only if this column is a base level Column.
-     * If it is a group column, it returns <code>false</code>
+     * Returns the true grid column index associated with this column only if this column is a base level Column. If it
+     * is a group column, it returns `false`.
+     * @return {Number}
      */
     getIndex: function() {
         return this.isGroupColumn ? false : this.getOwnerHeaderCt().getHeaderIndex(this);
     },
 
+    onRender: function() {
+        var me = this,
+            grid = me.up('tablepanel');
+
+        // Disable the menu if there's nothing to show in the menu, ie:
+        // Column cannot be sorted, grouped or locked, and there are no grid columns which may be hidden
+        if (grid && (!me.sortable || grid.sortableColumns === false) && !me.groupable && !me.lockable && (grid.enableColumnHide === false || !me.getOwnerHeaderCt().getHideableColumns().length)) {
+            me.menuDisabled = true;
+        }
+        me.callParent(arguments);
+    },
+
     afterRender: function() {
         var me = this,
             el = me.el;
@@ -92566,50 +96584,42 @@ Ext.define('Ext.grid.column.Column', {
         });
     },
 
-    setSize: function(width, height) {
+    /**
+     * Sets the width of this Column.
+     * @param {Number} width New width.
+     */
+    setWidth: function(width, /* private - used internally */ doLayout) {
         var me = this,
             headerCt = me.ownerCt,
-            ownerHeaderCt = me.getOwnerHeaderCt(),
             siblings,
             len, i,
             oldWidth = me.getWidth(),
-            newWidth = 0,
-            readyForSizing = true,
-            hidden,
+            groupWidth = 0,
             sibling;
 
         if (width !== oldWidth) {
+            me.oldWidth = oldWidth;
+
+            // Non-flexed Headers may never be squeezed in the event of a shortfall so
+            // always set the minWidth to their current width.
+            me.minWidth = me.width = width;
 
             // Bubble size changes upwards to group headers
             if (headerCt.isGroupHeader) {
                 siblings = headerCt.items.items;
                 len = siblings.length;
 
-                /*
-                 * setSize will be called for each column as it's rendered
-                 * so we want to wait until all sub columns have been rendered
-                 * before we try and calculate the size of the outer container.
-                 * We also take into account hidden columns, because they won't
-                 * be rendered, but we'll still need to make the calculation.
-                 */
                 for (i = 0; i < len; i++) {
                     sibling = siblings[i];
-                    hidden = sibling.hidden;
-                    if (!sibling.rendered && !hidden) {
-                        readyForSizing = false;
-                        break;
-                    }
-                    if (!hidden) {
-                        newWidth += (sibling === me) ? width : sibling.getWidth();
+                    if (!sibling.hidden) {
+                        groupWidth += (sibling === me) ? width : sibling.getWidth();
                     }
                 }
-
-                if (readyForSizing) {
-                    headerCt.minWidth = newWidth;
-                    headerCt.setWidth(newWidth);
-                }
+                headerCt.setWidth(groupWidth, doLayout);
+            } else if (doLayout !== false) {
+                // Allow the owning Container to perform the sizing
+                headerCt.doLayout();
             }
-            me.callParent(arguments);
         }
     },
 
@@ -92625,18 +96635,21 @@ Ext.define('Ext.grid.column.Column', {
         if (width && !me.isGroupHeader && ownerHeaderCt) {
             ownerHeaderCt.onHeaderResize(me, width, true);
         }
+        if (me.oldWidth && (width !== me.oldWidth)) {
+            ownerHeaderCt.fireEvent('columnresize', ownerHeaderCt, this, width);
+        }
+        delete me.oldWidth;
     },
 
     // private
     // After the container has laid out and stretched, it calls this to correctly pad the inner to center the text vertically
-    setPadding: function() {
+    // Total available header height must be passed to enable padding for inner elements to be calculated.
+    setPadding: function(headerHeight) {
         var me = this,
-            headerHeight,
-            lineHeight = parseInt(me.textEl.getStyle('line-height'), 10);
+            lineHeight = Ext.util.TextMetrics.measure(me.textEl.dom, me.text).height;
 
         // Top title containing element must stretch to match height of sibling group headers
         if (!me.isGroupHeader) {
-            headerHeight = me.el.getViewSize().height;
             if (me.titleContainer.getHeight() < headerHeight) {
                 me.titleContainer.dom.style.height = headerHeight + 'px';
             }
@@ -92658,7 +96671,8 @@ Ext.define('Ext.grid.column.Column', {
 
     onDestroy: function() {
         var me = this;
-        Ext.destroy(me.keyNav);
+        // force destroy on the textEl, IE reports a leak
+        Ext.destroy(me.textEl, me.keyNav);
         delete me.keyNav;
         me.callParent(arguments);
     },
@@ -92718,11 +96732,11 @@ Ext.define('Ext.grid.column.Column', {
      * @private
      * Process UI events from the view. The owning TablePanel calls this method, relaying events from the TableView
      * @param {String} type Event type, eg 'click'
-     * @param {TableView} view TableView Component
-     * @param {HtmlElement} cell Cell HtmlElement the event took place within
+     * @param {Ext.view.Table} view TableView Component
+     * @param {HTMLElement} cell Cell HtmlElement the event took place within
      * @param {Number} recordIndex Index of the associated Store Model (-1 if none)
      * @param {Number} cellIndex Cell index within the row
-     * @param {EventObject} e Original event
+     * @param {Ext.EventObject} e Original event
      */
     processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
         return this.fireEvent.apply(this, arguments);
@@ -92750,8 +96764,9 @@ Ext.define('Ext.grid.column.Column', {
     },
 
     /**
-     * Returns the parameter to sort upon when sorting this header. By default
-     * this returns the dataIndex and will not need to be overriden in most cases.
+     * Returns the parameter to sort upon when sorting this header. By default this returns the dataIndex and will not
+     * need to be overriden in most cases.
+     * @return {String}
      */
     getSortParam: function() {
         return this.dataIndex;
@@ -92844,22 +96859,30 @@ Ext.define('Ext.grid.column.Column', {
 
     show: function() {
         var me = this,
-            ownerCt = me.getOwnerHeaderCt(),
-            lb,
+            ownerCt = me.ownerCt,
+            ownerCtCompLayout = ownerCt.componentLayout,
+            ownerCtCompLayoutBusy = ownerCtCompLayout.layoutBusy,
+            ownerCtLayout = ownerCt.layout,
+            ownerCtLayoutBusy = ownerCtLayout.layoutBusy,
             items,
             len, i,
+            item,
             newWidth = 0;
 
         // TODO: Work with Jamie to produce a scheme where we can show/hide/resize without triggering a layout cascade
-        lb = me.ownerCt.componentLayout.layoutBusy;
-        me.ownerCt.componentLayout.layoutBusy = true;
+
+        // Suspend our owner's layouts (both component and container):
+        ownerCtCompLayout.layoutBusy = ownerCtLayout.layoutBusy = true;
+
         me.callParent(arguments);
-        me.ownerCt.componentLayout.layoutBusy = lb;
+
+        ownerCtCompLayout.layoutBusy = ownerCtCompLayoutBusy;
+        ownerCtLayout.layoutBusy = ownerCtLayoutBusy;
 
         // If a sub header, ensure that the group header is visible
         if (me.isSubHeader) {
-            if (!me.ownerCt.isVisible()) {
-                me.ownerCt.show();
+            if (!ownerCt.isVisible()) {
+                ownerCt.show();
             }
         }
 
@@ -92867,23 +96890,29 @@ Ext.define('Ext.grid.column.Column', {
         if (me.isGroupHeader && !me.query(':not([hidden])').length) {
             items = me.query('>*');
             for (i = 0, len = items.length; i < len; i++) {
-                items[i].show();
+                item = items[i];
+                item.preventLayout = true;
+                item.show();
+                newWidth += item.getWidth();
+                delete item.preventLayout;
             }
+            me.setWidth(newWidth);
         }
 
         // Resize the owning group to accommodate
-        if (me.ownerCt.isGroupHeader) {
-            items = me.ownerCt.query('>:not([hidden])');
+        if (ownerCt.isGroupHeader && me.preventLayout !== true) {
+            items = ownerCt.query('>:not([hidden])');
             for (i = 0, len = items.length; i < len; i++) {
                 newWidth += items[i].getWidth();
             }
-            me.ownerCt.minWidth = newWidth;
-            me.ownerCt.setWidth(newWidth);
+            ownerCt.minWidth = newWidth;
+            ownerCt.setWidth(newWidth);
         }
 
         // Notify owning HeaderContainer
+        ownerCt = me.getOwnerHeaderCt();
         if (ownerCt) {
-            ownerCt.onHeaderShow(me);
+            ownerCt.onHeaderShow(me, me.preventLayout);
         }
     },
 
@@ -92926,59 +96955,62 @@ Ext.define('Ext.grid.column.Column', {
         return (this.el.getRight() - e.getXY()[0] <= this.handleWidth);
     }
 
-    /**
-     * Retrieves the editing field for editing associated with this header. Returns false if there
-     * is no field associated with the Header the method will return false. If the
-     * field has not been instantiated it will be created. Note: These methods only has an implementation
-     * if a Editing plugin has been enabled on the grid.
-     * @param record The {@link Ext.data.Model Model} instance being edited.
-     * @param {Mixed} defaultField An object representing a default field to be created
-     * @returns {Ext.form.field.Field} field
-     * @method getEditor
-     */
     // intentionally omit getEditor and setEditor definitions bc we applyIf into columns
     // when the editing plugin is injected
 
-
     /**
-     * Sets the form field to be used for editing. Note: This method only has an implementation
-     * if an Editing plugin has been enabled on the grid.
-     * @param {Mixed} field An object representing a field to be created. If no xtype is specified a 'textfield' is assumed.
+     * @method getEditor
+     * Retrieves the editing field for editing associated with this header. Returns false if there is no field
+     * associated with the Header the method will return false. If the field has not been instantiated it will be
+     * created. Note: These methods only has an implementation if a Editing plugin has been enabled on the grid.
+     * @param {Object} record The {@link Ext.data.Model Model} instance being edited.
+     * @param {Object} defaultField An object representing a default field to be created
+     * @return {Ext.form.field.Field} field
+     */
+    /**
      * @method setEditor
+     * Sets the form field to be used for editing. Note: This method only has an implementation if an Editing plugin has
+     * been enabled on the grid.
+     * @param {Object} field An object representing a field to be created. If no xtype is specified a 'textfield' is
+     * assumed.
      */
 });
+
 /**
- * @class Ext.grid.RowNumberer
- * @extends Ext.grid.column.Column
  * This is a utility class that can be passed into a {@link Ext.grid.column.Column} as a column config that provides
  * an automatic row numbering column.
- * <br>Usage:<br><pre><code>
-columns: [
-    Ext.create('Ext.grid.RowNumberer'),
-    {text: "Company", flex: 1, sortable: true, dataIndex: 'company'},
-    {text: "Price", width: 120, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'},
-    {text: "Change", width: 120, sortable: true, dataIndex: 'change'},
-    {text: "% Change", width: 120, sortable: true, dataIndex: 'pctChange'},
-    {text: "Last Updated", width: 120, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
-]
- *</code></pre>
+ * 
+ * Usage:
+ *
+ *     columns: [
+ *         {xtype: 'rownumberer'},
+ *         {text: "Company", flex: 1, sortable: true, dataIndex: 'company'},
+ *         {text: "Price", width: 120, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'},
+ *         {text: "Change", width: 120, sortable: true, dataIndex: 'change'},
+ *         {text: "% Change", width: 120, sortable: true, dataIndex: 'pctChange'},
+ *         {text: "Last Updated", width: 120, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
+ *     ]
+ *
  */
 Ext.define('Ext.grid.RowNumberer', {
     extend: 'Ext.grid.column.Column',
     alias: 'widget.rownumberer',
+
     /**
-     * @cfg {String} text Any valid text or HTML fragment to display in the header cell for the row
-     * number column (defaults to '&#160').
+     * @cfg {String} text
+     * Any valid text or HTML fragment to display in the header cell for the row number column.
      */
     text: "&#160",
 
     /**
-     * @cfg {Number} width The default width in pixels of the row number column (defaults to 23).
+     * @cfg {Number} width
+     * The default width in pixels of the row number column.
      */
     width: 23,
 
     /**
-     * @cfg {Boolean} sortable True if the row number column is sortable (defaults to false).
+     * @cfg {Boolean} sortable
+     * True if the row number column is sortable.
      * @hide
      */
     sortable: false,
@@ -92993,7 +97025,7 @@ Ext.define('Ext.grid.RowNumberer', {
     },
 
     // private
-    fixed: true,
+    resizable: false,
     hideable: false,
     menuDisabled: true,
     dataIndex: '',
@@ -93046,7 +97078,7 @@ Ext.define('Ext.view.DropZone', {
     fireViewEvent: function() {
         var me = this,
             result;
-            
+
         me.lock();
         result = me.view.fireEvent.apply(me.view, arguments);
         me.unlock();
@@ -93161,7 +97193,7 @@ Ext.define('Ext.view.DropZone', {
     // The mouse is over a View node
     onNodeOver: function(node, dragZone, e, data) {
         var me = this;
-        
+
         if (!Ext.Array.contains(data.records, me.view.getRecord(node))) {
             me.positionIndicator(node, data, e);
         }
@@ -93172,7 +97204,7 @@ Ext.define('Ext.view.DropZone', {
     // Remove drop position indicator
     notifyOut: function(node, dragZone, e, data) {
         var me = this;
-        
+
         me.callParent(arguments);
         delete me.overRecord;
         delete me.currentPosition;
@@ -93232,6 +97264,12 @@ Ext.define('Ext.view.DropZone', {
             }
         }
         return performOperation;
+    },
+    
+    destroy: function(){
+        Ext.destroy(this.indicator);
+        delete this.indicator;
+        this.callParent();
     }
 });
 
@@ -93274,14 +97312,10 @@ Ext.define('Ext.grid.ViewDropZone', {
     }
 });
 /**
- * @class Ext.grid.column.Action
- * @extends Ext.grid.column.Column
- * <p>A Grid header type which renders an icon, or a series of icons in a grid cell, and offers a scoped click
- * handler for each icon.</p>
+ * A Grid header type which renders an icon, or a series of icons in a grid cell, and offers a scoped click
+ * handler for each icon.
  *
- * {@img Ext.grid.column.Action/Ext.grid.column.Action.png Ext.grid.column.Action grid column}
- *  
- * ## Code
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *         storeId:'employeeStore',
  *         fields:['firstname', 'lastname', 'senority', 'dep', 'hired'],
@@ -93290,10 +97324,10 @@ Ext.define('Ext.grid.ViewDropZone', {
  *             {firstname:"Dwight", lastname:"Schrute"},
  *             {firstname:"Jim", lastname:"Halpert"},
  *             {firstname:"Kevin", lastname:"Malone"},
- *             {firstname:"Angela", lastname:"Martin"}                        
+ *             {firstname:"Angela", lastname:"Martin"}
  *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Action Column Demo',
  *         store: Ext.data.StoreManager.lookup('employeeStore'),
@@ -93301,30 +97335,31 @@ Ext.define('Ext.grid.ViewDropZone', {
  *             {text: 'First Name',  dataIndex:'firstname'},
  *             {text: 'Last Name',  dataIndex:'lastname'},
  *             {
- *                 xtype:'actioncolumn', 
+ *                 xtype:'actioncolumn',
  *                 width:50,
  *                 items: [{
- *                     icon: 'images/edit.png',  // Use a URL in the icon config
+ *                     icon: 'extjs/examples/shared/icons/fam/cog_edit.png',  // Use a URL in the icon config
  *                     tooltip: 'Edit',
  *                     handler: function(grid, rowIndex, colIndex) {
  *                         var rec = grid.getStore().getAt(rowIndex);
  *                         alert("Edit " + rec.get('firstname'));
  *                     }
  *                 },{
- *                     icon: 'images/delete.png',
+ *                     icon: 'extjs/examples/restful/images/delete.png',
  *                     tooltip: 'Delete',
  *                     handler: function(grid, rowIndex, colIndex) {
  *                         var rec = grid.getStore().getAt(rowIndex);
  *                         alert("Terminate " + rec.get('firstname'));
- *                     }                
+ *                     }
  *                 }]
  *             }
  *         ],
  *         width: 250,
  *         renderTo: Ext.getBody()
  *     });
- * <p>The action column can be at any index in the columns array, and a grid can have any number of
- * action columns. </p>
+ *
+ * The action column can be at any index in the columns array, and a grid can have any number of
+ * action columns.
  */
 Ext.define('Ext.grid.column.Action', {
     extend: 'Ext.grid.column.Column',
@@ -93333,87 +97368,104 @@ Ext.define('Ext.grid.column.Action', {
 
     /**
      * @cfg {String} icon
-     * The URL of an image to display as the clickable element in the column. 
-     * Optional - defaults to <code>{@link Ext#BLANK_IMAGE_URL Ext.BLANK_IMAGE_URL}</code>.
+     * The URL of an image to display as the clickable element in the column. Defaults to
+     * `{@link Ext#BLANK_IMAGE_URL Ext.BLANK_IMAGE_URL}`.
      */
     /**
      * @cfg {String} iconCls
-     * A CSS class to apply to the icon image. To determine the class dynamically, configure the Column with a <code>{@link #getClass}</code> function.
+     * A CSS class to apply to the icon image. To determine the class dynamically, configure the Column with
+     * a `{@link #getClass}` function.
      */
     /**
-     * @cfg {Function} handler A function called when the icon is clicked.
-     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
-     * <li><code>view</code> : TableView<div class="sub-desc">The owning TableView.</div></li>
-     * <li><code>rowIndex</code> : Number<div class="sub-desc">The row index clicked on.</div></li>
-     * <li><code>colIndex</code> : Number<div class="sub-desc">The column index clicked on.</div></li>
-     * <li><code>item</code> : Object<div class="sub-desc">The clicked item (or this Column if multiple 
-     * {@link #items} were not configured).</div></li>
-     * <li><code>e</code> : Event<div class="sub-desc">The click event.</div></li>
-     * </ul></div>
+     * @cfg {Function} handler
+     * A function called when the icon is clicked.
+     * @cfg {Ext.view.Table} handler.view The owning TableView.
+     * @cfg {Number} handler.rowIndex The row index clicked on.
+     * @cfg {Number} handler.colIndex The column index clicked on.
+     * @cfg {Object} handler.item The clicked item (or this Column if multiple {@link #items} were not configured).
+     * @cfg {Event} handler.e The click event.
      */
     /**
-     * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
-     * and <code>{@link #getClass}</code> fuctions are executed. Defaults to this Column.
+     * @cfg {Object} scope
+     * The scope (**this** reference) in which the `{@link #handler}` and `{@link #getClass}` fuctions are executed.
+     * Defaults to this Column.
      */
     /**
-     * @cfg {String} tooltip A tooltip message to be displayed on hover. {@link Ext.tip.QuickTipManager#init Ext.tip.QuickTipManager} must have 
-     * been initialized.
+     * @cfg {String} tooltip
+     * A tooltip message to be displayed on hover. {@link Ext.tip.QuickTipManager#init Ext.tip.QuickTipManager} must
+     * have been initialized.
+     */
+    /* @cfg {Boolean} disabled
+     * If true, the action will not respond to click events, and will be displayed semi-opaque.
      */
     /**
-     * @cfg {Boolean} stopSelection Defaults to <code>true</code>. Prevent grid <i>row</i> selection upon mousedown.
+     * @cfg {Boolean} [stopSelection=true]
+     * Prevent grid _row_ selection upon mousedown.
      */
     /**
-     * @cfg {Function} getClass A function which returns the CSS class to apply to the icon image.
-     * The function is passed the following parameters:<ul>
-     *     <li><b>v</b> : Object<p class="sub-desc">The value of the column's configured field (if any).</p></li>
-     *     <li><b>metadata</b> : Object<p class="sub-desc">An object in which you may set the following attributes:<ul>
-     *         <li><b>css</b> : String<p class="sub-desc">A CSS class name to add to the cell's TD element.</p></li>
-     *         <li><b>attr</b> : String<p class="sub-desc">An HTML attribute definition string to apply to the data container element <i>within</i> the table cell
-     *         (e.g. 'style="color:red;"').</p></li>
-     *     </ul></p></li>
-     *     <li><b>r</b> : Ext.data.Record<p class="sub-desc">The Record providing the data.</p></li>
-     *     <li><b>rowIndex</b> : Number<p class="sub-desc">The row index..</p></li>
-     *     <li><b>colIndex</b> : Number<p class="sub-desc">The column index.</p></li>
-     *     <li><b>store</b> : Ext.data.Store<p class="sub-desc">The Store which is providing the data Model.</p></li>
-     * </ul>
+     * @cfg {Function} getClass
+     * A function which returns the CSS class to apply to the icon image.
+     *
+     * @cfg {Object} getClass.v The value of the column's configured field (if any).
+     *
+     * @cfg {Object} getClass.metadata An object in which you may set the following attributes:
+     * @cfg {String} getClass.metadata.css A CSS class name to add to the cell's TD element.
+     * @cfg {String} getClass.metadata.attr An HTML attribute definition string to apply to the data container
+     * element *within* the table cell (e.g. 'style="color:red;"').
+     *
+     * @cfg {Ext.data.Model} getClass.r The Record providing the data.
+     *
+     * @cfg {Number} getClass.rowIndex The row index..
+     *
+     * @cfg {Number} getClass.colIndex The column index.
+     *
+     * @cfg {Ext.data.Store} getClass.store The Store which is providing the data Model.
      */
     /**
-     * @cfg {Array} items An Array which may contain multiple icon definitions, each element of which may contain:
-     * <div class="mdetail-params"><ul>
-     * <li><code>icon</code> : String<div class="sub-desc">The url of an image to display as the clickable element 
-     * in the column.</div></li>
-     * <li><code>iconCls</code> : String<div class="sub-desc">A CSS class to apply to the icon image.
-     * To determine the class dynamically, configure the item with a <code>getClass</code> function.</div></li>
-     * <li><code>getClass</code> : Function<div class="sub-desc">A function which returns the CSS class to apply to the icon image.
-     * The function is passed the following parameters:<ul>
-     *     <li><b>v</b> : Object<p class="sub-desc">The value of the column's configured field (if any).</p></li>
-     *     <li><b>metadata</b> : Object<p class="sub-desc">An object in which you may set the following attributes:<ul>
-     *         <li><b>css</b> : String<p class="sub-desc">A CSS class name to add to the cell's TD element.</p></li>
-     *         <li><b>attr</b> : String<p class="sub-desc">An HTML attribute definition string to apply to the data container element <i>within</i> the table cell
-     *         (e.g. 'style="color:red;"').</p></li>
-     *     </ul></p></li>
-     *     <li><b>r</b> : Ext.data.Record<p class="sub-desc">The Record providing the data.</p></li>
-     *     <li><b>rowIndex</b> : Number<p class="sub-desc">The row index..</p></li>
-     *     <li><b>colIndex</b> : Number<p class="sub-desc">The column index.</p></li>
-     *     <li><b>store</b> : Ext.data.Store<p class="sub-desc">The Store which is providing the data Model.</p></li>
-     * </ul></div></li>
-     * <li><code>handler</code> : Function<div class="sub-desc">A function called when the icon is clicked.</div></li>
-     * <li><code>scope</code> : Scope<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the 
-     * <code>handler</code> and <code>getClass</code> functions are executed. Fallback defaults are this Column's
-     * configured scope, then this Column.</div></li>
-     * <li><code>tooltip</code> : String<div class="sub-desc">A tooltip message to be displayed on hover. 
-     * {@link Ext.tip.QuickTipManager#init Ext.tip.QuickTipManager} must have been initialized.</div></li>
-     * </ul></div>
+     * @cfg {Object[]} items
+     * An Array which may contain multiple icon definitions, each element of which may contain:
+     *
+     * @cfg {String} items.icon The url of an image to display as the clickable element in the column.
+     *
+     * @cfg {String} items.iconCls A CSS class to apply to the icon image. To determine the class dynamically,
+     * configure the item with a `getClass` function.
+     *
+     * @cfg {Function} items.getClass A function which returns the CSS class to apply to the icon image.
+     * @cfg {Object} items.getClass.v The value of the column's configured field (if any).
+     * @cfg {Object} items.getClass.metadata An object in which you may set the following attributes:
+     * @cfg {String} items.getClass.metadata.css A CSS class name to add to the cell's TD element.
+     * @cfg {String} items.getClass.metadata.attr An HTML attribute definition string to apply to the data
+     * container element _within_ the table cell (e.g. 'style="color:red;"').
+     * @cfg {Ext.data.Model} items.getClass.r The Record providing the data.
+     * @cfg {Number} items.getClass.rowIndex The row index..
+     * @cfg {Number} items.getClass.colIndex The column index.
+     * @cfg {Ext.data.Store} items.getClass.store The Store which is providing the data Model.
+     *
+     * @cfg {Function} items.handler A function called when the icon is clicked.
+     *
+     * @cfg {Object} items.scope The scope (`this` reference) in which the `handler` and `getClass` functions
+     * are executed. Fallback defaults are this Column's configured scope, then this Column.
+     *
+     * @cfg {String} items.tooltip A tooltip message to be displayed on hover.
+     * @cfg {Boolean} items.disabled If true, the action will not respond to click events, and will be displayed semi-opaque.
+     * {@link Ext.tip.QuickTipManager#init Ext.tip.QuickTipManager} must have been initialized.
+     */
+    /**
+     * @property {Array} items
+     * An array of action items copied from the configured {@link #cfg-items items} configuration. Each will have
+     * an `enable` and `disable` method added which will enable and disable the associated action, and
+     * update the displayed icon accordingly.
      */
     header: '&#160;',
 
-    actionIdRe: /x-action-col-(\d+)/,
+    actionIdRe: new RegExp(Ext.baseCSSPrefix + 'action-col-(\\d+)'),
 
     /**
-     * @cfg {String} altText The alt text to use for the image element. Defaults to <tt>''</tt>.
+     * @cfg {String} altText
+     * The alt text to use for the image element.
      */
     altText: '',
-    
+
     sortable: false,
 
     constructor: function(config) {
@@ -93431,7 +97483,7 @@ Ext.define('Ext.grid.column.Action', {
         // Items is an array property of ActionColumns
         me.items = items;
 
-//      Renderer closure iterates through items creating an <img> element for each and tagging with an identifying 
+//      Renderer closure iterates through items creating an <img> element for each and tagging with an identifying
 //      class name x-action-col-{n}
         me.renderer = function(v, meta) {
 //          Allow a configured renderer to create initial value (And set the other values in the "metadata" argument!)
@@ -93440,8 +97492,10 @@ Ext.define('Ext.grid.column.Action', {
             meta.tdCls += ' ' + Ext.baseCSSPrefix + 'action-col-cell';
             for (i = 0; i < l; i++) {
                 item = items[i];
+                item.disable = Ext.Function.bind(me.disableAction, me, [i]);
+                item.enable = Ext.Function.bind(me.enableAction, me, [i]);
                 v += '<img alt="' + (item.altText || me.altText) + '" src="' + (item.icon || Ext.BLANK_IMAGE_URL) +
-                    '" class="' + Ext.baseCSSPrefix + 'action-col-icon ' + Ext.baseCSSPrefix + 'action-col-' + String(i) + ' ' +  (item.iconCls || '') + 
+                    '" class="' + Ext.baseCSSPrefix + 'action-col-icon ' + Ext.baseCSSPrefix + 'action-col-' + String(i) + ' ' + (item.disabled ? Ext.baseCSSPrefix + 'item-disabled' : ' ') + (item.iconCls || '') +
                     ' ' + (Ext.isFunction(item.getClass) ? item.getClass.apply(item.scope||me.scope||me, arguments) : (me.iconCls || '')) + '"' +
                     ((item.tooltip) ? ' data-qtip="' + item.tooltip + '"' : '') + ' />';
             }
@@ -93449,6 +97503,36 @@ Ext.define('Ext.grid.column.Action', {
         };
     },
 
+    /**
+     * Enables this ActionColumn's action at the specified index.
+     */
+    enableAction: function(index) {
+        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);
+    },
+
+    /**
+     * Disables this ActionColumn's action at the specified index.
+     */
+    disableAction: function(index) {
+        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);
+    },
+
     destroy: function() {
         delete this.items;
         delete this.renderer;
@@ -93465,12 +97549,13 @@ Ext.define('Ext.grid.column.Action', {
         var me = this,
             match = e.getTarget().className.match(me.actionIdRe),
             item, fn;
+            
         if (match) {
             item = me.items[parseInt(match[1], 10)];
             if (item) {
                 if (type == 'click') {
                     fn = item.handler || me.handler;
-                    if (fn) {
+                    if (fn && !item.disabled) {
                         fn.call(item.scope || me.scope || me, view, recordIndex, cellIndex, item, e);
                     }
                 } else if (type == 'mousedown' && item.stopSelection !== false) {
@@ -93491,14 +97576,10 @@ Ext.define('Ext.grid.column.Action', {
     }
 });
 /**
- * @class Ext.grid.column.Boolean
- * @extends Ext.grid.column.Column
- * <p>A Column definition class which renders boolean data fields.  See the {@link Ext.grid.column.Column#xtype xtype}
- * config option of {@link Ext.grid.column.Column} for more details.</p>
+ * A Column definition class which renders boolean data fields.  See the {@link Ext.grid.column.Column#xtype xtype}
+ * config option of {@link Ext.grid.column.Column} for more details.
  *
- * {@img Ext.grid.column.Boolean/Ext.grid.column.Boolean.png Ext.grid.column.Boolean grid column}
- *
- * ## Code
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *        storeId:'sampleStore',
  *        fields:[
@@ -93506,10 +97587,10 @@ Ext.define('Ext.grid.column.Action', {
  *            {name: 'rocks', type: 'boolean'}
  *        ],
  *        data:{'items':[
- *            {"framework":"Ext JS 4", "rocks":true},
- *            {"framework":"Sencha Touch", "rocks":true},
- *            {"framework":"Ext GWT", "rocks":true},            
- *            {"framework":"Other Guys", "rocks":false}            
+ *            { 'framework': "Ext JS 4",     'rocks': true  },
+ *            { 'framework': "Sencha Touch", 'rocks': true  },
+ *            { 'framework': "Ext GWT",      'rocks': true  }, 
+ *            { 'framework': "Other Guys",   'rocks': false } 
  *        ]},
  *        proxy: {
  *            type: 'memory',
@@ -93524,13 +97605,14 @@ Ext.define('Ext.grid.column.Action', {
  *         title: 'Boolean Column Demo',
  *         store: Ext.data.StoreManager.lookup('sampleStore'),
  *         columns: [
- *             {text: 'Framework',  dataIndex: 'framework', flex: 1},
+ *             { text: 'Framework',  dataIndex: 'framework', flex: 1 },
  *             {
  *                 xtype: 'booleancolumn', 
  *                 text: 'Rocks',
  *                 trueText: 'Yes',
  *                 falseText: 'No', 
- *                 dataIndex: 'rocks'}
+ *                 dataIndex: 'rocks'
+ *             }
  *         ],
  *         height: 200,
  *         width: 400,
@@ -93544,20 +97626,19 @@ Ext.define('Ext.grid.column.Boolean', {
 
     /**
      * @cfg {String} trueText
-     * The string returned by the renderer when the column value is not falsey (defaults to <tt>'true'</tt>).
+     * The string returned by the renderer when the column value is not falsey.
      */
     trueText: 'true',
 
     /**
      * @cfg {String} falseText
-     * The string returned by the renderer when the column value is falsey (but not undefined) (defaults to
-     * <tt>'false'</tt>).
+     * The string returned by the renderer when the column value is falsey (but not undefined).
      */
     falseText: 'false',
 
     /**
      * @cfg {String} undefinedText
-     * The string returned by the renderer when the column value is undefined (defaults to <tt>'&#160;'</tt>).
+     * The string returned by the renderer when the column value is undefined.
      */
     undefinedText: '&#160;',
 
@@ -93579,30 +97660,24 @@ Ext.define('Ext.grid.column.Boolean', {
     }
 });
 /**
- * @class Ext.grid.column.Date
- * @extends Ext.grid.column.Column
- *
  * A Column definition class which renders a passed date according to the default locale, or a configured
  * {@link #format}.
  *
- * {@img Ext.grid.column.Date/Ext.grid.column.Date.png Ext.grid.column.Date grid column}
- *
- * ## Code
- *
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *         storeId:'sampleStore',
  *         fields:[
- *             {name: 'symbol', type: 'string'},
- *             {name: 'date', type: 'date'},
- *             {name: 'change', type: 'number'},
- *             {name: 'volume', type: 'number'},
- *             {name: 'topday', type: 'date'}                        
+ *             { name: 'symbol', type: 'string' },
+ *             { name: 'date',   type: 'date' },
+ *             { name: 'change', type: 'number' },
+ *             { name: 'volume', type: 'number' },
+ *             { name: 'topday', type: 'date' }                        
  *         ],
  *         data:[
- *             {symbol:"msft", date:'2011/04/22', change:2.43, volume:61606325, topday:'04/01/2010'},
- *             {symbol:"goog", date:'2011/04/22', change:0.81, volume:3053782, topday:'04/11/2010'},
- *             {symbol:"apple", date:'2011/04/22', change:1.35, volume:24484858, topday:'04/28/2010'},            
- *             {symbol:"sencha", date:'2011/04/22', change:8.85, volume:5556351, topday:'04/22/2010'}            
+ *             { symbol: "msft",   date: '2011/04/22', change: 2.43, volume: 61606325, topday: '04/01/2010' },
+ *             { symbol: "goog",   date: '2011/04/22', change: 0.81, volume: 3053782,  topday: '04/11/2010' },
+ *             { symbol: "apple",  date: '2011/04/22', change: 1.35, volume: 24484858, topday: '04/28/2010' },            
+ *             { symbol: "sencha", date: '2011/04/22', change: 8.85, volume: 5556351,  topday: '04/22/2010' }            
  *         ]
  *     });
  *     
@@ -93610,11 +97685,11 @@ Ext.define('Ext.grid.column.Boolean', {
  *         title: 'Date Column Demo',
  *         store: Ext.data.StoreManager.lookup('sampleStore'),
  *         columns: [
- *             {text: 'Symbol',  dataIndex: 'symbol', flex: 1},
- *             {text: 'Date',  dataIndex: 'date', xtype: 'datecolumn', format:'Y-m-d'},
- *             {text: 'Change',  dataIndex: 'change', xtype: 'numbercolumn', format:'0.00'},
- *             {text: 'Volume',  dataIndex: 'volume', xtype: 'numbercolumn', format:'0,000'},
- *             {text: 'Top Day',  dataIndex: 'topday', xtype: 'datecolumn', format:'l'}            
+ *             { text: 'Symbol',   dataIndex: 'symbol', flex: 1 },
+ *             { text: 'Date',     dataIndex: 'date',   xtype: 'datecolumn',   format:'Y-m-d' },
+ *             { text: 'Change',   dataIndex: 'change', xtype: 'numbercolumn', format:'0.00' },
+ *             { text: 'Volume',   dataIndex: 'volume', xtype: 'numbercolumn', format:'0,000' },
+ *             { text: 'Top Day',  dataIndex: 'topday', xtype: 'datecolumn',   format:'l' }            
  *         ],
  *         height: 200,
  *         width: 450,
@@ -93633,35 +97708,34 @@ Ext.define('Ext.grid.column.Date', {
      * This defaults to the default date from {@link Ext.Date#defaultFormat} which itself my be overridden
      * in a locale file.
      */
-    format : Ext.Date.defaultFormat,
 
-    constructor: function(cfg){
-        this.callParent(arguments);
-        this.renderer = Ext.util.Format.dateRenderer(this.format);
+    initComponent: function(){
+        var me = this;
+        
+        me.callParent(arguments);
+        if (!me.format) {
+            me.format = Ext.Date.defaultFormat;
+        }
+        me.renderer = Ext.util.Format.dateRenderer(me.format);
     }
 });
 /**
- * @class Ext.grid.column.Number
- * @extends Ext.grid.column.Column
- *
  * A Column definition class which renders a numeric data field according to a {@link #format} string.
  *
- * {@img Ext.grid.column.Number/Ext.grid.column.Number.png Ext.grid.column.Number cell editing}
- *
- * ## Code
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *        storeId:'sampleStore',
  *        fields:[
- *            {name: 'symbol', type: 'string'},
- *            {name: 'price', type: 'number'},
- *            {name: 'change', type: 'number'},
- *            {name: 'volume', type: 'number'},            
+ *            { name: 'symbol', type: 'string' },
+ *            { name: 'price',  type: 'number' },
+ *            { name: 'change', type: 'number' },
+ *            { name: 'volume', type: 'number' },            
  *        ],
  *        data:[
- *            {symbol:"msft", price:25.76, change:2.43, volume:61606325},
- *            {symbol:"goog", price:525.73, change:0.81, volume:3053782},
- *            {symbol:"apple", price:342.41, change:1.35, volume:24484858},            
- *            {symbol:"sencha", price:142.08, change:8.85, volume:5556351}            
+ *            { symbol: "msft",   price: 25.76,  change: 2.43, volume: 61606325 },
+ *            { symbol: "goog",   price: 525.73, change: 0.81, volume: 3053782  },
+ *            { symbol: "apple",  price: 342.41, change: 1.35, volume: 24484858 },            
+ *            { symbol: "sencha", price: 142.08, change: 8.85, volume: 5556351  }            
  *        ]
  *     });
  *     
@@ -93669,10 +97743,10 @@ Ext.define('Ext.grid.column.Date', {
  *         title: 'Number Column Demo',
  *         store: Ext.data.StoreManager.lookup('sampleStore'),
  *         columns: [
- *             {text: 'Symbol',  dataIndex: 'symbol', flex: 1},
- *             {text: 'Current Price',  dataIndex: 'price', renderer: Ext.util.Format.usMoney},
- *             {text: 'Change',  dataIndex: 'change', xtype: 'numbercolumn', format:'0.00'},
- *             {text: 'Volume',  dataIndex: 'volume', xtype: 'numbercolumn', format:'0,000'}
+ *             { text: 'Symbol',         dataIndex: 'symbol', flex: 1 },
+ *             { text: 'Current Price',  dataIndex: 'price',  renderer: Ext.util.Format.usMoney },
+ *             { text: 'Change',         dataIndex: 'change', xtype: 'numbercolumn', format:'0.00' },
+ *             { text: 'Volume',         dataIndex: 'volume', xtype: 'numbercolumn', format:'0,000' }
  *         ],
  *         height: 200,
  *         width: 400,
@@ -93687,35 +97761,31 @@ Ext.define('Ext.grid.column.Number', {
 
     /**
      * @cfg {String} format
-     * A formatting string as used by {@link Ext.util.Format#number} to format a numeric value for this Column
-     * (defaults to <code>'0,000.00'</code>).
+     * A formatting string as used by {@link Ext.util.Format#number} to format a numeric value for this Column.
      */
     format : '0,000.00',
+
     constructor: function(cfg) {
         this.callParent(arguments);
         this.renderer = Ext.util.Format.numberRenderer(this.format);
     }
 });
 /**
- * @class Ext.grid.column.Template
- * @extends Ext.grid.column.Column
- * 
  * A Column definition class which renders a value by processing a {@link Ext.data.Model Model}'s
- * {@link Ext.data.Model#data data} using a {@link #tpl configured} {@link Ext.XTemplate XTemplate}.
+ * {@link Ext.data.Model#persistenceProperty data} using a {@link #tpl configured}
+ * {@link Ext.XTemplate XTemplate}.
  * 
- *  {@img Ext.grid.column.Template/Ext.grid.column.Template.png Ext.grid.column.Template grid column}
- * 
- * ## Code
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *         storeId:'employeeStore',
  *         fields:['firstname', 'lastname', 'senority', 'department'],
  *         groupField: 'department',
  *         data:[
- *             {firstname:"Michael", lastname:"Scott", senority:7, department:"Manangement"},
- *             {firstname:"Dwight", lastname:"Schrute", senority:2, department:"Sales"},
- *             {firstname:"Jim", lastname:"Halpert", senority:3, department:"Sales"},
- *             {firstname:"Kevin", lastname:"Malone", senority:4, department:"Accounting"},
- *             {firstname:"Angela", lastname:"Martin", senority:5, department:"Accounting"}                        
+ *             { firstname: "Michael", lastname: "Scott",   senority: 7, department: "Manangement" },
+ *             { firstname: "Dwight",  lastname: "Schrute", senority: 2, department: "Sales" },
+ *             { firstname: "Jim",     lastname: "Halpert", senority: 3, department: "Sales" },
+ *             { firstname: "Kevin",   lastname: "Malone",  senority: 4, department: "Accounting" },
+ *             { firstname: "Angela",  lastname: "Martin",  senority: 5, department: "Accounting" }                        
  *         ]
  *     });
  *     
@@ -93723,15 +97793,13 @@ Ext.define('Ext.grid.column.Number', {
  *         title: 'Column Template Demo',
  *         store: Ext.data.StoreManager.lookup('employeeStore'),
  *         columns: [
- *             {text: 'Full Name',  xtype:'templatecolumn', tpl:'{firstname} {lastname}', flex:1},
- *             {text: 'Deparment (Yrs)', xtype:'templatecolumn', tpl:'{department} ({senority})'}
+ *             { text: 'Full Name',       xtype: 'templatecolumn', tpl: '{firstname} {lastname}', flex:1 },
+ *             { text: 'Deparment (Yrs)', xtype: 'templatecolumn', tpl: '{department} ({senority})' }
  *         ],
  *         height: 200,
  *         width: 300,
  *         renderTo: Ext.getBody()
  *     });
- * 
- * @markdown
  */
 Ext.define('Ext.grid.column.Template', {
     extend: 'Ext.grid.column.Column',
@@ -93740,10 +97808,12 @@ Ext.define('Ext.grid.column.Template', {
     alternateClassName: 'Ext.grid.TemplateColumn',
 
     /**
-     * @cfg {String/XTemplate} tpl
-     * An {@link Ext.XTemplate XTemplate}, or an XTemplate <i>definition string</i> to use to process a
-     * {@link Ext.data.Model Model}'s {@link Ext.data.Model#data data} to produce a column's rendered value.
+     * @cfg {String/Ext.XTemplate} tpl
+     * An {@link Ext.XTemplate XTemplate}, or an XTemplate *definition string* to use to process a
+     * {@link Ext.data.Model Model}'s {@link Ext.data.Model#persistenceProperty data} to produce a
+     * column's rendered value.
      */
+
     constructor: function(cfg){
         var me = this,
             tpl;
@@ -93841,6 +97911,7 @@ Ext.define('Ext.grid.feature.Feature', {
      *
      * The method must also return the eventName as the first index of the array
      * to be passed to fireEvent.
+     * @template
      */
     getFireEventArgs: function(eventName, view, featureTarget, e) {
         return [eventName, view, featureTarget, e];
@@ -93848,6 +97919,7 @@ Ext.define('Ext.grid.feature.Feature', {
     
     /**
      * Approriate place to attach events to the view, selectionmodel, headerCt, etc
+     * @template
      */
     attachEvents: function() {
         
@@ -93861,6 +97933,7 @@ Ext.define('Ext.grid.feature.Feature', {
      * Allows a feature to mutate the metaRowTpl.
      * The array received as a single argument can be manipulated to add things
      * on the end/begining of a particular row.
+     * @template
      */
     mutateMetaRowTpl: function(metaRowTplArray) {
         
@@ -93870,6 +97943,7 @@ Ext.define('Ext.grid.feature.Feature', {
      * Allows a feature to inject member methods into the metaRowTpl. This is
      * important for embedding functionality which will become part of the proper
      * row tpl.
+     * @template
      */
     getMetaRowTplFragments: function() {
         return {};
@@ -93885,6 +97959,7 @@ Ext.define('Ext.grid.feature.Feature', {
      * @param {Number} idx The row index for this record.
      * @param {Ext.data.Model} record The record instance
      * @param {Object} orig The original result from the prepareData call to massage.
+     * @template
      */
     getAdditionalData: function(data, idx, record, orig) {
         return {};
@@ -93931,7 +98006,7 @@ Ext.define('Ext.grid.feature.AbstractSummary', {
     
     /**
      * Toggle whether or not to show the summary row.
-     * @param {Boolan} visible True to show the summary row
+     * @param {Boolean} visible True to show the summary row
      */
     toggleSummaryRow: function(visible){
         this.showSummaryRow = !!visible;
@@ -93959,9 +98034,10 @@ Ext.define('Ext.grid.feature.AbstractSummary', {
      * @return {String} The value of the summary row
      */
     printSummaryRow: function(index){
-        var inner = this.view.getTableChunker().metaRowTpl.join('');
+        var inner = this.view.getTableChunker().metaRowTpl.join(''),
+            prefix = Ext.baseCSSPrefix;
         
-        inner = inner.replace('x-grid-row', 'x-grid-row-summary');
+        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}');
@@ -94005,7 +98081,7 @@ Ext.define('Ext.grid.feature.AbstractSummary', {
      * be passed to the stores aggregate function.
      * @param {String} field The field to aggregate on
      * @param {Boolean} group True to aggregate in grouped mode 
-     * @return {Mixed} See the return type for the store functions.
+     * @return {Number/String/Object} See the return type for the store functions.
      */
     getSummary: function(store, type, field, group){
         if (type) {
@@ -94160,8 +98236,10 @@ Ext.define('Ext.grid.feature.Grouping', {
     eventSelector: '.' + Ext.baseCSSPrefix + 'grid-group-hd',
 
     constructor: function() {
-        this.collapsedState = {};
-        this.callParent(arguments);
+        var me = this;
+        
+        me.collapsedState = {};
+        me.callParent(arguments);
     },
     
     /**
@@ -94221,33 +98299,31 @@ Ext.define('Ext.grid.feature.Grouping', {
     hdCollapsedCls: Ext.baseCSSPrefix + 'grid-group-hd-collapsed',
 
     /**
-     * @cfg {String} groupByText Text displayed in the grid header menu for grouping by header
-     * (defaults to 'Group By This Field').
+     * @cfg {String} groupByText Text displayed in the grid header menu for grouping by header.
      */
     groupByText : 'Group By This Field',
     /**
-     * @cfg {String} showGroupsText Text displayed in the grid header for enabling/disabling grouping
-     * (defaults to 'Show in Groups').
+     * @cfg {String} showGroupsText Text displayed in the grid header for enabling/disabling grouping.
      */
     showGroupsText : 'Show in Groups',
 
     /**
-     * @cfg {Boolean} hideGroupedHeader<tt>true</tt> to hide the header that is currently grouped (defaults to <tt>false</tt>)
+     * @cfg {Boolean} hideGroupedHeader<tt>true</tt> to hide the header that is currently grouped.
      */
     hideGroupedHeader : false,
 
     /**
-     * @cfg {Boolean} startCollapsed <tt>true</tt> to start all groups collapsed (defaults to <tt>false</tt>)
+     * @cfg {Boolean} startCollapsed <tt>true</tt> to start all groups collapsed
      */
     startCollapsed : false,
 
     /**
-     * @cfg {Boolean} enableGroupingMenu <tt>true</tt> to enable the grouping control in the header menu (defaults to <tt>true</tt>)
+     * @cfg {Boolean} enableGroupingMenu <tt>true</tt> to enable the grouping control in the header menu
      */
     enableGroupingMenu : true,
 
     /**
-     * @cfg {Boolean} enableNoGroups <tt>true</tt> to allow the user to turn off grouping (defaults to <tt>true</tt>)
+     * @cfg {Boolean} enableNoGroups <tt>true</tt> to allow the user to turn off grouping
      */
     enableNoGroups : true,
     
@@ -94257,33 +98333,46 @@ Ext.define('Ext.grid.feature.Grouping', {
             store = view.store,
             groupToggleMenuItem;
             
+        me.lastGroupField = me.getGroupField();
+
         if (me.lastGroupIndex) {
             store.group(me.lastGroupIndex);
         }
         me.callParent();
         groupToggleMenuItem = me.view.headerCt.getMenu().down('#groupToggleMenuItem');
         groupToggleMenuItem.setChecked(true, true);
-        view.refresh();
+        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;
-            store.groupers.clear();
+            me.block();
+            store.clearGrouping();
+            me.unblock();
         }
         
         me.callParent();
         groupToggleMenuItem = me.view.headerCt.getMenu().down('#groupToggleMenuItem');
         groupToggleMenuItem.setChecked(true, true);
         groupToggleMenuItem.setChecked(false, true);
-        view.refresh();
+        if (!remote) {
+            view.refresh();
+        }
+    },
+    
+    refreshIf: function() {
+        if (this.blockRefresh !== true) {
+            this.view.refresh();
+        }    
     },
 
     getFeatureTpl: function(values, parent, x, xcount) {
@@ -94323,8 +98412,7 @@ Ext.define('Ext.grid.feature.Grouping', {
     // perhaps rename to afterViewRender
     attachEvents: function() {
         var me = this,
-            view = me.view,
-            header, headerId, menu, menuItem;
+            view = me.view;
 
         view.on({
             scope: me,
@@ -94338,16 +98426,10 @@ Ext.define('Ext.grid.feature.Grouping', {
         if (me.enableGroupingMenu) {
             me.injectGroupingMenu();
         }
-
-        if (me.hideGroupedHeader) {
-            header = view.headerCt.down('gridcolumn[dataIndex=' + me.getGroupField() + ']');
-            headerId = header.id;
-            menu = view.headerCt.getMenu();
-            menuItem = menu.down('menuitem[headerId='+ headerId +']');
-            if (menuItem) {
-                menuItem.setChecked(false);
-            }
-        }
+        me.lastGroupField = me.getGroupField();
+        me.block();
+        me.onGroupChange();
+        me.unblock();
     },
     
     injectGroupingMenu: function() {
@@ -94380,6 +98462,7 @@ Ext.define('Ext.grid.feature.Grouping', {
         return function() {
             var o = Ext.grid.header.Container.prototype.getMenuItems.call(this);
             o.push('-', {
+                iconCls: Ext.baseCSSPrefix + 'group-by-icon',
                 itemId: 'groupMenuItem',
                 text: groupByText,
                 handler: groupMenuItemClick
@@ -94402,15 +98485,30 @@ Ext.define('Ext.grid.feature.Grouping', {
      * @private
      */
     onGroupMenuItemClick: function(menuItem, e) {
-        var menu = menuItem.parentMenu,
+        var me = this,
+            menu = menuItem.parentMenu,
             hdr  = menu.activeHeader,
-            view = this.view;
+            view = me.view,
+            store = view.store,
+            remote = store.remoteGroup;
 
-        delete this.lastGroupIndex;
-        this.enable();
-        view.store.group(hdr.dataIndex);
-        this.pruneGroupedHeader();
-        
+        delete me.lastGroupIndex;
+        me.block();
+        me.enable();
+        store.group(hdr.dataIndex);
+        me.pruneGroupedHeader();
+        me.unblock();
+        if (!remote) {
+            view.refresh();
+        }  
+    },
+    
+    block: function(){
+        this.blockRefresh = this.view.blockRefresh = true;
+    },
+    
+    unblock: function(){
+        this.blockRefresh = this.view.blockRefresh = false;
     },
 
     /**
@@ -94467,7 +98565,7 @@ Ext.define('Ext.grid.feature.Grouping', {
 
     /**
      * Expand a group by the groupBody
-     * @param {Ext.core.Element} groupBd
+     * @param {Ext.Element} groupBd
      * @private
      */
     expand: function(groupBd) {
@@ -94488,7 +98586,7 @@ Ext.define('Ext.grid.feature.Grouping', {
 
     /**
      * Collapse a group by the groupBody
-     * @param {Ext.core.Element} groupBd
+     * @param {Ext.Element} groupBd
      * @private
      */
     collapse: function(groupBd) {
@@ -94508,7 +98606,41 @@ Ext.define('Ext.grid.feature.Grouping', {
     },
     
     onGroupChange: function(){
-        this.view.refresh();
+        var me = this,
+            field = me.getGroupField(),
+            menuItem;
+            
+        if (me.hideGroupedHeader) {
+            if (me.lastGroupField) {
+                menuItem = me.getMenuItem(me.lastGroupField);
+                if (menuItem) {
+                    menuItem.setChecked(true);
+                }
+            }
+            if (field) {
+                menuItem = me.getMenuItem(field);
+                if (menuItem) {
+                    menuItem.setChecked(false);
+                }
+            }
+        }
+        if (me.blockRefresh !== true) {
+            me.view.refresh();
+        }
+        me.lastGroupField = field;
+    },
+    
+    /**
+     * Gets the related menu item for a dataIndex
+     * @private
+     * @return {Ext.grid.header.Container} The header
+     */
+    getMenuItem: function(dataIndex){
+        var view = this.view,
+            header = view.headerCt.down('gridcolumn[dataIndex=' + dataIndex + ']'),
+            menu = view.headerCt.getMenu();
+            
+        return menu.down('menuitem[headerId='+ header.id +']');
     },
 
     /**
@@ -94633,12 +98765,12 @@ Ext.define('Ext.grid.feature.Grouping', {
 /**
  * @class Ext.grid.feature.GroupingSummary
  * @extends Ext.grid.feature.Grouping
- * 
+ *
  * This feature adds an aggregate summary row at the bottom of each group that is provided
- * by the {@link Ext.grid.feature.Grouping} feature. There are 2 aspects to the summary:
- * 
+ * by the {@link Ext.grid.feature.Grouping} feature. There are two aspects to the summary:
+ *
  * ## Calculation
- * 
+ *
  * The summary value needs to be calculated for each column in the grid. This is controlled
  * by the summaryType option specified on the column. There are several built in summary types,
  * which can be specified as a string on the column configuration. These call underlying methods
@@ -94652,9 +98784,9 @@ Ext.define('Ext.grid.feature.Grouping', {
  *
  * Alternatively, the summaryType can be a function definition. If this is the case,
  * the function is called with an array of records to calculate the summary value.
- * 
+ *
  * ## Rendering
- * 
+ *
  * Similar to a column, the summary also supports a summaryRenderer function. This
  * summaryRenderer is called before displaying a value. The function is optional, if
  * not specified the default calculated value is shown. The summaryRenderer is called with:
@@ -94662,9 +98794,10 @@ Ext.define('Ext.grid.feature.Grouping', {
  *  - value {Object} - The calculated value.
  *  - summaryData {Object} - Contains all raw summary values for the row.
  *  - field {String} - The name of the field we are calculating
- * 
+ *
  * ## Example Usage
  *
+ *     @example
  *     Ext.define('TestResult', {
  *         extend: 'Ext.data.Model',
  *         fields: ['student', 'subject', {
@@ -94672,7 +98805,7 @@ Ext.define('Ext.grid.feature.Grouping', {
  *             type: 'int'
  *         }]
  *     });
- *     
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         width: 200,
  *         height: 240,
@@ -94707,7 +98840,7 @@ Ext.define('Ext.grid.feature.Grouping', {
  *             text: 'Name',
  *             summaryType: 'count',
  *             summaryRenderer: function(value){
- *                 return Ext.String.format('{0} student{1}', value, value !== 1 ? 's' : ''); 
+ *                 return Ext.String.format('{0} student{1}', value, value !== 1 ? 's' : '');
  *             }
  *         }, {
  *             dataIndex: 'mark',
@@ -94717,20 +98850,20 @@ Ext.define('Ext.grid.feature.Grouping', {
  *     });
  */
 Ext.define('Ext.grid.feature.GroupingSummary', {
-    
+
     /* Begin Definitions */
-    
+
     extend: 'Ext.grid.feature.Grouping',
-    
+
     alias: 'feature.groupingsummary',
-    
+
     mixins: {
         summary: 'Ext.grid.feature.AbstractSummary'
     },
-    
+
     /* End Definitions */
 
-     
+
    /**
     * Modifies the row template to include the summary row.
     * @private
@@ -94738,7 +98871,7 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
     */
    getFeatureTpl: function() {
         var tpl = this.callParent(arguments);
-            
+
         if (this.showSummaryRow) {
             // lop off the end </tpl> so we can attach it
             tpl = tpl.replace('</tpl>', '');
@@ -94746,7 +98879,7 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
         }
         return tpl;
     },
-    
+
     /**
      * Gets any fragments needed for the template.
      * @private
@@ -94755,7 +98888,7 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
     getFragmentTpl: function() {
         var me = this,
             fragments = me.callParent();
-            
+
         Ext.apply(fragments, me.getSummaryFragments());
         if (me.showSummaryRow) {
             // this gets called before render, so we'll setup the data here.
@@ -94764,7 +98897,7 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
         }
         return fragments;
     },
-    
+
     /**
      * Gets the data for printing a template row
      * @private
@@ -94780,7 +98913,7 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
             name = me.summaryGroups[index - 1].name,
             active = me.summaryData[name],
             column;
-            
+
         for (; i < length; ++i) {
             column = columns[i];
             column.gridSummaryValue = this.getColumnValue(column, active);
@@ -94788,7 +98921,7 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
         }
         return data;
     },
-    
+
     /**
      * Generates all of the summary data to be used when processing the template
      * @private
@@ -94810,16 +98943,15 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
             root,
             key,
             comp;
-            
+
         for (i = 0, length = groups.length; i < length; ++i) {
             data[groups[i].name] = {};
         }
-        
-    /**
-     * @cfg {String} remoteRoot.  The name of the property
-     * which contains the Array of summary objects.  Defaults to <tt>undefined</tt>.
-     * It allows to use server-side calculated summaries.
-     */
+
+        /**
+         * @cfg {String} [remoteRoot=undefined]  The name of the property which contains the Array of
+         * summary objects. It allows to use server-side calculated summaries.
+         */
         if (me.remoteRoot && reader.rawData) {
             // reset reader root and rebuild extractors to extract summaries data
             root = reader.root;
@@ -94832,21 +98964,21 @@ Ext.define('Ext.grid.feature.GroupingSummary', {
             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) {
+                    if (remote !== undefined && data[key] !== undefined) {
                         data[key][comp.id] = remote;
                     }
                 }
@@ -95040,6 +99172,7 @@ Ext.define('Ext.grid.feature.RowWrap', {
  * 
  * ## Example Usage
  *
+ *     @example
  *     Ext.define('TestResult', {
  *         extend: 'Ext.data.Model',
  *         fields: ['student', {
@@ -95272,7 +99405,7 @@ Ext.define('Ext.grid.header.DropZone', {
 
     getTopIndicator: function() {
         if (!this.topIndicator) {
-            this.topIndicator = Ext.core.DomHelper.append(Ext.getBody(), {
+            this.topIndicator = Ext.DomHelper.append(Ext.getBody(), {
                 cls: "col-move-top",
                 html: "&#160;"
             }, true);
@@ -95282,7 +99415,7 @@ Ext.define('Ext.grid.header.DropZone', {
 
     getBottomIndicator: function() {
         if (!this.bottomIndicator) {
-            this.bottomIndicator = Ext.core.DomHelper.append(Ext.getBody(), {
+            this.bottomIndicator = Ext.DomHelper.append(Ext.getBody(), {
                 cls: "col-move-bottom",
                 html: "&#160;"
             }, true);
@@ -95498,18 +99631,13 @@ Ext.define('Ext.grid.header.DropZone', {
     }
 });
 
-
 /**
- * @class Ext.grid.plugin.Editing
-
-This class provides an abstract grid editing plugin on selected {@link Ext.grid.column.Column columns}.
-The editable columns are specified by providing an {@link Ext.grid.column.Column#editor editor}
-in the {@link Ext.grid.column.Column column configuration}.
-
-*Note:* This class should not be used directly. See {@link Ext.grid.plugin.CellEditing} and
-{@link Ext.grid.plugin.RowEditing}.
-
- * @markdown
+ * This class provides an abstract grid editing plugin on selected {@link Ext.grid.column.Column columns}.
+ * The editable columns are specified by providing an {@link Ext.grid.column.Column#editor editor}
+ * in the {@link Ext.grid.column.Column column configuration}.
+ *
+ * **Note:** This class should not be used directly. See {@link Ext.grid.plugin.CellEditing} and
+ * {@link Ext.grid.plugin.RowEditing}.
  */
 Ext.define('Ext.grid.plugin.Editing', {
     alias: 'editing.editing',
@@ -95525,7 +99653,7 @@ Ext.define('Ext.grid.plugin.Editing', {
 
     /**
      * @cfg {Number} clicksToEdit
-     * The number of clicks on a grid required to display the editor (defaults to 2).
+     * The number of clicks on a grid required to display the editor.
      */
     clicksToEdit: 2,
 
@@ -95570,7 +99698,7 @@ Ext.define('Ext.grid.plugin.Editing', {
         grid.isEditable = true;
         grid.editingPlugin = grid.view.editingPlugin = me;
     },
-    
+
     /**
      * Fires after the grid is reconfigured
      * @private
@@ -95744,16 +99872,17 @@ Ext.define('Ext.grid.plugin.Editing', {
 
     /**
      * @private
-     * @abstract. Template method called before editing begins.
+     * @template
+     * Template method called before editing begins.
      * @param {Object} context The current editing context
      * @return {Boolean} Return false to cancel the editing process
      */
     beforeEdit: Ext.emptyFn,
 
     /**
-     * Start editing the specified record, using the specified Column definition to define which field is being edited.
-     * @param {Model} record The Store data record which backs the row to be edited.
-     * @param {Model} columnHeader The Column object defining the column to be edited.
+     * Starts editing the specified record, using the specified Column definition to define which field is being edited.
+     * @param {Ext.data.Model/Number} record The Store data record which backs the row to be edited, or index of the record in Store.
+     * @param {Ext.grid.column.Column/Number} columnHeader The Column object defining the column to be edited, or index of the column.
      */
     startEdit: function(record, columnHeader) {
         var me = this,
@@ -95768,7 +99897,8 @@ Ext.define('Ext.grid.plugin.Editing', {
     },
 
     /**
-     * @private Collects all information necessary for any subclasses to perform their editing functions.
+     * @private
+     * Collects all information necessary for any subclasses to perform their editing functions.
      * @param record
      * @param columnHeader
      * @returns {Object} The editing context based upon the passed record and column
@@ -95810,14 +99940,14 @@ Ext.define('Ext.grid.plugin.Editing', {
     },
 
     /**
-     * Cancel any active edit that is in progress.
+     * Cancels any active edit that is in progress.
      */
     cancelEdit: function() {
         this.editing = false;
     },
 
     /**
-     * Complete the edit if there is an active edit in progress.
+     * Completes the edit if there is an active edit in progress.
      */
     completeEdit: function() {
         var me = this;
@@ -95838,13 +99968,11 @@ Ext.define('Ext.grid.plugin.Editing', {
         return me.fireEvent('validateedit', me, context) !== false && !context.cancel;
     }
 });
+
 /**
- * @class Ext.grid.plugin.CellEditing
- * @extends Ext.grid.plugin.Editing
- *
  * The Ext.grid.plugin.CellEditing plugin injects editing at a cell level for a Grid. Only a single
  * cell will be editable at a time. The field that will be used for the editor is defined at the
- * {@link Ext.grid.column.Column#field field}. The editor can be a field instance or a field configuration.
+ * {@link Ext.grid.column.Column#editor editor}. The editor can be a field instance or a field configuration.
  *
  * If an editor is not specified for a particular column then that cell will not be editable and it will
  * be skipped when activated via the mouse or the keyboard.
@@ -95853,10 +99981,7 @@ Ext.define('Ext.grid.plugin.Editing', {
  * An appropriate field type should be chosen to match the data structure that it will be editing. For example,
  * to edit a date, it would be useful to specify {@link Ext.form.field.Date} as the editor.
  *
- * {@img Ext.grid.plugin.CellEditing/Ext.grid.plugin.CellEditing.png Ext.grid.plugin.CellEditing plugin}
- *
- * ## Example Usage
- *
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *         storeId:'simpsonsStore',
  *         fields:['name', 'email', 'phone'],
@@ -95874,16 +99999,16 @@ Ext.define('Ext.grid.plugin.Editing', {
  *             }
  *         }
  *     });
- *     
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Simpsons',
  *         store: Ext.data.StoreManager.lookup('simpsonsStore'),
  *         columns: [
- *             {header: 'Name',  dataIndex: 'name', field: 'textfield'},
+ *             {header: 'Name',  dataIndex: 'name', editor: 'textfield'},
  *             {header: 'Email', dataIndex: 'email', flex:1,
  *                 editor: {
- *                     xtype:'textfield',
- *                     allowBlank:false
+ *                     xtype: 'textfield',
+ *                     allowBlank: false
  *                 }
  *             },
  *             {header: 'Phone', dataIndex: 'phone'}
@@ -95907,79 +100032,73 @@ Ext.define('Ext.grid.plugin.CellEditing', {
     constructor: function() {
         /**
          * @event beforeedit
-         * Fires before cell editing is triggered. The edit event object has the following properties <br />
-         * <ul style="padding:5px;padding-left:16px;">
-         * <li>grid - The grid</li>
-         * <li>record - The record being edited</li>
-         * <li>field - The field name being edited</li>
-         * <li>value - The value for the field being edited.</li>
-         * <li>row - The grid table row</li>
-         * <li>column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.</li>
-         * <li>rowIdx - The row index that is being edited</li>
-         * <li>colIdx - The column index that is being edited</li>
-         * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
-         * </ul>
-         * @param {Ext.grid.plugin.Editing} editor
-         * @param {Object} e An edit event (see above for description)
+         * Fires before cell editing is triggered. Return false from event handler to stop the editing.
+         *
+         * @param {Object} e An edit event with the following properties:
+         *
+         * - grid - The grid
+         * - record - The record being edited
+         * - field - The field name being edited
+         * - value - The value for the field being edited.
+         * - row - The grid table row
+         * - column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.
+         * - rowIdx - The row index that is being edited
+         * - colIdx - The column index that is being edited
+         * - cancel - Set this to true to cancel the edit or return false from your handler.
          */
         /**
          * @event edit
-         * Fires after a cell is edited. The edit event object has the following properties <br />
-         * <ul style="padding:5px;padding-left:16px;">
-         * <li>grid - The grid</li>
-         * <li>record - The record that was edited</li>
-         * <li>field - The field name that was edited</li>
-         * <li>value - The value being set</li>
-         * <li>originalValue - The original value for the field, before the edit.</li>
-         * <li>row - The grid table row</li>
-         * <li>column - The grid {@link Ext.grid.column.Column Column} defining the column that was edited.</li>
-         * <li>rowIdx - The row index that was edited</li>
-         * <li>colIdx - The column index that was edited</li>
-         * </ul>
+         * Fires after a cell is edited. Usage example:
+         *
+         *     grid.on('edit', function(editor, e) {
+         *         // commit the changes right after editing finished
+         *         e.record.commit();
+         *     };
          *
-         * <pre><code>
-grid.on('edit', onEdit, this);
-
-function onEdit(e) {
-    // execute an XHR to send/commit data to the server, in callback do (if successful):
-    e.record.commit();
-};
-         * </code></pre>
          * @param {Ext.grid.plugin.Editing} editor
-         * @param {Object} e An edit event (see above for description)
+         * @param {Object} e An edit event with the following properties:
+         *
+         * - grid - The grid
+         * - record - The record that was edited
+         * - field - The field name that was edited
+         * - value - The value being set
+         * - originalValue - The original value for the field, before the edit.
+         * - row - The grid table row
+         * - column - The grid {@link Ext.grid.column.Column Column} defining the column that was edited.
+         * - rowIdx - The row index that was edited
+         * - colIdx - The column index that was edited
          */
         /**
          * @event validateedit
-         * Fires after a cell is edited, but before the value is set in the record. Return false
-         * to cancel the change. The edit event object has the following properties <br />
-         * <ul style="padding:5px;padding-left:16px;">
-         * <li>grid - The grid</li>
-         * <li>record - The record being edited</li>
-         * <li>field - The field name being edited</li>
-         * <li>value - The value being set</li>
-         * <li>originalValue - The original value for the field, before the edit.</li>
-         * <li>row - The grid table row</li>
-         * <li>column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.</li>
-         * <li>rowIdx - The row index that is being edited</li>
-         * <li>colIdx - The column index that is being edited</li>
-         * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
-         * </ul>
-         * Usage example showing how to remove the red triangle (dirty record indicator) from some
-         * records (not all).  By observing the grid's validateedit event, it can be cancelled if
-         * the edit occurs on a targeted row (for example) and then setting the field's new value
-         * in the Record directly:
-         * <pre><code>
-grid.on('validateedit', function(e) {
-  var myTargetRow = 6;
-
-  if (e.row == myTargetRow) {
-    e.cancel = true;
-    e.record.data[e.field] = e.value;
-  }
-});
-         * </code></pre>
+         * Fires after a cell is edited, but before the value is set in the record. Return false from event handler to
+         * cancel the change.
+         *
+         * Usage example showing how to remove the red triangle (dirty record indicator) from some records (not all). By
+         * observing the grid's validateedit event, it can be cancelled if the edit occurs on a targeted row (for
+         * example) and then setting the field's new value in the Record directly:
+         *
+         *     grid.on('validateedit', function(editor, e) {
+         *       var myTargetRow = 6;
+         *
+         *       if (e.row == myTargetRow) {
+         *         e.cancel = true;
+         *         e.record.data[e.field] = e.value;
+         *       }
+         *     });
+         *
          * @param {Ext.grid.plugin.Editing} editor
-         * @param {Object} e An edit event (see above for description)
+         * @param {Object} e An edit event with the following properties:
+         *
+         * - grid - The grid
+         * - record - The record being edited
+         * - field - The field name being edited
+         * - value - The value being set
+         * - originalValue - The original value for the field, before the edit.
+         * - row - The grid table row
+         * - column - The grid {@link Ext.grid.column.Column Column} defining the column that is being edited.
+         * - rowIdx - The row index that is being edited
+         * - colIdx - The column index that is being edited
+         * - cancel - Set this to true to cancel the edit or return false from your handler.
          */
         this.callParent(arguments);
         this.editors = Ext.create('Ext.util.MixedCollection', false, function(editor) {
@@ -96033,16 +100152,15 @@ grid.on('validateedit', function(e) {
     },
 
     /**
-     * Start editing the specified record, using the specified Column definition to define which field is being edited.
-     * @param {Model} record The Store data record which backs the row to be edited.
-     * @param {Model} columnHeader The Column object defining the column to be edited.
-     * @override
+     * Starts editing the specified record, using the specified Column definition to define which field is being edited.
+     * @param {Ext.data.Model} record The Store data record which backs the row to be edited.
+     * @param {Ext.data.Model} columnHeader The Column object defining the column to be edited. @override
      */
     startEdit: function(record, columnHeader) {
         var me = this,
-            ed   = me.getEditor(record, columnHeader),
             value = record.get(columnHeader.dataIndex),
-            context = me.getEditingContext(record, columnHeader);
+            context = me.getEditingContext(record, columnHeader),
+            ed;
 
         record = context.record;
         columnHeader = context.column;
@@ -96051,17 +100169,18 @@ grid.on('validateedit', function(e) {
         // cell DOM element. Completing the edit causes a view refresh.
         me.completeEdit();
 
+        context.originalValue = context.value = value;
+        if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', context) === false || context.cancel) {
+            return false;
+        }
+        
         // See if the field is editable for the requested record
         if (columnHeader && !columnHeader.getEditor(record)) {
             return false;
         }
-
+        
+        ed = me.getEditor(record, columnHeader);
         if (ed) {
-            context.originalValue = context.value = value;
-            if (me.beforeEdit(context) === false || me.fireEvent('beforeedit', context) === false || context.cancel) {
-                return false;
-            }
-
             me.context = context;
             me.setActiveEditor(ed);
             me.setActiveRecord(record);
@@ -96143,11 +100262,19 @@ grid.on('validateedit', function(e) {
             return editor;
         }
     },
+    
+    // inherit docs
+    setColumnField: function(column, field) {
+        var ed = this.editors.getByKey(column.getItemId());
+        Ext.destroy(ed, column.field);
+        this.editors.removeAtKey(column.getItemId());
+        this.callParent(arguments);
+    },
 
     /**
-     * Get the cell (td) for a particular record and column.
+     * Gets the cell (td) for a particular record and column.
      * @param {Ext.data.Model} record
-     * @param {Ext.grid.column.Colunm} column
+     * @param {Ext.grid.column.Column} column
      * @private
      */
     getCell: function(record, column) {
@@ -96194,13 +100321,11 @@ grid.on('validateedit', function(e) {
             }
             me.context.value = value;
             me.fireEvent('edit', me, me.context);
-            
-
         }
     },
 
     /**
-     * Cancel any active editing.
+     * Cancels any active editing.
      */
     cancelEdit: function() {
         var me = this,
@@ -96234,26 +100359,65 @@ grid.on('validateedit', function(e) {
     }
 });
 /**
- * @class Ext.grid.plugin.DragDrop
- * <p>This plugin provides drag and/or drop functionality for a GridView.</p>
- * <p>It creates a specialized instance of {@link Ext.dd.DragZone DragZone} which knows how to drag out of a {@link Ext.grid.View GridView}
- * and loads the data object which is passed to a cooperating {@link Ext.dd.DragZone DragZone}'s methods with the following properties:<ul>
- * <li>copy : Boolean
- *  <div class="sub-desc">The value of the GridView's <code>copy</code> property, or <code>true</code> if the GridView was configured
- *  with <code>allowCopy: true</code> <u>and</u> the control key was pressed when the drag operation was begun.</div></li>
- * <li>view : GridView
- *  <div class="sub-desc">The source GridView from which the drag originated.</div></li>
- * <li>ddel : HtmlElement
- *  <div class="sub-desc">The drag proxy element which moves with the mouse</div></li>
- * <li>item : HtmlElement
- *  <div class="sub-desc">The GridView node upon which the mousedown event was registered.</div></li>
- * <li>records : Array
- *  <div class="sub-desc">An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source GridView.</div></li>
- * </ul></p>
- * <p>It also creates a specialized instance of {@link Ext.dd.DropZone} which cooperates with other DropZones which are members of the same
- * ddGroup which processes such data objects.</p>
- * <p>Adding this plugin to a view means that two new events may be fired from the client GridView, <code>{@link #event-beforedrop beforedrop}</code> and
- * <code>{@link #event-drop drop}</code></p>
+ * This plugin provides drag and/or drop functionality for a GridView.
+ *
+ * It creates a specialized instance of {@link Ext.dd.DragZone DragZone} which knows how to drag out of a {@link
+ * Ext.grid.View GridView} and loads the data object which is passed to a cooperating {@link Ext.dd.DragZone DragZone}'s
+ * methods with the following properties:
+ *
+ * - `copy` : Boolean
+ *
+ *   The value of the GridView's `copy` property, or `true` if the GridView was configured with `allowCopy: true` _and_
+ *   the control key was pressed when the drag operation was begun.
+ *
+ * - `view` : GridView
+ *
+ *   The source GridView from which the drag originated.
+ *
+ * - `ddel` : HtmlElement
+ *
+ *   The drag proxy element which moves with the mouse
+ *
+ * - `item` : HtmlElement
+ *
+ *   The GridView node upon which the mousedown event was registered.
+ *
+ * - `records` : Array
+ *
+ *   An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source GridView.
+ *
+ * It also creates a specialized instance of {@link Ext.dd.DropZone} which cooperates with other DropZones which are
+ * members of the same ddGroup which processes such data objects.
+ *
+ * Adding this plugin to a view means that two new events may be fired from the client GridView, `{@link #beforedrop
+ * beforedrop}` and `{@link #drop drop}`
+ *
+ *     @example
+ *     Ext.create('Ext.data.Store', {
+ *         storeId:'simpsonsStore',
+ *         fields:['name'],
+ *         data: [["Lisa"], ["Bart"], ["Homer"], ["Marge"]],
+ *         proxy: {
+ *             type: 'memory',
+ *             reader: 'array'
+ *         }
+ *     });
+ *
+ *     Ext.create('Ext.grid.Panel', {
+ *         store: 'simpsonsStore',
+ *         columns: [
+ *             {header: 'Name',  dataIndex: 'name', flex: true}
+ *         ],
+ *         viewConfig: {
+ *             plugins: {
+ *                 ptype: 'gridviewdragdrop',
+ *                 dragText: 'Drag and drop to reorganize'
+ *             }
+ *         },
+ *         height: 200,
+ *         width: 400,
+ *         renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.grid.plugin.DragDrop', {
     extend: 'Ext.AbstractPlugin',
@@ -96266,94 +100430,131 @@ Ext.define('Ext.grid.plugin.DragDrop', {
 
     /**
      * @event beforedrop
-     * <p><b>This event is fired through the GridView. Add listeners to the GridView object</b></p>
-     * <p>Fired when a drop gesture has been triggered by a mouseup event in a valid drop position in the GridView.
-     * @param {HtmlElement} node The GridView node <b>if any</b> over which the mouse was positioned.</p>
-     * <p>Returning <code>false</code> to this event signals that the drop gesture was invalid, and if the drag proxy
-     * will animate back to the point from which the drag began.</p>
-     * <p>Returning <code>0</code> To this event signals that the data transfer operation should not take place, but
-     * that the gesture was valid, and that the repair operation should not take place.</p>
-     * <p>Any other return value continues with the data transfer operation.</p>
-     * @param {Object} data The data object gathered at mousedown time by the cooperating {@link Ext.dd.DragZone DragZone}'s
-     * {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following properties:<ul>
-     * <li>copy : Boolean
-     *  <div class="sub-desc">The value of the GridView's <code>copy</code> property, or <code>true</code> if the GridView was configured
-     *  with <code>allowCopy: true</code> and the control key was pressed when the drag operation was begun</div></li>
-     * <li>view : GridView
-     *  <div class="sub-desc">The source GridView from which the drag originated.</div></li>
-     * <li>ddel : HtmlElement
-     *  <div class="sub-desc">The drag proxy element which moves with the mouse</div></li>
-     * <li>item : HtmlElement
-     *  <div class="sub-desc">The GridView node upon which the mousedown event was registered.</div></li>
-     * <li>records : Array
-     *  <div class="sub-desc">An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source GridView.</div></li>
-     * </ul>
+     * **This event is fired through the GridView. Add listeners to the GridView object**
+     *
+     * Fired when a drop gesture has been triggered by a mouseup event in a valid drop position in the GridView.
+     *
+     * @param {HTMLElement} node The GridView node **if any** over which the mouse was positioned.
+     *
+     * Returning `false` to this event signals that the drop gesture was invalid, and if the drag proxy will animate
+     * back to the point from which the drag began.
+     *
+     * Returning `0` To this event signals that the data transfer operation should not take place, but that the gesture
+     * was valid, and that the repair operation should not take place.
+     *
+     * Any other return value continues with the data transfer operation.
+     *
+     * @param {Object} data The data object gathered at mousedown time by the cooperating {@link Ext.dd.DragZone
+     * DragZone}'s {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following properties:
+     *
+     * - copy : Boolean
+     *
+     *   The value of the GridView's `copy` property, or `true` if the GridView was configured with `allowCopy: true` and
+     *   the control key was pressed when the drag operation was begun
+     *
+     * - view : GridView
+     *
+     *   The source GridView from which the drag originated.
+     *
+     * - ddel : HtmlElement
+     *
+     *   The drag proxy element which moves with the mouse
+     *
+     * - item : HtmlElement
+     *
+     *   The GridView node upon which the mousedown event was registered.
+     *
+     * - records : Array
+     *
+     *   An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source GridView.
+     *
      * @param {Ext.data.Model} overModel The Model over which the drop gesture took place.
-     * @param {String} dropPosition <code>"before"</code> or <code>"after"</code> depending on whether the mouse is above or below the midline of the node.
-     * @param {Function} dropFunction <p>A function to call to complete the data transfer operation and either move or copy Model instances from the source
-     * View's Store to the destination View's Store.</p>
-     * <p>This is useful when you want to perform some kind of asynchronous processing before confirming
-     * the drop, such as an {@link Ext.window.MessageBox#confirm confirm} call, or an Ajax request.</p>
-     * <p>Return <code>0</code> from this event handler, and call the <code>dropFunction</code> at any time to perform the data transfer.</p>
+     *
+     * @param {String} dropPosition `"before"` or `"after"` depending on whether the mouse is above or below the midline
+     * of the node.
+     *
+     * @param {Function} dropFunction
+     *
+     * A function to call to complete the data transfer operation and either move or copy Model instances from the
+     * source View's Store to the destination View's Store.
+     *
+     * This is useful when you want to perform some kind of asynchronous processing before confirming the drop, such as
+     * an {@link Ext.window.MessageBox#confirm confirm} call, or an Ajax request.
+     *
+     * Return `0` from this event handler, and call the `dropFunction` at any time to perform the data transfer.
      */
 
     /**
      * @event drop
-     * <b>This event is fired through the GridView. Add listeners to the GridView object</b>
-     * Fired when a drop operation has been completed and the data has been moved or copied.
-     * @param {HtmlElement} node The GridView node <b>if any</b> over which the mouse was positioned.
-     * @param {Object} data The data object gathered at mousedown time by the cooperating {@link Ext.dd.DragZone DragZone}'s
-     * {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following properties:<ul>
-     * <li>copy : Boolean
-     *  <div class="sub-desc">The value of the GridView's <code>copy</code> property, or <code>true</code> if the GridView was configured
-     *  with <code>allowCopy: true</code> and the control key was pressed when the drag operation was begun</div></li>
-     * <li>view : GridView
-     *  <div class="sub-desc">The source GridView from which the drag originated.</div></li>
-     * <li>ddel : HtmlElement
-     *  <div class="sub-desc">The drag proxy element which moves with the mouse</div></li>
-     * <li>item : HtmlElement
-     *  <div class="sub-desc">The GridView node upon which the mousedown event was registered.</div></li>
-     * <li>records : Array
-     *  <div class="sub-desc">An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source GridView.</div></li>
-     * </ul>
+     * **This event is fired through the GridView. Add listeners to the GridView object** Fired when a drop operation
+     * has been completed and the data has been moved or copied.
+     *
+     * @param {HTMLElement} node The GridView node **if any** over which the mouse was positioned.
+     *
+     * @param {Object} data The data object gathered at mousedown time by the cooperating {@link Ext.dd.DragZone
+     * DragZone}'s {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following properties:
+     *
+     * - copy : Boolean
+     *
+     *   The value of the GridView's `copy` property, or `true` if the GridView was configured with `allowCopy: true` and
+     *   the control key was pressed when the drag operation was begun
+     *
+     * - view : GridView
+     *
+     *   The source GridView from which the drag originated.
+     *
+     * - ddel : HtmlElement
+     *
+     *   The drag proxy element which moves with the mouse
+     *
+     * - item : HtmlElement
+     *
+     *   The GridView node upon which the mousedown event was registered.
+     *
+     * - records : Array
+     *
+     *   An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source GridView.
+     *
      * @param {Ext.data.Model} overModel The Model over which the drop gesture took place.
-     * @param {String} dropPosition <code>"before"</code> or <code>"after"</code> depending on whether the mouse is above or below the midline of the node.
+     *
+     * @param {String} dropPosition `"before"` or `"after"` depending on whether the mouse is above or below the midline
+     * of the node.
      */
 
     dragText : '{0} selected row{1}',
 
     /**
      * @cfg {String} ddGroup
-     * A named drag drop group to which this object belongs.  If a group is specified, then both the DragZones and DropZone
-     * used by this plugin will only interact with other drag drop objects in the same group (defaults to 'TreeDD').
+     * A named drag drop group to which this object belongs. If a group is specified, then both the DragZones and
+     * DropZone used by this plugin will only interact with other drag drop objects in the same group.
      */
     ddGroup : "GridDD",
 
     /**
      * @cfg {String} dragGroup
-     * <p>The ddGroup to which the DragZone will belong.</p>
-     * <p>This defines which other DropZones the DragZone will interact with. Drag/DropZones only interact with other Drag/DropZones
-     * which are members of the same ddGroup.</p>
+     * The ddGroup to which the DragZone will belong.
+     *
+     * This defines which other DropZones the DragZone will interact with. Drag/DropZones only interact with other
+     * Drag/DropZones which are members of the same ddGroup.
      */
 
     /**
      * @cfg {String} dropGroup
-     * <p>The ddGroup to which the DropZone will belong.</p>
-     * <p>This defines which other DragZones the DropZone will interact with. Drag/DropZones only interact with other Drag/DropZones
-     * which are members of the same ddGroup.</p>
+     * The ddGroup to which the DropZone will belong.
+     *
+     * This defines which other DragZones the DropZone will interact with. Drag/DropZones only interact with other
+     * Drag/DropZones which are members of the same ddGroup.
      */
 
     /**
      * @cfg {Boolean} enableDrop
-     * <p>Defaults to <code>true</code></p>
-     * <p>Set to <code>false</code> to disallow the View from accepting drop gestures</p>
+     * False to disallow the View from accepting drop gestures.
      */
     enableDrop: true,
 
     /**
      * @cfg {Boolean} enableDrag
-     * <p>Defaults to <code>true</code></p>
-     * <p>Set to <code>false</code> to disallow dragging items from the View </p>
+     * False to disallow dragging items from the View.
      */
     enableDrag: true,
 
@@ -96369,6 +100570,28 @@ Ext.define('Ext.grid.plugin.DragDrop', {
         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;
 
@@ -96436,18 +100659,15 @@ Ext.define('Ext.grid.plugin.HeaderReorderer', {
 /**
  * @class Ext.grid.plugin.HeaderResizer
  * @extends Ext.util.Observable
- * 
+ *
  * Plugin to add header resizing functionality to a HeaderContainer.
  * Always resizing header to the left of the splitter you are resizing.
- * 
- * Todo: Consider RTL support, columns would always calculate to the right of
- *    the splitter instead of to the left.
  */
 Ext.define('Ext.grid.plugin.HeaderResizer', {
     extend: 'Ext.util.Observable',
     requires: ['Ext.dd.DragTracker', 'Ext.util.Region'],
     alias: 'plugin.gridheaderresizer',
-    
+
     disabled: false,
 
     /**
@@ -96518,9 +100738,10 @@ Ext.define('Ext.grid.plugin.HeaderResizer', {
             if (headerEl){
                 overHeader = Ext.getCmp(headerEl.id);
 
-                // On left edge, we are resizing the previous non-hidden, base level column.
+                // On left edge, go back to the previous non-hidden header.
                 if (overHeader.isOnLeftEdge(e)) {
-                    resizeHeader = overHeader.previousNode('gridcolumn:not([hidden]):not([isGroupHeader])');
+                    resizeHeader = overHeader.previousNode('gridcolumn:not([hidden])');
+
                 }
                 // Else, if on the right edge, we're resizing the column we are over
                 else if (overHeader.isOnRightEdge(e)) {
@@ -96534,14 +100755,15 @@ Ext.define('Ext.grid.plugin.HeaderResizer', {
                 // We *are* resizing
                 if (resizeHeader) {
                     // If we're attempting to resize a group header, that cannot be resized,
-                    // so find its last base level column header; Group headers are sized
+                    // so find its last visible leaf header; Group headers are sized
                     // by the size of their child headers.
                     if (resizeHeader.isGroupHeader) {
-                        resizeHeader = resizeHeader.getVisibleGridColumns();
-                        resizeHeader = resizeHeader[resizeHeader.length - 1];
+                        resizeHeader = resizeHeader.down(':not([isGroupHeader]):not([hidden]):last');
                     }
 
-                    if (resizeHeader && !(resizeHeader.fixed || this.disabled)) {
+                    // Check if the header is resizable. Continue checking the old "fixed" property, bug also
+                    // check whether the resizablwe property is set to false.
+                    if (resizeHeader && !(resizeHeader.fixed || (resizeHeader.resizable === false) || this.disabled)) {
                         this.activeHd = resizeHeader;
                         overHeader.el.dom.style.cursor = this.eResizeCursor;
                     }
@@ -96671,38 +100893,32 @@ Ext.define('Ext.grid.plugin.HeaderResizer', {
                 delete dragHd.flex;
             }
 
+            this.headerCt.suspendLayout = true;
+            dragHd.setWidth(this.origWidth + offset[0], false);
+
+            // In the case of forceFit, change the following Header width.
+            // Then apply the two width changes by laying out the owning HeaderContainer
             // If HeaderContainer is configured forceFit, inhibit upstream layout notification, so that
             // we can also shrink the following Header by an equal amount, and *then* inform the upstream layout.
             if (this.headerCt.forceFit) {
                 nextHd = dragHd.nextNode('gridcolumn:not([hidden]):not([isGroupHeader])');
                 if (nextHd) {
-                    this.headerCt.componentLayout.layoutBusy = true;
+                    delete nextHd.flex;
+                    nextHd.setWidth(nextHd.getWidth() - offset[0], false);
                 }
             }
-
-            // Non-flexed Headers may never be squeezed in the event of a shortfall so
-            // always set the minWidth to their current width.
-            dragHd.minWidth = this.origWidth + offset[0];
-            dragHd.setWidth(dragHd.minWidth);
-
-            // In the case of forceFit, change the following Header width.
-            // Then apply the two width changes by laying out the owning HeaderContainer
-            if (nextHd) {
-                delete nextHd.flex;
-                nextHd.setWidth(nextHd.getWidth() - offset[0]);
-                this.headerCt.componentLayout.layoutBusy = false;
-                this.headerCt.doComponentLayout();
-            }
+            this.headerCt.suspendLayout = false;
+            this.headerCt.doComponentLayout(this.headerCt.getFullWidth());
         }
     },
-    
+
     disable: function() {
         this.disabled = true;
         if (this.tracker) {
             this.tracker.disable();
         }
     },
-    
+
     enable: function() {
         this.disabled = false;
         if (this.tracker) {
@@ -96711,53 +100927,40 @@ Ext.define('Ext.grid.plugin.HeaderResizer', {
     }
 });
 /**
- * @class Ext.grid.plugin.RowEditing
- * @extends Ext.grid.plugin.Editing
- * 
  * The Ext.grid.plugin.RowEditing plugin injects editing at a row level for a Grid. When editing begins,
  * a small floating dialog will be shown for the appropriate row. Each editable column will show a field
  * for editing. There is a button to save or cancel all changes for the edit.
- * 
+ *
  * The field that will be used for the editor is defined at the
- * {@link Ext.grid.column.Column#field field}. The editor can be a field instance or a field configuration.
+ * {@link Ext.grid.column.Column#editor editor}. The editor can be a field instance or a field configuration.
  * If an editor is not specified for a particular column then that column won't be editable and the value of
  * the column will be displayed.
  *
  * The editor may be shared for each column in the grid, or a different one may be specified for each column.
  * An appropriate field type should be chosen to match the data structure that it will be editing. For example,
  * to edit a date, it would be useful to specify {@link Ext.form.field.Date} as the editor.
- * 
- * {@img Ext.grid.plugin.RowEditing/Ext.grid.plugin.RowEditing.png Ext.grid.plugin.RowEditing plugin}
- *
- * ## Example Usage
  *
+ *     @example
  *     Ext.create('Ext.data.Store', {
  *         storeId:'simpsonsStore',
  *         fields:['name', 'email', 'phone'],
- *         data:{'items':[
+ *         data: [
  *             {"name":"Lisa", "email":"lisa@simpsons.com", "phone":"555-111-1224"},
  *             {"name":"Bart", "email":"bart@simpsons.com", "phone":"555--222-1234"},
- *             {"name":"Homer", "email":"home@simpsons.com", "phone":"555-222-1244"},                        
- *             {"name":"Marge", "email":"marge@simpsons.com", "phone":"555-222-1254"}            
- *         ]},
- *         proxy: {
- *             type: 'memory',
- *             reader: {
- *                 type: 'json',
- *                 root: 'items'
- *             }
- *         }
+ *             {"name":"Homer", "email":"home@simpsons.com", "phone":"555-222-1244"},
+ *             {"name":"Marge", "email":"marge@simpsons.com", "phone":"555-222-1254"}
+ *         ]
  *     });
- *     
+ *
  *     Ext.create('Ext.grid.Panel', {
  *         title: 'Simpsons',
  *         store: Ext.data.StoreManager.lookup('simpsonsStore'),
  *         columns: [
- *             {header: 'Name',  dataIndex: 'name', field: 'textfield'},
- *             {header: 'Email', dataIndex: 'email', flex:1, 
+ *             {header: 'Name',  dataIndex: 'name', editor: 'textfield'},
+ *             {header: 'Email', dataIndex: 'email', flex:1,
  *                 editor: {
- *                     xtype:'textfield',
- *                     allowBlank:false
+ *                     xtype: 'textfield',
+ *                     allowBlank: false
  *                 }
  *             },
  *             {header: 'Phone', dataIndex: 'phone'}
@@ -96785,9 +100988,8 @@ Ext.define('Ext.grid.plugin.RowEditing', {
 
     /**
      * @cfg {Boolean} autoCancel
-     * `true` to automatically cancel any pending changes when the row editor begins editing a new row.
-     * `false` to force the user to explicitly cancel the pending changes. Defaults to `true`.
-     * @markdown
+     * True to automatically cancel any pending changes when the row editor begins editing a new row.
+     * False to force the user to explicitly cancel the pending changes. Defaults to true.
      */
     autoCancel: true,
 
@@ -96795,90 +100997,90 @@ Ext.define('Ext.grid.plugin.RowEditing', {
      * @cfg {Number} clicksToMoveEditor
      * The number of clicks to move the row editor to a new row while it is visible and actively editing another row.
      * This will default to the same value as {@link Ext.grid.plugin.Editing#clicksToEdit clicksToEdit}.
-     * @markdown
      */
 
     /**
      * @cfg {Boolean} errorSummary
-     * `true` to show a {@link Ext.tip.ToolTip tooltip} that summarizes all validation errors present
-     * in the row editor. Set to `false` to prevent the tooltip from showing. Defaults to `true`.
-     * @markdown
+     * True to show a {@link Ext.tip.ToolTip tooltip} that summarizes all validation errors present
+     * in the row editor. Set to false to prevent the tooltip from showing. Defaults to true.
      */
     errorSummary: true,
 
     /**
      * @event beforeedit
-     * Fires before row editing is triggered. The edit event object has the following properties <br />
-     * <ul style="padding:5px;padding-left:16px;">
-     * <li>grid - The grid this editor is on</li>
-     * <li>view - The grid view</li>
-     * <li>store - The grid store</li>
-     * <li>record - The record being edited</li>
-     * <li>row - The grid table row</li>
-     * <li>column - The grid {@link Ext.grid.column.Column Column} defining the column that initiated the edit</li>
-     * <li>rowIdx - The row index that is being edited</li>
-     * <li>colIdx - The column index that initiated the edit</li>
-     * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
-     * </ul>
+     * Fires before row editing is triggered.
+     *
      * @param {Ext.grid.plugin.Editing} editor
-     * @param {Object} e An edit event (see above for description)
+     * @param {Object} e An edit event with the following properties:
+     *
+     * - grid - The grid this editor is on
+     * - view - The grid view
+     * - store - The grid store
+     * - record - The record being edited
+     * - row - The grid table row
+     * - column - The grid {@link Ext.grid.column.Column Column} defining the column that initiated the edit
+     * - rowIdx - The row index that is being edited
+     * - colIdx - The column index that initiated the edit
+     * - cancel - Set this to true to cancel the edit or return false from your handler.
+     */
+    
+    /**
+     * @event canceledit
+     * Fires when the user has started editing a row but then cancelled the edit
+     * @param {Object} grid The grid
      */
+    
     /**
      * @event edit
-     * Fires after a row is edited. The edit event object has the following properties <br />
-     * <ul style="padding:5px;padding-left:16px;">
-     * <li>grid - The grid this editor is on</li>
-     * <li>view - The grid view</li>
-     * <li>store - The grid store</li>
-     * <li>record - The record being edited</li>
-     * <li>row - The grid table row</li>
-     * <li>column - The grid {@link Ext.grid.column.Column Column} defining the column that initiated the edit</li>
-     * <li>rowIdx - The row index that is being edited</li>
-     * <li>colIdx - The column index that initiated the edit</li>
-     * </ul>
+     * Fires after a row is edited. Usage example:
+     *
+     *     grid.on('edit', function(editor, e) {
+     *         // commit the changes right after editing finished
+     *         e.record.commit();
+     *     };
      *
-     * <pre><code>
-grid.on('edit', onEdit, this);
-
-function onEdit(e) {
-    // execute an XHR to send/commit data to the server, in callback do (if successful):
-    e.record.commit();
-};
-     * </code></pre>
      * @param {Ext.grid.plugin.Editing} editor
-     * @param {Object} e An edit event (see above for description)
+     * @param {Object} e An edit event with the following properties:
+     *
+     * - grid - The grid this editor is on
+     * - view - The grid view
+     * - store - The grid store
+     * - record - The record being edited
+     * - row - The grid table row
+     * - column - The grid {@link Ext.grid.column.Column Column} defining the column that initiated the edit
+     * - rowIdx - The row index that is being edited
+     * - colIdx - The column index that initiated the edit
      */
     /**
      * @event validateedit
-     * Fires after a cell is edited, but before the value is set in the record. Return false
-     * to cancel the change. The edit event object has the following properties <br />
-     * <ul style="padding:5px;padding-left:16px;">
-     * <li>grid - The grid this editor is on</li>
-     * <li>view - The grid view</li>
-     * <li>store - The grid store</li>
-     * <li>record - The record being edited</li>
-     * <li>row - The grid table row</li>
-     * <li>column - The grid {@link Ext.grid.column.Column Column} defining the column that initiated the edit</li>
-     * <li>rowIdx - The row index that is being edited</li>
-     * <li>colIdx - The column index that initiated the edit</li>
-     * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
-     * </ul>
-     * Usage example showing how to remove the red triangle (dirty record indicator) from some
-     * records (not all).  By observing the grid's validateedit event, it can be cancelled if
-     * the edit occurs on a targeted row (for example) and then setting the field's new value
-     * in the Record directly:
-     * <pre><code>
-grid.on('validateedit', function(e) {
-  var myTargetRow = 6;
-
-  if (e.rowIdx == myTargetRow) {
-    e.cancel = true;
-    e.record.data[e.field] = e.value;
-  }
-});
-     * </code></pre>
+     * Fires after a cell is edited, but before the value is set in the record. Return false to cancel the change. The
+     * edit event object has the following properties
+     *
+     * Usage example showing how to remove the red triangle (dirty record indicator) from some records (not all). By
+     * observing the grid's validateedit event, it can be cancelled if the edit occurs on a targeted row (for example)
+     * and then setting the field's new value in the Record directly:
+     *
+     *     grid.on('validateedit', function(editor, e) {
+     *       var myTargetRow = 6;
+     *
+     *       if (e.rowIdx == myTargetRow) {
+     *         e.cancel = true;
+     *         e.record.data[e.field] = e.value;
+     *       }
+     *     });
+     *
      * @param {Ext.grid.plugin.Editing} editor
-     * @param {Object} e An edit event (see above for description)
+     * @param {Object} e An edit event with the following properties:
+     *
+     * - grid - The grid this editor is on
+     * - view - The grid view
+     * - store - The grid store
+     * - record - The record being edited
+     * - row - The grid table row
+     * - column - The grid {@link Ext.grid.column.Column Column} defining the column that initiated the edit
+     * - rowIdx - The row index that is being edited
+     * - colIdx - The column index that initiated the edit
+     * - cancel - Set this to true to cancel the edit or return false from your handler.
      */
 
     constructor: function() {
@@ -96903,10 +101105,9 @@ grid.on('validateedit', function(e) {
     },
 
     /**
-     * Start editing the specified record, using the specified Column definition to define which field is being edited.
-     * @param {Model} record The Store data record which backs the row to be edited.
-     * @param {Model} columnHeader The Column object defining the column to be edited.
-     * @override
+     * Starts editing the specified record, using the specified Column definition to define which field is being edited.
+     * @param {Ext.data.Model} record The Store data record which backs the row to be edited.
+     * @param {Ext.data.Model} columnHeader The Column object defining the column to be edited. @override
      */
     startEdit: function(record, columnHeader) {
         var me = this,
@@ -96929,6 +101130,8 @@ grid.on('validateedit', function(e) {
         if (me.editing) {
             me.getEditor().cancelEdit();
             me.callParent(arguments);
+            
+            me.fireEvent('canceledit', me.context);
         }
     },
 
@@ -96944,7 +101147,26 @@ grid.on('validateedit', function(e) {
 
     // private
     validateEdit: function() {
-        var me = this;
+        var me             = this,
+            editor         = me.editor,
+            context        = me.context,
+            record         = context.record,
+            newValues      = {},
+            originalValues = {},
+            name;
+
+        editor.items.each(function(item) {
+            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();
     },
 
@@ -97024,10 +101246,10 @@ grid.on('validateedit', function(e) {
         if (column.isHeader) {
             var me = this,
                 editor;
-            
+
             me.initFieldAccessors(column);
             editor = me.getEditor();
-            
+
             if (editor && editor.onColumnAdd) {
                 editor.onColumnAdd(column);
             }
@@ -97039,11 +101261,11 @@ grid.on('validateedit', function(e) {
         if (column.isHeader) {
             var me = this,
                 editor = me.getEditor();
-    
+
             if (editor && editor.onColumnRemove) {
                 editor.onColumnRemove(column);
             }
-            me.removeFieldAccessors(column);  
+            me.removeFieldAccessors(column);
         }
     },
 
@@ -97052,7 +101274,7 @@ grid.on('validateedit', function(e) {
         if (column.isHeader) {
             var me = this,
                 editor = me.getEditor();
-    
+
             if (editor && editor.onColumnResize) {
                 editor.onColumnResize(column, width);
             }
@@ -97099,26 +101321,28 @@ grid.on('validateedit', function(e) {
         me.getEditor().setField(column.field, column);
     }
 });
+
 /**
  * @class Ext.grid.property.Grid
  * @extends Ext.grid.Panel
+ *
  * A specialized grid implementation intended to mimic the traditional property grid as typically seen in
  * development IDEs.  Each row in the grid represents a property of some object, and the data is stored
  * as a set of name/value pairs in {@link Ext.grid.property.Property Properties}.  Example usage:
- * <pre><code>
-var grid = new Ext.grid.property.Grid({
-    title: 'Properties Grid',
   width: 300,
   renderTo: 'grid-ct',
-    source: {
-        "(name)": "My Object",
       "Created": Ext.Date.parse('10/15/2006', 'm/d/Y'),
       "Available": false,
       "Version": .01,
-        "Description": "A test object"
-    }
-});
-</code></pre>
+ *
+ *     @example
+ *     Ext.create('Ext.grid.property.Grid', {
*         title: 'Properties Grid',
*         width: 300,
+ *         renderTo: Ext.getBody(),
+ *         source: {
*             "(name)": "My Object",
*             "Created": Ext.Date.parse('10/15/2006', 'm/d/Y'),
*             "Available": false,
+ *             "Version": .01,
+ *             "Description": "A test object"
+ *         }
+ *     });
  */
 Ext.define('Ext.grid.property.Grid', {
 
@@ -97276,8 +101500,8 @@ var grid = Ext.create('Ext.grid.property.Grid', {
              * @param {Object} source The source data object for the grid (corresponds to the same object passed in
              * as the {@link #source} config property).
              * @param {String} recordId The record's id in the data store
-             * @param {Mixed} value The current edited property value
-             * @param {Mixed} oldValue The original property value prior to editing
+             * @param {Object} value The current edited property value
+             * @param {Object} oldValue The original property value prior to editing
              */
             'beforepropertychange',
             /**
@@ -97286,8 +101510,8 @@ var grid = Ext.create('Ext.grid.property.Grid', {
              * @param {Object} source The source data object for the grid (corresponds to the same object passed in
              * as the {@link #source} config property).
              * @param {String} recordId The record's id in the data store
-             * @param {Mixed} value The current edited property value
-             * @param {Mixed} oldValue The original property value prior to editing
+             * @param {Object} value The current edited property value
+             * @param {Object} oldValue The original property value prior to editing
              */
             'propertychange'
         );
@@ -97427,7 +101651,7 @@ grid.setSource({
     /**
      * Sets the value of a property.
      * @param {String} prop The name of the property to set
-     * @param {Mixed} value The value to test
+     * @param {Object} value The value to test
      * @param {Boolean} create (Optional) True to create the property if it doesn't already exist. Defaults to <tt>false</tt>.
      */
     setProperty: function(prop, value, create) {
@@ -97612,7 +101836,7 @@ Ext.define('Ext.grid.property.Store', {
 
     /**
      * Creates new property store.
-     * @param {Ext.grid.Grid} grid The grid this store will be bound to
+     * @param {Ext.grid.Panel} grid The grid this store will be bound to
      * @param {Object} source The source data config object
      */
     constructor : function(grid, source){
@@ -97927,63 +102151,61 @@ Ext.define('Ext.layout.component.field.Slider', {
 /**
  * @class Ext.layout.container.Absolute
  * @extends Ext.layout.container.Anchor
- * <p>This is a layout that inherits the anchoring of <b>{@link Ext.layout.container.Anchor}</b> and adds the
- * ability for x/y positioning using the standard x and y component config options.</p>
- * <p>This class is intended to be extended or created via the <tt><b>{@link Ext.container.Container#layout layout}</b></tt>
- * configuration property.  See <tt><b>{@link Ext.container.Container#layout}</b></tt> for additional details.</p>
- * {@img Ext.layout.container.Absolute/Ext.layout.container.Absolute.png Ext.layout.container.Absolute container layout}
- * <p>Example usage:</p>
- * <pre><code>
-Ext.create('Ext.form.Panel', {
-    title: 'Absolute Layout',
   width: 300,
   height: 275,
   layout:'absolute',
-    layoutConfig: {
-        // layout-specific configs go here
-        //itemCls: 'x-abs-layout-item',
   },
   url:'save-form.php',
   defaultType: 'textfield',
-    items: [{
-        x: 10,
       y: 10,
       xtype:'label',
-        text: 'Send To:'
-    },{
-        x: 80,
       y: 10,
       name: 'to',
-        anchor:'90%'  // anchor width by percentage
-    },{
-        x: 10,
       y: 40,
       xtype:'label',
-        text: 'Subject:'
-    },{
-        x: 80,
       y: 40,
       name: 'subject',
-        anchor: '90%'  // anchor width by percentage
-    },{
-        x:0,
       y: 80,
       xtype: 'textareafield',
       name: 'msg',
-        anchor: '100% 100%'  // anchor width and height
-    }],
-    renderTo: Ext.getBody()
-});
-</code></pre>
+ *
+ * This is a layout that inherits the anchoring of {@link Ext.layout.container.Anchor} and adds the
+ * ability for x/y positioning using the standard x and y component config options.
+ *
+ * This class is intended to be extended or created via the {@link Ext.container.Container#layout layout}
+ * configuration property.  See {@link Ext.container.Container#layout} for additional details.
+ *
+ *     @example
+ *     Ext.create('Ext.form.Panel', {
*         title: 'Absolute Layout',
*         width: 300,
*         height: 275,
+ *         layout:'absolute',
+ *         layoutConfig: {
+ *             // layout-specific configs go here
*             //itemCls: 'x-abs-layout-item',
*         },
*         url:'save-form.php',
+ *         defaultType: 'textfield',
+ *         items: [{
*             x: 10,
*             y: 10,
+ *             xtype:'label',
+ *             text: 'Send To:'
+ *         },{
*             x: 80,
*             y: 10,
+ *             name: 'to',
+ *             anchor:'90%'  // anchor width by percentage
+ *         },{
*             x: 10,
*             y: 40,
+ *             xtype:'label',
+ *             text: 'Subject:'
+ *         },{
*             x: 80,
*             y: 40,
+ *             name: 'subject',
+ *             anchor: '90%'  // anchor width by percentage
+ *         },{
*             x:0,
*             y: 80,
*             xtype: 'textareafield',
+ *             name: 'msg',
+ *             anchor: '100% 100%'  // anchor width and height
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
  */
-
 Ext.define('Ext.layout.container.Absolute', {
 
     /* Begin Definitions */
 
     alias: 'layout.absolute',
     extend: 'Ext.layout.container.Anchor',
-    requires: ['Ext.chart.axis.Axis', 'Ext.fx.Anim'],
     alternateClassName: 'Ext.layout.AbsoluteLayout',
 
     /* End Definitions */
@@ -98021,98 +102243,104 @@ Ext.define('Ext.layout.container.Absolute', {
 /**
  * @class Ext.layout.container.Accordion
  * @extends Ext.layout.container.VBox
- * <p>This is a layout that manages multiple Panels in an expandable accordion style such that only
- * <b>one Panel can be expanded at any given time</b>. Each Panel has built-in support for expanding and collapsing.</p>
- * <p>Note: Only Ext.Panels <b>and all subclasses of Ext.panel.Panel</b> may be used in an accordion layout Container.</p>
- * {@img Ext.layout.container.Accordion/Ext.layout.container.Accordion.png Ext.layout.container.Accordion container layout}
- * <p>Example usage:</p>
- * <pre><code>
-Ext.create('Ext.panel.Panel', {
-    title: 'Accordion Layout',
   width: 300,
   height: 300,
   layout:'accordion',
-    defaults: {
-        // applied to each contained panel
-        bodyStyle: 'padding:15px'
-    },
-    layoutConfig: {
-        // layout-specific configs go here
-        titleCollapse: false,
       animate: true,
-        activeOnTop: true
-    },
-    items: [{
-        title: 'Panel 1',
-        html: 'Panel content!'
-    },{
-        title: 'Panel 2',
-        html: 'Panel content!'
-    },{
-        title: 'Panel 3',
-        html: 'Panel content!'
-    }],
-    renderTo: Ext.getBody()
-});
-</code></pre>
+ *
+ * This is a layout that manages multiple Panels in an expandable accordion style such that only
+ * **one Panel can be expanded at any given time**. Each Panel has built-in support for expanding and collapsing.
+ *
+ * Note: Only Ext Panels and all subclasses of Ext.panel.Panel may be used in an accordion layout Container.
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
*         title: 'Accordion Layout',
*         width: 300,
*         height: 300,
+ *         layout:'accordion',
+ *         defaults: {
+ *             // applied to each contained panel
+ *             bodyStyle: 'padding:15px'
+ *         },
+ *         layoutConfig: {
+ *             // layout-specific configs go here
*             titleCollapse: false,
+ *             animate: true,
+ *             activeOnTop: true
+ *         },
+ *         items: [{
+ *             title: 'Panel 1',
+ *             html: 'Panel content!'
+ *         },{
+ *             title: 'Panel 2',
+ *             html: 'Panel content!'
+ *         },{
+ *             title: 'Panel 3',
+ *             html: 'Panel content!'
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
  */
 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',
 
     /**
      * @cfg {Boolean} fill
      * True to adjust the active item's height to fill the available space in the container, false to use the
-     * item's current height, or auto height if not explicitly set (defaults to true).
+     * item's current height, or auto height if not explicitly set.
      */
     fill : true,
+
     /**
      * @cfg {Boolean} autoWidth
-     * <p><b>This config is ignored in ExtJS 4.x.</b></p>
      * Child Panels have their width actively managed to fit within the accordion's width.
+     * @deprecated This config is ignored in ExtJS 4
      */
     autoWidth : true,
+
     /**
      * @cfg {Boolean} titleCollapse
-     * <p><b>Not implemented in PR2.</b></p>
      * True to allow expand/collapse of each contained panel by clicking anywhere on the title bar, false to allow
-     * expand/collapse only when the toggle tool button is clicked (defaults to true).  When set to false,
+     * expand/collapse only when the toggle tool button is clicked.  When set to false,
      * {@link #hideCollapseTool} should be false also.
      */
     titleCollapse : true,
+
     /**
      * @cfg {Boolean} hideCollapseTool
-     * True to hide the contained Panels' collapse/expand toggle buttons, false to display them (defaults to false).
+     * True to hide the contained Panels' collapse/expand toggle buttons, false to display them.
      * When set to true, {@link #titleCollapse} is automatically set to <code>true</code>.
      */
     hideCollapseTool : false,
+
     /**
      * @cfg {Boolean} collapseFirst
      * True to make sure the collapse/expand toggle button always renders first (to the left of) any other tools
-     * in the contained Panels' title bars, false to render it last (defaults to false).
+     * in the contained Panels' title bars, false to render it last.
      */
     collapseFirst : false,
+
     /**
      * @cfg {Boolean} animate
      * True to slide the contained panels open and closed during expand/collapse using animation, false to open and
-     * close directly with no animation (defaults to <code>true</code>). Note: The layout performs animated collapsing
+     * close directly with no animation. Note: The layout performs animated collapsing
      * and expanding, <i>not</i> the child Panels.
      */
     animate : true,
     /**
      * @cfg {Boolean} activeOnTop
-     * <p><b>Not implemented in PR4.</b></p>
-     * <p>Only valid when {@link #multi" is <code>false</code>.</p>
+     * Only valid when {@link #multi} is `false` and {@link #animate} is `false`.
+     *
      * True to swap the position of each panel as it is expanded so that it becomes the first item in the container,
-     * false to keep the panels in the rendered order. <b>This is NOT compatible with "animate:true"</b> (defaults to false).
+     * false to keep the panels in the rendered order.
      */
     activeOnTop : false,
     /**
      * @cfg {Boolean} multi
-     * Defaults to <code>false</code>. Set to <code>true</code> to enable multiple accordion items to be open at once.
+     * Set to <code>true</code> to enable multiple accordion items to be open at once.
      */
     multi: false,
 
@@ -98138,7 +102366,7 @@ Ext.define('Ext.layout.container.Accordion', {
 
         me.callParent(arguments);
         if (me.fill) {
-            if (!me.owner.el.dom.style.height || !me.getLayoutTargetSize().height) {
+            if (!(me.owner.el.dom.style.height || me.getLayoutTargetSize().height)) {
                 return false;
             }
         } else {
@@ -98154,8 +102382,7 @@ Ext.define('Ext.layout.container.Accordion', {
             i = 0,
             comp,
             targetSize = me.getLayoutTargetSize(),
-            renderedPanels = [],
-            border;
+            renderedPanels = [];
 
         for (; i < ln; i++) {
             comp = items[i];
@@ -98208,6 +102435,7 @@ Ext.define('Ext.layout.container.Accordion', {
                     comp.autoHeight = true;
                     comp.autoScroll = false;
                 }
+                comp.border = comp.collapsed;
             }
         }
 
@@ -98215,7 +102443,7 @@ Ext.define('Ext.layout.container.Accordion', {
         if (ln && me.expandedItem === undefined) {
             me.expandedItem = 0;
             comp = items[0];
-            comp.collapsed = false;
+            comp.collapsed = comp.border = false;
             if (me.fill) {
                 comp.flex = 1;
             }
@@ -98272,6 +102500,12 @@ Ext.define('Ext.layout.container.Accordion', {
         for (i = 0; i < ln; i++) {
             child = children[i];
 
+            // Fix for EXTJSIV-3724. Windows only.
+            // Collapsing the Psnel's el to a size which only allows a single hesder to be visible, scrolls the header out of view.
+            if (Ext.isWindows) {
+                child.el.dom.scrollTop = 0;
+            }
+
             if (siblingCollapsed) {
                 child.header.removeCls(Ext.baseCSSPrefix + 'accordion-hd-sibling-expanded');
             }
@@ -98288,6 +102522,21 @@ Ext.define('Ext.layout.container.Accordion', {
             siblingCollapsed = child.collapsed;
         }
     },
+    
+    animCallback: function(){
+        Ext.Array.forEach(this.toCollapse, function(comp){
+            comp.fireEvent('collapse', comp);
+        });
+        
+        Ext.Array.forEach(this.toExpand, function(comp){
+            comp.fireEvent('expand', comp);
+        });    
+    },
+    
+    setupEvents: function(){
+        this.toCollapse = [];
+        this.toExpand = [];    
+    },
 
     // When a Component expands, adjust the heights of the other Components to be just enough to accommodate
     // their headers.
@@ -98299,6 +102548,7 @@ Ext.define('Ext.layout.container.Accordion', {
             i = 0,
             comp;
 
+        me.setupEvents();
         for (; i < len; i++) {
             comp = it[i];
             if (comp === toExpand && comp.collapsed) {
@@ -98309,7 +102559,12 @@ Ext.define('Ext.layout.container.Accordion', {
         }
 
         me.animate = me.initialAnimate;
-        me.layout();
+        if (me.activeOnTop) {
+            // insert will trigger a layout
+            me.owner.insert(0, toExpand); 
+        } else {
+            me.layout();
+        }
         me.animate = false;
         return false;
     },
@@ -98319,6 +102574,7 @@ Ext.define('Ext.layout.container.Accordion', {
             toExpand = comp.next() || comp.prev(),
             expanded = me.multi ? me.owner.query('>panel:not([collapsed])') : [];
 
+        me.setupEvents();
         // If we are allowing multi, and the "toCollapse" component is NOT the only expanded Component,
         // then ask the box layout to collapse it to its header.
         if (me.multi) {
@@ -98367,7 +102623,11 @@ Ext.define('Ext.layout.container.Accordion', {
         comp.el.setHeight(comp.height);
         comp.collapsed = true;
         delete comp.flex;
-        comp.fireEvent('collapse', comp);
+        if (this.initialAnimate) {
+            this.toCollapse.push(comp);
+        } else {
+            comp.fireEvent('collapse', comp);
+        }
         if (comp.collapseTool) {
             comp.collapseTool.setType('expand-' + comp.getOppositeDirection(comp.collapseDirection));
         }
@@ -98394,7 +102654,11 @@ Ext.define('Ext.layout.container.Accordion', {
         comp.flex = 1;
         comp.removeCls(comp.collapsedCls);
         comp.header.removeCls(comp.collapsedHeaderCls);
-        comp.fireEvent('expand', comp);
+         if (this.initialAnimate) {
+            this.toExpand.push(comp);
+        } else {
+            comp.fireEvent('expand', comp);
+        }
         if (comp.collapseTool) {
             comp.collapseTool.setType('collapse-' + comp.collapseDirection);
         }
@@ -98402,17 +102666,17 @@ Ext.define('Ext.layout.container.Accordion', {
     }
 });
 /**
- * @class Ext.resizer.Splitter
- * @extends Ext.Component
- * <p>This class functions <b>between siblings of a {@link Ext.layout.container.VBox VBox} or {@link Ext.layout.container.HBox HBox}
- * layout</b> to resize both immediate siblings.</p>
- * <p>By default it will set the size of both siblings. <b>One</b> of the siblings may be configured with
- * <code>{@link Ext.Component#maintainFlex maintainFlex}: true</code> which will cause it not to receive a new size explicitly, but to be resized
- * by the layout.</p>
- * <p>A Splitter may be configured to show a centered mini-collapse tool orientated to collapse the {@link #collapseTarget}.
+ * This class functions between siblings of a {@link Ext.layout.container.VBox VBox} or {@link Ext.layout.container.HBox HBox}
+ * layout to resize both immediate siblings.
+ *
+ * By default it will set the size of both siblings. <b>One</b> of the siblings may be configured with
+ * `{@link Ext.Component#maintainFlex maintainFlex}: true` which will cause it not to receive a new size explicitly, but to be resized
+ * by the layout.
+ *
+ * A Splitter may be configured to show a centered mini-collapse tool orientated to collapse the {@link #collapseTarget}.
  * The Splitter will then call that sibling Panel's {@link Ext.panel.Panel#collapse collapse} or {@link Ext.panel.Panel#expand expand} method
  * to perform the appropriate operation (depending on the sibling collapse state). To create the mini-collapse tool but take care
- * of collapsing yourself, configure the splitter with <code>{@link #performCollapse} false</code>.</p>
+ * of collapsing yourself, configure the splitter with <code>{@link #performCollapse} false</code>.
  */
 Ext.define('Ext.resizer.Splitter', {
     extend: 'Ext.Component',
@@ -98421,7 +102685,10 @@ Ext.define('Ext.resizer.Splitter', {
     alias: 'widget.splitter',
 
     renderTpl: [
-        '<tpl if="collapsible===true"><div class="' + Ext.baseCSSPrefix + 'collapse-el ' + Ext.baseCSSPrefix + 'layout-split-{collapseDir}">&nbsp;</div></tpl>'
+        '<tpl if="collapsible===true">',
+            '<div id="{id}-collapseEl" class="', Ext.baseCSSPrefix, 'collapse-el ',
+                    Ext.baseCSSPrefix, 'layout-split-{collapseDir}">&nbsp;</div>',
+        '</tpl>'
     ],
 
     baseCls: Ext.baseCSSPrefix + 'splitter',
@@ -98459,7 +102726,7 @@ Ext.define('Ext.resizer.Splitter', {
      * that the splitter is between.
      */
     defaultSplitMax: 1000,
-    
+
     /**
      * @cfg {String} collapsedCls
      * A class to add to the splitter when it is collapsed. See {@link #collapsible}.
@@ -98469,7 +102736,7 @@ Ext.define('Ext.resizer.Splitter', {
     height: 5,
 
     /**
-     * @cfg {Mixed} collapseTarget
+     * @cfg {String/Ext.panel.Panel} collapseTarget
      * <p>A string describing the relative position of the immediate sibling Panel to collapse. May be 'prev' or 'next' (Defaults to 'next')</p>
      * <p>Or the immediate sibling Panel to collapse.</p>
      * <p>The orientation of the mini-collapse tool will be inferred from this setting.</p>
@@ -98493,9 +102760,8 @@ Ext.define('Ext.resizer.Splitter', {
             collapseDir: collapseDir,
             collapsible: me.collapsible || target.collapsible
         });
-        Ext.applyIf(me.renderSelectors, {
-            collapseEl: '.' + Ext.baseCSSPrefix + 'collapse-el'
-        });
+
+        me.addChildEls('collapseEl');
 
         this.callParent(arguments);
 
@@ -98549,7 +102815,7 @@ Ext.define('Ext.resizer.Splitter', {
 
     getCollapseTarget: function() {
         var me = this;
-        
+
         return me.collapseTarget.isComponent ? me.collapseTarget : me.collapseTarget == 'prev' ? me.previousSibling() : me.nextSibling();
     },
 
@@ -98588,72 +102854,76 @@ Ext.define('Ext.resizer.Splitter', {
 });
 
 /**
- * @class Ext.layout.container.Border
- * @extends Ext.layout.container.Container
- * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
- * nested panels, automatic bars between regions and built-in
- * {@link Ext.panel.Panel#collapsible expanding and collapsing} of regions.</p>
- * <p>This class is intended to be extended or created via the <code>layout:'border'</code>
- * {@link Ext.container.Container#layout} config, and should generally not need to be created directly
- * via the new keyword.</p>
- * {@img Ext.layout.container.Border/Ext.layout.container.Border.png Ext.layout.container.Border container layout}
- * <p>Example usage:</p>
- * <pre><code>
-     Ext.create('Ext.panel.Panel', {
-        width: 500,
-        height: 400,
-        title: 'Border Layout',
-        layout: 'border',
-        items: [{
-            title: 'South Region is resizable',
-            region: 'south',     // position for region
-            xtype: 'panel',
-            height: 100,
-            split: true,         // enable resizing
-            margins: '0 5 5 5'
-        },{
-            // xtype: 'panel' implied by default
-            title: 'West Region is collapsible',
-            region:'west',
-            xtype: 'panel',
-            margins: '5 0 0 5',
-            width: 200,
-            collapsible: true,   // make collapsible
-            id: 'west-region-container',
-            layout: 'fit'
-        },{
-            title: 'Center Region',
-            region: 'center',     // center region is required, no width/height specified
-            xtype: 'panel',
-            layout: 'fit',
-            margins: '5 5 0 0'
-        }],
-        renderTo: Ext.getBody()
-    });
-</code></pre>
- * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
- * <li>Any Container using the Border layout <b>must</b> have a child item with <code>region:'center'</code>.
- * The child item in the center region will always be resized to fill the remaining space not used by
- * the other regions in the layout.</li>
- * <li>Any child items with a region of <code>west</code> or <code>east</code> may be configured with either
- * an initial <code>width</code>, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage width <b>string</b> (Which is simply divided by 100 and used as a flex value). The 'center' region has a flex value of <code>1</code>.</li>
- * <li>Any child items with a region of <code>north</code> or <code>south</code> may be configured with either
- * an initial <code>height</code>, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage height <b>string</b> (Which is simply divided by 100 and used as a flex value). The 'center' region has a flex value of <code>1</code>.</li>
- * <li>The regions of a BorderLayout are <b>fixed at render time</b> and thereafter, its child Components may not be removed or added</b>.To add/remove
- * Components within a BorderLayout, have them wrapped by an additional Container which is directly
- * managed by the BorderLayout.  If the region is to be collapsible, the Container used directly
- * by the BorderLayout manager should be a Panel.  In the following example a Container (an Ext.panel.Panel)
- * is added to the west region:<pre><code>
-wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
-wrc.{@link Ext.container.Container#removeAll removeAll}();
-wrc.{@link Ext.container.Container#add add}({
-    title: 'Added Panel',
-    html: 'Some content'
-});
- * </code></pre>
- * </li>
- * <li><b>There is no BorderLayout.Region class in ExtJS 4.0+</b></li>
- * </ul></div>
+ * This is a multi-pane, application-oriented UI layout style that supports multiple nested panels, automatic bars
+ * between regions and built-in {@link Ext.panel.Panel#collapsible expanding and collapsing} of regions.
+ *
+ * This class is intended to be extended or created via the `layout:'border'` {@link Ext.container.Container#layout}
+ * config, and should generally not need to be created directly via the new keyword.
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         width: 500,
+ *         height: 400,
+ *         title: 'Border Layout',
+ *         layout: 'border',
+ *         items: [{
+ *             title: 'South Region is resizable',
+ *             region: 'south',     // position for region
+ *             xtype: 'panel',
+ *             height: 100,
+ *             split: true,         // enable resizing
+ *             margins: '0 5 5 5'
+ *         },{
+ *             // xtype: 'panel' implied by default
+ *             title: 'West Region is collapsible',
+ *             region:'west',
+ *             xtype: 'panel',
+ *             margins: '5 0 0 5',
+ *             width: 200,
+ *             collapsible: true,   // make collapsible
+ *             id: 'west-region-container',
+ *             layout: 'fit'
+ *         },{
+ *             title: 'Center Region',
+ *             region: 'center',     // center region is required, no width/height specified
+ *             xtype: 'panel',
+ *             layout: 'fit',
+ *             margins: '5 5 0 0'
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ * # Notes
+ *
+ * - Any Container using the Border layout **must** have a child item with `region:'center'`.
+ *   The child item in the center region will always be resized to fill the remaining space
+ *   not used by the other regions in the layout.
+ *
+ * - Any child items with a region of `west` or `east` may be configured with either an initial
+ *   `width`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage width
+ *   **string** (Which is simply divided by 100 and used as a flex value).
+ *   The 'center' region has a flex value of `1`.
+ *
+ * - Any child items with a region of `north` or `south` may be configured with either an initial
+ *   `height`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage height
+ *   **string** (Which is simply divided by 100 and used as a flex value).
+ *   The 'center' region has a flex value of `1`.
+ *
+ * - The regions of a BorderLayout are **fixed at render time** and thereafter, its child
+ *   Components may not be removed or added**. To add/remove Components within a BorderLayout,
+ *   have them wrapped by an additional Container which is directly managed by the BorderLayout.
+ *   If the region is to be collapsible, the Container used directly by the BorderLayout manager
+ *   should be a Panel. In the following example a Container (an Ext.panel.Panel) is added to
+ *   the west region:
+ *
+ *       wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
+ *       wrc.{@link Ext.container.Container#removeAll removeAll}();
+ *       wrc.{@link Ext.container.Container#add add}({
+ *           title: 'Added Panel',
+ *           html: 'Some content'
+ *       });
+ *
+ * - **There is no BorderLayout.Region class in ExtJS 4.0+**
  */
 Ext.define('Ext.layout.container.Border', {
 
@@ -98723,6 +102993,8 @@ Ext.define('Ext.layout.container.Border', {
 
         // Delegate this operation to the shadow "V" or "H" box layout.
         this.shadowLayout.beforeLayout();
+
+        // note: don't call base because that does a renderItems again
     },
 
     renderItems: function(items, target) {
@@ -98737,6 +103009,14 @@ Ext.define('Ext.layout.container.Border', {
         //</debug>
     },
 
+    renderChildren: function() {
+        if (!this.borderLayoutInitialized) {
+            this.initializeBorderLayout();
+        }
+
+        this.shadowLayout.renderChildren();
+    },
+
     /*
      * Gathers items for a layout operation. Injected into child Box layouts through configuration.
      * We must not include child items which are floated over the layout (are primed with a slide out animation)
@@ -98770,7 +103050,7 @@ Ext.define('Ext.layout.container.Border', {
 
                 // This layout intercepts any initial collapsed state. Panel must not do this itself.
                 comp.borderCollapse = comp.collapsed;
-                delete comp.collapsed;
+                comp.collapsed = false;
 
                 comp.on({
                     beforecollapse: me.onBeforeRegionCollapse,
@@ -99092,13 +103372,16 @@ Ext.define('Ext.layout.container.Border', {
     },
 
     /**
-     * <p>Return the {@link Ext.panel.Panel#placeholder placeholder} Component to which the passed child Panel of the layout will collapse.
-     * By default, this will be a {@link Ext.panel.Header Header} component (Docked to the appropriate border). See {@link Ext.panel.Panel#placeholder placeholder}.
-     * config to customize this.</p>
-     * <p><b>Note that this will be a fully instantiated Component, but will only be <i>rendered</i> when the Panel is first collapsed.</b></p>
-     * @param {Panel} panel The child Panel of the layout for which to return the {@link Ext.panel.Panel#placeholder placeholder}.
-     * @returns {Component} The Panel's {@link Ext.panel.Panel#placeholder placeholder} unless the {@link Ext.panel.Panel#collapseMode collapseMode} is
-     * <code>'header'</code>, in which case <i>undefined</i> is returned.
+     * Return the {@link Ext.panel.Panel#placeholder placeholder} Component to which the passed child Panel of the
+     * layout will collapse. By default, this will be a {@link Ext.panel.Header Header} component (Docked to the
+     * appropriate border). See {@link Ext.panel.Panel#placeholder placeholder}. config to customize this.
+     *
+     * **Note that this will be a fully instantiated Component, but will only be _rendered_ when the Panel is first
+     * collapsed.**
+     * @param {Ext.panel.Panel} panel The child Panel of the layout for which to return the {@link
+     * Ext.panel.Panel#placeholder placeholder}.
+     * @return {Ext.Component} The Panel's {@link Ext.panel.Panel#placeholder placeholder} unless the {@link
+     * Ext.panel.Panel#collapseMode collapseMode} is `'header'`, in which case _undefined_ is returned.
      */
     getPlaceholder: function(comp) {
         var me = this,
@@ -99201,7 +103484,7 @@ Ext.define('Ext.layout.container.Border', {
      * @private
      * Calculates the size and positioning of the passed child item. Must be present because Panel's expand,
      * when configured with a flex, calls this method on its ownerCt's layout.
-     * @param {Component} child The child Component to calculate the box for
+     * @param {Ext.Component} child The child Component to calculate the box for
      * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
      */
     calculateChildBox: function(comp) {
@@ -99224,6 +103507,15 @@ Ext.define('Ext.layout.container.Border', {
      * @returns {Boolean} false to inhibit the Panel from performing its own collapse.
      */
     onBeforeRegionCollapse: function(comp, direction, animate) {
+        if (comp.collapsedChangingLayout) {
+            //<debug warn>
+            if (Ext.global.console && Ext.global.console.warn) {
+                Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
+            }
+            //</debug>
+            return false;
+        }
+        comp.collapsedChangingLayout = true;
         var me = this,
             compEl = comp.el,
             width,
@@ -99298,6 +103590,7 @@ Ext.define('Ext.layout.container.Border', {
             delete me.shadowContainer.layout.layoutBusy;
             delete me.layoutBusy;
             delete me.owner.componentLayout.layoutBusy;
+            delete comp.collapsedChangingLayout;
 
             // Fire the collapse event: The Panel has in fact been collapsed, but by substitution of an alternative Component
             comp.collapsed = true;
@@ -99346,7 +103639,8 @@ Ext.define('Ext.layout.container.Border', {
 
     // Hijack the expand operation to remove the placeholder and slide the region back in.
     onBeforeRegionExpand: function(comp, animate) {
-        this.onPlaceHolderToolClick(null, null, null, {client: comp});
+        // We don't check for comp.collapsedChangingLayout here because onPlaceHolderToolClick does it
+        this.onPlaceHolderToolClick(null, null, null, {client: comp, shouldFireBeforeexpand: false});
         return false;
     },
 
@@ -99368,6 +103662,18 @@ Ext.define('Ext.layout.container.Border', {
             scsl = shadowContainer.suspendLayout,
             isFloating;
 
+        if (comp.collapsedChangingLayout) {
+            //<debug warn>
+            if (Ext.global.console && Ext.global.console.warn) {
+                Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
+            }
+            //</debug>
+            return false;
+        }
+        if (tool.shouldFireBeforeexpand !== false && comp.fireEvent('beforeexpand', comp, true) === false) {
+            return false;
+        }
+        comp.collapsedChangingLayout = true;
         // If the slide in is still going, stop it.
         // This will either leave the Component in its fully floated state (which is processed below)
         // or in its collapsed state. Either way, we expand it..
@@ -99443,6 +103749,7 @@ Ext.define('Ext.layout.container.Border', {
             delete me.shadowContainer.layout.layoutBusy;
             delete me.layoutBusy;
             delete me.owner.componentLayout.layoutBusy;
+            delete comp.collapsedChangingLayout;
 
             // In case it was floated out and they clicked the re-expand tool
             comp.removeCls(Ext.baseCSSPrefix + 'border-region-slide-in');
@@ -99658,29 +103965,36 @@ Ext.define('Ext.layout.container.Border', {
 });
 
 /**
- * @class Ext.layout.container.Card
- * @extends Ext.layout.container.AbstractCard
- *
  * This layout manages multiple child Components, each fitted to the Container, where only a single child Component can be
  * visible at any given time.  This layout style is most commonly used for wizards, tab implementations, etc.
  * This class is intended to be extended or created via the layout:'card' {@link Ext.container.Container#layout} config,
  * and should generally not need to be created directly via the new keyword.
  *
  * The CardLayout's focal method is {@link #setActiveItem}.  Since only one panel is displayed at a time,
- * the only way to move from one Component to the next is by calling setActiveItem, passing the id or index of
- * the next panel to display.  The layout itself does not provide a user interface for handling this navigation,
+ * the only way to move from one Component to the next is by calling setActiveItem, passing the next panel to display
+ * (or its id or index).  The layout itself does not provide a user interface for handling this navigation,
  * so that functionality must be provided by the developer.
  *
+ * To change the active card of a container, call the setActiveItem method of its layout:
+ *
+ *     Ext.create('Ext.panel.Panel', {
+ *         layout: 'card',
+ *         items: [
+ *             { html: 'Card 1' },
+ *             { html: 'Card 2' }
+ *         ],
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ *     p.getLayout().setActiveItem(1);
+ *
  * In the following example, a simplistic wizard setup is demonstrated.  A button bar is added
  * to the footer of the containing panel to provide navigation buttons.  The buttons will be handled by a
  * common navigation routine.  Note that other uses of a CardLayout (like a tab control) would require a
  * completely different implementation.  For serious implementations, a better approach would be to extend
  * CardLayout to provide the custom functionality needed.
  *
- * {@img Ext.layout.container.Card/Ext.layout.container.Card.png Ext.layout.container.Card container layout}
- *
- * Example usage:
- * 
+ *     @example
  *     var navigate = function(panel, direction){
  *         // This routine could contain business logic required to manage the navigation steps.
  *         // It would call setActiveItem as needed, manage navigation button state, handle any
@@ -99693,13 +104007,12 @@ Ext.define('Ext.layout.container.Border', {
  *         Ext.getCmp('move-prev').setDisabled(!layout.getPrev());
  *         Ext.getCmp('move-next').setDisabled(!layout.getNext());
  *     };
- *  
+ *
  *     Ext.create('Ext.panel.Panel', {
  *         title: 'Example Wizard',
  *         width: 300,
  *         height: 200,
  *         layout: 'card',
- *         activeItem: 0, // make sure the active item is set on the container config!
  *         bodyStyle: 'padding:15px',
  *         defaults: {
  *             // applied to each contained panel
@@ -99736,7 +104049,7 @@ Ext.define('Ext.layout.container.Border', {
  *             html: '<h1>Congratulations!</h1><p>Step 3 of 3 - Complete</p>'
  *         }],
  *         renderTo: Ext.getBody()
- *     });  
+ *     });
  */
 Ext.define('Ext.layout.container.Card', {
 
@@ -99751,7 +104064,7 @@ Ext.define('Ext.layout.container.Card', {
 
     /**
      * Makes the given card active.
-     * 
+     *
      *     var card1 = Ext.create('Ext.panel.Panel', {itemId: 'card-1'});
      *     var card2 = Ext.create('Ext.panel.Panel', {itemId: 'card-2'});
      *     var panel = Ext.create('Ext.panel.Panel', {
@@ -99763,7 +104076,7 @@ Ext.define('Ext.layout.container.Card', {
      *     panel.getLayout().setActiveItem(card2);
      *     panel.getLayout().setActiveItem('card-2');
      *     panel.getLayout().setActiveItem(1);
-     * 
+     *
      * @param {Ext.Component/Number/String} newCard  The component, component {@link Ext.Component#id id},
      * {@link Ext.Component#itemId itemId}, or index of component.
      * @return {Ext.Component} the activated component or false when nothing activated.
@@ -99836,7 +104149,6 @@ Ext.define('Ext.layout.container.Card', {
     },
 
     configureItem: function(item) {
-
         // Card layout only controls dimensions which IT has controlled.
         // That calculation has to be determined at run time by examining the ownerCt's isFixedWidth()/isFixedHeight() methods
         item.layoutManagedHeight = 0;
@@ -99845,72 +104157,70 @@ Ext.define('Ext.layout.container.Card', {
         this.callParent(arguments);
     }});
 /**
- * @class Ext.layout.container.Column
- * @extends Ext.layout.container.Auto
- * <p>This is the layout style of choice for creating structural layouts in a multi-column format where the width of
- * each column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content.
- * This class is intended to be extended or created via the layout:'column' {@link Ext.container.Container#layout} config,
- * and should generally not need to be created directly via the new keyword.</p>
- * <p>ColumnLayout does not have any direct config options (other than inherited ones), but it does support a
- * specific config property of <b><tt>columnWidth</tt></b> that can be included in the config of any panel added to it.  The
- * layout will use the columnWidth (if present) or width of each panel during layout to determine how to size each panel.
- * If width or columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).</p>
- * <p>The width property is always evaluated as pixels, and must be a number greater than or equal to 1.
- * The columnWidth property is always evaluated as a percentage, and must be a decimal value greater than 0 and
- * less than 1 (e.g., .25).</p>
- * <p>The basic rules for specifying column widths are pretty simple.  The logic makes two passes through the
- * set of contained panels.  During the first layout pass, all panels that either have a fixed width or none
- * specified (auto) are skipped, but their widths are subtracted from the overall container width.  During the second
- * pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages based on
- * the total <b>remaining</b> container width.  In other words, percentage width panels are designed to fill the space
- * left over by all the fixed-width and/or auto-width panels.  Because of this, while you can specify any number of columns
- * with different percentages, the columnWidths must always add up to 1 (or 100%) when added together, otherwise your
- * layout may not render as expected.  
- * {@img Ext.layout.container.Column/Ext.layout.container.Column1.png Ext.layout.container.Column container layout}
- * Example usage:</p>
- * <pre><code>
-    // All columns are percentages -- they must add up to 1
-    Ext.create('Ext.panel.Panel', {
-        title: 'Column Layout - Percentage Only',
-        width: 350,
-        height: 250,
-        layout:'column',
-        items: [{
-            title: 'Column 1',
-            columnWidth: .25
-        },{
-            title: 'Column 2',
-            columnWidth: .55
-        },{
-            title: 'Column 3',
-            columnWidth: .20
-        }],
-        renderTo: Ext.getBody()
-    }); 
-
-// {@img Ext.layout.container.Column/Ext.layout.container.Column2.png Ext.layout.container.Column container layout}
-// Mix of width and columnWidth -- all columnWidth values must add up
-// to 1. The first column will take up exactly 120px, and the last two
-// columns will fill the remaining container width.
-
-    Ext.create('Ext.Panel', {
-        title: 'Column Layout - Mixed',
-        width: 350,
-        height: 250,
-        layout:'column',
-        items: [{
-            title: 'Column 1',
-            width: 120
-        },{
-            title: 'Column 2',
-            columnWidth: .7
-        },{
-            title: 'Column 3',
-            columnWidth: .3
-        }],
-        renderTo: Ext.getBody()
-    }); 
-</code></pre>
+ * This is the layout style of choice for creating structural layouts in a multi-column format where the width of each
+ * column can be specified as a percentage or fixed width, but the height is allowed to vary based on the content. This
+ * class is intended to be extended or created via the layout:'column' {@link Ext.container.Container#layout} config,
+ * and should generally not need to be created directly via the new keyword.
+ *
+ * ColumnLayout does not have any direct config options (other than inherited ones), but it does support a specific
+ * config property of `columnWidth` that can be included in the config of any panel added to it. The layout will use
+ * the columnWidth (if present) or width of each panel during layout to determine how to size each panel. If width or
+ * columnWidth is not specified for a given panel, its width will default to the panel's width (or auto).
+ *
+ * The width property is always evaluated as pixels, and must be a number greater than or equal to 1. The columnWidth
+ * property is always evaluated as a percentage, and must be a decimal value greater than 0 and less than 1 (e.g., .25).
+ *
+ * The basic rules for specifying column widths are pretty simple. The logic makes two passes through the set of
+ * contained panels. During the first layout pass, all panels that either have a fixed width or none specified (auto)
+ * are skipped, but their widths are subtracted from the overall container width.
+ *
+ * During the second pass, all panels with columnWidths are assigned pixel widths in proportion to their percentages
+ * based on the total **remaining** container width. In other words, percentage width panels are designed to fill
+ * the space left over by all the fixed-width and/or auto-width panels. Because of this, while you can specify any
+ * number of columns with different percentages, the columnWidths must always add up to 1 (or 100%) when added
+ * together, otherwise your layout may not render as expected.
+ *
+ *     @example
+ *     // All columns are percentages -- they must add up to 1
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Column Layout - Percentage Only',
+ *         width: 350,
+ *         height: 250,
+ *         layout:'column',
+ *         items: [{
+ *             title: 'Column 1',
+ *             columnWidth: .25
+ *         },{
+ *             title: 'Column 2',
+ *             columnWidth: .55
+ *         },{
+ *             title: 'Column 3',
+ *             columnWidth: .20
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ *     // Mix of width and columnWidth -- all columnWidth values must add up
+ *     // to 1. The first column will take up exactly 120px, and the last two
+ *     // columns will fill the remaining container width.
+ *
+ *     Ext.create('Ext.Panel', {
+ *         title: 'Column Layout - Mixed',
+ *         width: 350,
+ *         height: 250,
+ *         layout:'column',
+ *         items: [{
+ *             title: 'Column 1',
+ *             width: 120
+ *         },{
+ *             title: 'Column 2',
+ *             columnWidth: .7
+ *         },{
+ *             title: 'Column 3',
+ *             columnWidth: .3
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.layout.container.Column', {
 
@@ -100003,9 +104313,9 @@ Ext.define('Ext.layout.container.Column', {
             item = items[i];
             if (item.columnWidth) {
                 columnWidth = Math.floor(item.columnWidth * availableWidth) - parallelMargins[i];
-                if (item.getWidth() != columnWidth) {
-                    me.setItemSize(item, columnWidth, item.height);
-                }
+                me.setItemSize(item, columnWidth, item.height);
+            } else {
+                me.layoutItem(item);
             }
         }
 
@@ -100030,79 +104340,67 @@ Ext.define('Ext.layout.container.Column', {
     },
 
     configureItem: function(item) {
+        this.callParent(arguments);
+
         if (item.columnWidth) {
             item.layoutManagedWidth = 1;
-        } else {
-            item.layoutManagedWidth = 2;
         }
-        item.layoutManagedHeight = 2;
-        this.callParent(arguments);
     }
 });
 /**
- * @class Ext.layout.container.Table
- * @extends Ext.layout.container.Auto
- * <p>This layout allows you to easily render content into an HTML table.  The total number of columns can be
- * specified, and rowspan and colspan can be used to create complex layouts within the table.
- * This class is intended to be extended or created via the <code>layout: {type: 'table'}</code>
- * {@link Ext.container.Container#layout} config, and should generally not need to be created directly via the new keyword.</p>
- * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
- * the {@link Ext.container.Container#layout} object which will then be applied internally to the layout.  In the
- * case of TableLayout, the only valid layout config properties are {@link #columns} and {@link #tableAttrs}.
- * However, the items added to a TableLayout can supply the following table-specific config properties:</p>
- * <ul>
- * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
- * <li><b>colspan</b> Applied to the table cell containing the item.</li>
- * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
- * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
- * </ul>
- * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
- * HTML table.  You simply add each panel (or "cell") that you want to include along with any span attributes
- * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
- * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
- * total column count in the layoutConfig and start adding panels in their natural order from left to right,
- * top to bottom.  The layout will automatically figure out, based on the column count, rowspans and colspans,
- * how to position each panel within the table.  Just like with HTML tables, your rowspans and colspans must add
- * up correctly in your overall layout or you'll end up with missing and/or extra cells!  Example usage:</p>
- * {@img Ext.layout.container.Table/Ext.layout.container.Table.png Ext.layout.container.Table container layout}
- * <pre><code>
-// This code will generate a layout table that is 3 columns by 2 rows
-// with some spanning included.  The basic layout will be:
-// +--------+-----------------+
-// |   A    |   B             |
-// |        |--------+--------|
-// |        |   C    |   D    |
-// +--------+--------+--------+
-    Ext.create('Ext.panel.Panel', {
-        title: 'Table Layout',
-        width: 300,
-        height: 150,
-        layout: {
-            type: 'table',
-            // The total column count must be specified here
-            columns: 3
-        },
-        defaults: {
-            // applied to each contained panel
-            bodyStyle:'padding:20px'
-        },
-        items: [{
-            html: 'Cell A content',
-            rowspan: 2
-        },{
-            html: 'Cell B content',
-            colspan: 2
-        },{
-            html: 'Cell C content',
-            cellCls: 'highlight'
-        },{
-            html: 'Cell D content'
-        }],
-        renderTo: Ext.getBody()
-    });
-</code></pre>
+ * This layout allows you to easily render content into an HTML table. The total number of columns can be specified, and
+ * rowspan and colspan can be used to create complex layouts within the table. This class is intended to be extended or
+ * created via the `layout: {type: 'table'}` {@link Ext.container.Container#layout} config, and should generally not
+ * need to be created directly via the new keyword.
+ *
+ * Note that when creating a layout via config, the layout-specific config properties must be passed in via the {@link
+ * Ext.container.Container#layout} object which will then be applied internally to the layout. In the case of
+ * TableLayout, the only valid layout config properties are {@link #columns} and {@link #tableAttrs}. However, the items
+ * added to a TableLayout can supply the following table-specific config properties:
+ *
+ *   - **rowspan** Applied to the table cell containing the item.
+ *   - **colspan** Applied to the table cell containing the item.
+ *   - **cellId** An id applied to the table cell containing the item.
+ *   - **cellCls** A CSS class name added to the table cell containing the item.
+ *
+ * The basic concept of building up a TableLayout is conceptually very similar to building up a standard HTML table. You
+ * simply add each panel (or "cell") that you want to include along with any span attributes specified as the special
+ * config properties of rowspan and colspan which work exactly like their HTML counterparts. Rather than explicitly
+ * creating and nesting rows and columns as you would in HTML, you simply specify the total column count in the
+ * layoutConfig and start adding panels in their natural order from left to right, top to bottom. The layout will
+ * automatically figure out, based on the column count, rowspans and colspans, how to position each panel within the
+ * table. Just like with HTML tables, your rowspans and colspans must add up correctly in your overall layout or you'll
+ * end up with missing and/or extra cells! Example usage:
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Table Layout',
+ *         width: 300,
+ *         height: 150,
+ *         layout: {
+ *             type: 'table',
+ *             // The total column count must be specified here
+ *             columns: 3
+ *         },
+ *         defaults: {
+ *             // applied to each contained panel
+ *             bodyStyle: 'padding:20px'
+ *         },
+ *         items: [{
+ *             html: 'Cell A content',
+ *             rowspan: 2
+ *         },{
+ *             html: 'Cell B content',
+ *             colspan: 2
+ *         },{
+ *             html: 'Cell C content',
+ *             cellCls: 'highlight'
+ *         },{
+ *             html: 'Cell D content'
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
  */
-
 Ext.define('Ext.layout.container.Table', {
 
     /* Begin Definitions */
@@ -100115,7 +104413,7 @@ Ext.define('Ext.layout.container.Table', {
 
     /**
      * @cfg {Number} columns
-     * The total number of columns to create in the table for this layout.  If not specified, all Components added to
+     * The total number of columns to create in the table for this layout. If not specified, all Components added to
      * this layout will be rendered into a single row using one column per Component.
      */
 
@@ -100136,33 +104434,34 @@ Ext.define('Ext.layout.container.Table', {
 
     /**
      * @cfg {Object} tableAttrs
-     * <p>An object containing properties which are added to the {@link Ext.core.DomHelper DomHelper} specification
-     * used to create the layout's <tt>&lt;table&gt;</tt> element. Example:</p><pre><code>
-{
-    xtype: 'panel',
-    layout: {
-        type: 'table',
-        columns: 3,
-        tableAttrs: {
-            style: {
-                width: '100%'
-            }
-        }
-    }
-}</code></pre>
+     * An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification used to
+     * create the layout's `<table>` element. Example:
+     *
+     *     {
+     *         xtype: 'panel',
+     *         layout: {
+     *             type: 'table',
+     *             columns: 3,
+     *             tableAttrs: {
+     *                 style: {
+     *                     width: '100%'
+     *                 }
+     *             }
+     *         }
+     *     }
      */
     tableAttrs:null,
 
     /**
      * @cfg {Object} trAttrs
-     * <p>An object containing properties which are added to the {@link Ext.core.DomHelper DomHelper} specification
-     * used to create the layout's <tt>&lt;tr&gt;</tt> elements.
+     * An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification used to
+     * create the layout's <tr> elements.
      */
 
     /**
      * @cfg {Object} tdAttrs
-     * <p>An object containing properties which are added to the {@link Ext.core.DomHelper DomHelper} specification
-     * used to create the layout's <tt>&lt;td&gt;</tt> elements.
+     * An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification used to
+     * create the layout's <td> elements.
      */
 
     /**
@@ -100256,7 +104555,7 @@ Ext.define('Ext.layout.container.Table', {
      * Determine the row and cell indexes for each component, taking into consideration
      * the number of columns and each item's configured colspan/rowspan values.
      * @param {Array} items The layout components
-     * @return {Array} List of row and cell indexes for each of the components
+     * @return {Object[]} List of row and cell indexes for each of the components
      */
     calculateCells: function(items) {
         var cells = [],
@@ -100343,16 +104642,10 @@ Ext.define('Ext.layout.container.Table', {
     }
 });
 /**
- * @class Ext.menu.Item
- * @extends Ext.Component
- *
  * A base class for all menu items that require menu-related functionality such as click handling,
  * sub-menus, icons, etc.
  *
- * {@img Ext.menu.Menu/Ext.menu.Menu.png Ext.menu.Menu component}
- *
- * __Example Usage:__
- *
+ *     @example
  *     Ext.create('Ext.menu.Menu', {
  *         width: 100,
  *         height: 100,
@@ -100362,13 +104655,12 @@ Ext.define('Ext.layout.container.Table', {
  *             text: 'icon item',
  *             iconCls: 'add16'
  *         },{
- *             text: 'text item',
+ *             text: 'text item'
  *         },{
  *             text: 'plain item',
  *             plain: true
  *         }]
  *     });
- *
  */
 Ext.define('Ext.menu.Item', {
     extend: 'Ext.Component',
@@ -100380,11 +104672,15 @@ Ext.define('Ext.menu.Item', {
      * Whether or not this item is currently activated
      */
 
+    /**
+     * @property {Ext.menu.Menu} parentMenu
+     * The parent Menu of this item.
+     */
+
     /**
      * @cfg {String} activeCls
      * The CSS class added to the menu item when the item is activated (focused/mouseover).
      * Defaults to `Ext.baseCSSPrefix + 'menu-item-active'`.
-     * @markdown
      */
     activeCls: Ext.baseCSSPrefix + 'menu-item-active',
 
@@ -100396,7 +104692,6 @@ Ext.define('Ext.menu.Item', {
     /**
      * @cfg {Boolean} canActivate
      * Whether or not this menu item can be activated when focused/mouseovered. Defaults to `true`.
-     * @markdown
      */
     canActivate: true,
 
@@ -100404,7 +104699,6 @@ Ext.define('Ext.menu.Item', {
      * @cfg {Number} clickHideDelay
      * The delay in milliseconds to wait before hiding the menu after clicking the menu item.
      * This only has an effect when `hideOnClick: true`. Defaults to `1`.
-     * @markdown
      */
     clickHideDelay: 1,
 
@@ -100418,7 +104712,6 @@ Ext.define('Ext.menu.Item', {
      * @cfg {String} disabledCls
      * The CSS class added to the menu item when the item is disabled.
      * Defaults to `Ext.baseCSSPrefix + 'menu-item-disabled'`.
-     * @markdown
      */
     disabledCls: Ext.baseCSSPrefix + 'menu-item-disabled',
 
@@ -100465,7 +104758,7 @@ Ext.define('Ext.menu.Item', {
 
     /**
      * @cfg {String} menuAlign
-     * The default {@link Ext.core.Element#getAlignToXY Ext.Element.getAlignToXY} anchor position value for this
+     * The default {@link Ext.Element#getAlignToXY Ext.Element.getAlignToXY} anchor position value for this
      * item's sub-menu relative to this item's position. Defaults to `'tl-tr?'`.
      * @markdown
      */
@@ -100496,11 +104789,11 @@ Ext.define('Ext.menu.Item', {
             '{text}',
         '</tpl>',
         '<tpl if="!plain">',
-            '<a class="' + Ext.baseCSSPrefix + 'menu-item-link" href="{href}" <tpl if="hrefTarget">target="{hrefTarget}"</tpl> hidefocus="true" unselectable="on">',
-                '<img src="{icon}" class="' + Ext.baseCSSPrefix + 'menu-item-icon {iconCls}" />',
-                '<span class="' + Ext.baseCSSPrefix + 'menu-item-text" <tpl if="menu">style="margin-right: 17px;"</tpl> >{text}</span>',
+            '<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="menu">style="margin-right: 17px;"</tpl> >{text}</span>',
                 '<tpl if="menu">',
-                    '<img src="' + Ext.BLANK_IMAGE_URL + '" class="' + Ext.baseCSSPrefix + 'menu-item-arrow" />',
+                    '<img id="{id}-arrowEl" src="{blank}" class="' + Ext.baseCSSPrefix + 'menu-item-arrow" />',
                 '</tpl>',
             '</a>',
         '</tpl>'
@@ -100690,24 +104983,20 @@ Ext.define('Ext.menu.Item', {
 
     onRender: function(ct, pos) {
         var me = this,
-            prefix = '.' + Ext.baseCSSPrefix;
+            blank = Ext.BLANK_IMAGE_URL;
 
         Ext.applyIf(me.renderData, {
             href: me.href || '#',
             hrefTarget: me.hrefTarget,
-            icon: me.icon || Ext.BLANK_IMAGE_URL,
+            icon: me.icon || blank,
             iconCls: me.iconCls + (me.checkChangeDisabled ? ' ' + me.disabledCls : ''),
             menu: Ext.isDefined(me.menu),
             plain: me.plain,
-            text: me.text
+            text: me.text,
+            blank: blank
         });
 
-        Ext.applyIf(me.renderSelectors, {
-            itemEl: prefix + 'menu-item-link',
-            iconEl: prefix + 'menu-item-icon',
-            textEl: prefix + 'menu-item-text',
-            arrowEl: prefix + 'menu-item-arrow'
-        });
+        me.addChildEls('itemEl', 'iconEl', 'textEl', 'arrowEl');
 
         me.callParent(arguments);
     },
@@ -100761,15 +105050,9 @@ Ext.define('Ext.menu.Item', {
 });
 
 /**
- * @class Ext.menu.CheckItem
- * @extends Ext.menu.Item
- *
  * A menu item that contains a togglable checkbox by default, but that can also be a part of a radio group.
  *
- * {@img Ext.menu.CheckItem/Ext.menu.CheckItem.png Ext.menu.CheckItem component}
- *
- * __Example Usage__
- *
+ *     @example
  *     Ext.create('Ext.menu.Menu', {
  *         width: 100,
  *         height: 110,
@@ -100787,8 +105070,7 @@ Ext.define('Ext.menu.Item', {
  *         },{
  *             text: 'regular item'
  *         }]
- *     }); 
- *     
+ *     });
  */
 Ext.define('Ext.menu.CheckItem', {
     extend: 'Ext.menu.Item',
@@ -100798,14 +105080,12 @@ Ext.define('Ext.menu.CheckItem', {
      * @cfg {String} checkedCls
      * The CSS class used by {@link #cls} to show the checked state.
      * Defaults to `Ext.baseCSSPrefix + 'menu-item-checked'`.
-     * @markdown
      */
     checkedCls: Ext.baseCSSPrefix + 'menu-item-checked',
     /**
      * @cfg {String} uncheckedCls
      * The CSS class used by {@link #cls} to show the unchecked state.
      * Defaults to `Ext.baseCSSPrefix + 'menu-item-unchecked'`.
-     * @markdown
      */
     uncheckedCls: Ext.baseCSSPrefix + 'menu-item-unchecked',
     /**
@@ -100813,7 +105093,6 @@ Ext.define('Ext.menu.CheckItem', {
      * The CSS class applied to this item's icon image to denote being a part of a radio group.
      * Defaults to `Ext.baseCSSClass + 'menu-group-icon'`.
      * Any specified {@link #iconCls} overrides this.
-     * @markdown
      */
     groupCls: Ext.baseCSSPrefix + 'menu-group-icon',
 
@@ -100821,7 +105100,6 @@ Ext.define('Ext.menu.CheckItem', {
      * @cfg {Boolean} hideOnClick
      * Whether to not to hide the owning menu when this item is clicked.
      * Defaults to `false` for checkbox items, and to `true` for radio group items.
-     * @markdown
      */
     hideOnClick: false,
 
@@ -100906,7 +105184,6 @@ Ext.define('Ext.menu.CheckItem', {
      * Sets the checked state of the item
      * @param {Boolean} checked True to check, false to uncheck
      * @param {Boolean} suppressEvents (optional) True to prevent firing the checkchange events. Defaults to `false`.
-     * @markdown
      */
     setChecked: function(checked, suppressEvents) {
         var me = this;
@@ -100960,10 +105237,14 @@ Ext.define('Ext.menu.KeyNav', {
     },
 
     enter: function(e) {
-        var menu = this.menu;
-
+        var menu = this.menu,
+            focused = menu.focusedItem;
         if (menu.activeItem) {
             menu.onClick(e);
+        } else if (focused && focused.isFormField) {
+            // prevent stopEvent being called
+            return true;
         }
     },
 
@@ -101055,16 +105336,10 @@ Ext.define('Ext.menu.KeyNav', {
     }
 });
 /**
- * @class Ext.menu.Separator
- * @extends Ext.menu.Item
- *
  * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
  * add one of these by using "-" in your call to add() or in your items config rather than creating one directly.
  *
- * {@img Ext.menu.Separator/Ext.menu.Separator.png Ext.menu.Separator component}
- *
- * ## Code 
- *
+ *     @example
  *     Ext.create('Ext.menu.Menu', {
  *         width: 100,
  *         height: 100,
@@ -101080,156 +105355,141 @@ Ext.define('Ext.menu.KeyNav', {
  *         },{
  *            text: 'regular item',
  *         }]
- *     }); 
- *
- * @markdown
+ *     });
  */
 Ext.define('Ext.menu.Separator', {
     extend: 'Ext.menu.Item',
     alias: 'widget.menuseparator',
-    
+
     /**
      * @cfg {String} activeCls @hide
      */
-    
+
     /**
      * @cfg {Boolean} canActivate @hide
      */
     canActivate: false,
-    
+
     /**
      * @cfg {Boolean} clickHideDelay @hide
      */
-     
+
     /**
      * @cfg {Boolean} destroyMenu @hide
      */
-     
+
     /**
      * @cfg {Boolean} disabledCls @hide
      */
-     
+
     focusable: false,
-     
+
     /**
      * @cfg {String} href @hide
      */
-    
+
     /**
      * @cfg {String} hrefTarget @hide
      */
-    
+
     /**
      * @cfg {Boolean} hideOnClick @hide
      */
     hideOnClick: false,
-    
+
     /**
      * @cfg {String} icon @hide
      */
-    
+
     /**
      * @cfg {String} iconCls @hide
      */
-    
+
     /**
-     * @cfg {Mixed} menu @hide
+     * @cfg {Object} menu @hide
      */
-    
+
     /**
      * @cfg {String} menuAlign @hide
      */
-    
+
     /**
      * @cfg {Number} menuExpandDelay @hide
      */
-    
+
     /**
      * @cfg {Number} menuHideDelay @hide
      */
-    
+
     /**
      * @cfg {Boolean} plain @hide
      */
     plain: true,
-    
+
     /**
      * @cfg {String} separatorCls
      * The CSS class used by the separator item to show the incised line.
      * Defaults to `Ext.baseCSSPrefix + 'menu-item-separator'`.
-     * @markdown
      */
     separatorCls: Ext.baseCSSPrefix + 'menu-item-separator',
-    
+
     /**
      * @cfg {String} text @hide
      */
     text: '&#160;',
-    
+
     onRender: function(ct, pos) {
         var me = this,
             sepCls = me.separatorCls;
-            
+
         me.cls += ' ' + sepCls;
-        
-        Ext.applyIf(me.renderSelectors, {
-            itemSepEl: '.' + sepCls
-        });
-        
+
         me.callParent(arguments);
     }
 });
 /**
- * @class Ext.menu.Menu
- * @extends Ext.panel.Panel
- *
  * A menu object. This is the container to which you may add {@link Ext.menu.Item menu items}.
  *
  * Menus may contain either {@link Ext.menu.Item menu items}, or general {@link Ext.Component Components}.
  * Menus may also contain {@link Ext.panel.AbstractPanel#dockedItems docked items} because it extends {@link Ext.panel.Panel}.
  *
  * To make a contained general {@link Ext.Component Component} line up with other {@link Ext.menu.Item menu items},
- * specify `{@link Ext.menu.Item#iconCls iconCls}: 'no-icon'` _or_ `{@link Ext.menu.Item#indent indent}: true`.
- * This reserves a space for an icon, and indents the Component in line with the other menu items.
- * See {@link Ext.form.field.ComboBox}.{@link Ext.form.field.ComboBox#getListParent getListParent} for an example.
+ * specify `{@link Ext.menu.Item#plain plain}: true`. This reserves a space for an icon, and indents the Component
+ * in line with the other menu items.
  *
- * By default, Menus are absolutely positioned, floating Components. By configuring a Menu with `{@link #floating}:false`,
+ * By default, Menus are absolutely positioned, floating Components. By configuring a Menu with `{@link #floating}: false`,
  * a Menu may be used as a child of a {@link Ext.container.Container Container}.
  *
- * {@img Ext.menu.Item/Ext.menu.Item.png Ext.menu.Item component}
- *
- *__Example Usage__
- *
+ *     @example
  *     Ext.create('Ext.menu.Menu', {
  *         width: 100,
  *         height: 100,
  *         margin: '0 0 10 0',
  *         floating: false,  // usually you want this set to True (default)
  *         renderTo: Ext.getBody(),  // usually rendered by it's containing component
- *         items: [{                        
- *             text: 'regular item 1'        
+ *         items: [{
+ *             text: 'regular item 1'
  *         },{
  *             text: 'regular item 2'
  *         },{
- *             text: 'regular item 3'  
+ *             text: 'regular item 3'
  *         }]
- *     }); 
- *     
+ *     });
+ *
  *     Ext.create('Ext.menu.Menu', {
  *         width: 100,
  *         height: 100,
  *         plain: true,
  *         floating: false,  // usually you want this set to True (default)
  *         renderTo: Ext.getBody(),  // usually rendered by it's containing component
- *         items: [{                        
- *             text: 'plain item 1'    
+ *         items: [{
+ *             text: 'plain item 1'
  *         },{
  *             text: 'plain item 2'
  *         },{
  *             text: 'plain item 3'
  *         }]
- *     }); 
- *
+ *     });
  */
 Ext.define('Ext.menu.Menu', {
     extend: 'Ext.panel.Panel',
@@ -101244,10 +105504,14 @@ Ext.define('Ext.menu.Menu', {
         'Ext.menu.Separator'
     ],
 
+    /**
+     * @property {Ext.menu.Menu} parentMenu
+     * The parent Menu of this Menu.
+     */
+
     /**
      * @cfg {Boolean} allowOtherMenus
-     * True to allow multiple menus to be displayed at the same time. Defaults to `false`.
-     * @markdown
+     * True to allow multiple menus to be displayed at the same time.
      */
     allowOtherMenus: false,
 
@@ -101263,9 +105527,8 @@ Ext.define('Ext.menu.Menu', {
 
     /**
      * @cfg {String} defaultAlign
-     * The default {@link Ext.core.Element#getAlignToXY Ext.core.Element#getAlignToXY} anchor position value for this menu
-     * relative to its element of origin. Defaults to `'tl-bl?'`.
-     * @markdown
+     * The default {@link Ext.Element#getAlignToXY Ext.Element#getAlignToXY} anchor position value for this menu
+     * relative to its element of origin.
      */
     defaultAlign: 'tl-bl?',
 
@@ -101274,7 +105537,6 @@ Ext.define('Ext.menu.Menu', {
      * A Menu configured as `floating: true` (the default) will be rendered as an absolutely positioned,
      * {@link Ext.Component#floating floating} {@link Ext.Component Component}. If configured as `floating: false`, the Menu may be
      * used as a child item of another {@link Ext.container.Container Container}.
-     * @markdown
      */
     floating: true,
 
@@ -101285,10 +105547,10 @@ Ext.define('Ext.menu.Menu', {
     constrain: true,
 
     /**
-     * @cfg {Boolean} hidden
+     * @cfg {Boolean} [hidden=undefined]
      * True to initially render the Menu as hidden, requiring to be shown manually.
+     *
      * Defaults to `true` when `floating: true`, and defaults to `false` when `floating: false`.
-     * @markdown
      */
     hidden: true,
 
@@ -101297,8 +105559,7 @@ Ext.define('Ext.menu.Menu', {
     /**
      * @cfg {Boolean} ignoreParentClicks
      * True to ignore clicks on any item in this menu that is a parent item (displays a submenu)
-     * so that the submenu is not dismissed when clicking the parent item. Defaults to `false`.
-     * @markdown
+     * so that the submenu is not dismissed when clicking the parent item.
      */
     ignoreParentClicks: false,
 
@@ -101309,22 +105570,20 @@ Ext.define('Ext.menu.Menu', {
      */
 
     /**
-     * @cfg {Boolean} showSeparator True to show the icon separator. (defaults to true).
+     * @cfg {Boolean} showSeparator
+     * True to show the icon separator.
      */
     showSeparator : true,
 
     /**
      * @cfg {Number} minWidth
-     * The minimum width of the Menu. Defaults to `120`.
-     * @markdown
+     * The minimum width of the Menu.
      */
     minWidth: 120,
 
     /**
-     * @cfg {Boolean} plain
-     * True to remove the incised line down the left side of the menu and to not
-     * indent general Component items. Defaults to `false`.
-     * @markdown
+     * @cfg {Boolean} [plain=false]
+     * True to remove the incised line down the left side of the menu and to not indent general Component items.
      */
 
     initComponent: function() {
@@ -101340,7 +105599,6 @@ Ext.define('Ext.menu.Menu', {
              * @param {Ext.menu.Menu} menu The menu which has been clicked
              * @param {Ext.Component} item The menu item that was clicked. `undefined` if not applicable.
              * @param {Ext.EventObject} e The underlying {@link Ext.EventObject}.
-             * @markdown
              */
             'click',
 
@@ -101349,7 +105607,6 @@ Ext.define('Ext.menu.Menu', {
              * Fires when the mouse enters this menu
              * @param {Ext.menu.Menu} menu The menu
              * @param {Ext.EventObject} e The underlying {@link Ext.EventObject}
-             * @markdown
              */
             'mouseenter',
 
@@ -101358,7 +105615,6 @@ Ext.define('Ext.menu.Menu', {
              * Fires when the mouse leaves this menu
              * @param {Ext.menu.Menu} menu The menu
              * @param {Ext.EventObject} e The underlying {@link Ext.EventObject}
-             * @markdown
              */
             'mouseleave',
 
@@ -101458,7 +105714,7 @@ Ext.define('Ext.menu.Menu', {
         // floating elements inherit their parent's width, making them the width of
         // document.body instead of the width of their contents.
         // This includes left/right dock items.
-        if ((!Ext.iStrict && Ext.isIE) || Ext.isIE6) {
+        if ((!Ext.isStrict && Ext.isIE) || Ext.isIE6) {
             var innerCt = me.layout.getRenderTarget(),
                 innerCtWidth = 0,
                 dis = me.dockedItems,
@@ -101482,6 +105738,10 @@ Ext.define('Ext.menu.Menu', {
             me.el.setWidth(newWidth);
         }
     },
+    
+    getBubbleTarget: function(){
+        return this.parentMenu || this.callParent();
+    },
 
     /**
      * Returns whether a menu item can be activated or not.
@@ -101503,7 +105763,9 @@ Ext.define('Ext.menu.Menu', {
                 delete me.activeItem;
             }
         }
-        if (me.focusedItem) {
+
+        // only blur if focusedItem is not a filter
+        if (me.focusedItem && !me.filtered) {
             me.focusedItem.blur();
             if (!me.focusedItem.$focused) {
                 delete me.focusedItem;
@@ -101740,12 +106002,12 @@ Ext.define('Ext.menu.Menu', {
     },
 
     /**
-     * Shows the floating menu by the specified {@link Ext.Component Component} or {@link Ext.core.Element Element}.
-     * @param {Mixed component} The {@link Ext.Component} or {@link Ext.core.Element} to show the menu by.
-     * @param {String} position (optional) Alignment position as used by {@link Ext.core.Element#getAlignToXY Ext.core.Element.getAlignToXY}. Defaults to `{@link #defaultAlign}`.
-     * @param {Array} offsets (optional) Alignment offsets as used by {@link Ext.core.Element#getAlignToXY Ext.core.Element.getAlignToXY}. Defaults to `undefined`.
-     * @return {Menu} This Menu.
-     * @markdown
+     * Shows the floating menu by the specified {@link Ext.Component Component} or {@link Ext.Element Element}.
+     * @param {Ext.Component/Ext.Element} component The {@link Ext.Component} or {@link Ext.Element} to show the menu by.
+     * @param {String} position (optional) Alignment position as used by {@link Ext.Element#getAlignToXY}.
+     * Defaults to `{@link #defaultAlign}`.
+     * @param {Number[]} offsets (optional) Alignment offsets as used by {@link Ext.Element#getAlignToXY}. Defaults to `undefined`.
+     * @return {Ext.menu.Menu} This Menu.
      */
     showBy: function(cmp, pos, off) {
         var me = this,
@@ -101757,6 +106019,7 @@ Ext.define('Ext.menu.Menu', {
 
             // show off-screen first so that we can calc position without causing a visual jump
             me.doAutoRender();
+            delete me.needsLayout;
 
             // Component or Element
             cmp = cmp.el || cmp;
@@ -101772,14 +106035,6 @@ Ext.define('Ext.menu.Menu', {
         }
         return me;
     },
-    
-    // inherit docs
-    showAt: function(){
-        this.callParent(arguments);
-        if (this.floating) {
-            this.doConstrain();
-        }    
-    },
 
     doConstrain : function() {
         var me = this,
@@ -101792,7 +106047,8 @@ Ext.define('Ext.menu.Menu', {
         me.setSize();
         full = me.getHeight();
         if (me.floating) {
-            parentEl = Ext.fly(me.el.dom.parentNode);
+            //if our reset css is scoped, there will be a x-reset wrapper on this menu which we need to skip
+            parentEl = Ext.fly(me.el.getScopeParent());
             scrollTop = parentEl.getScroll().top;
             viewHeight = parentEl.getViewSize().height;
             //Normalize y by the scroll position for the parent element.  Need to move it into the coordinate space
@@ -101821,34 +106077,33 @@ Ext.define('Ext.menu.Menu', {
                 me.iconSepEl.setHeight(me.layout.getRenderTarget().dom.scrollHeight);
             }
         }
-        vector = me.getConstrainVector(me.el.dom.parentNode);
+        vector = me.getConstrainVector(me.el.getScopeParent());
         if (vector) {
             me.setPosition(me.getPosition()[0] + vector[0]);
         }
         me.el.setY(returnY);
     }
 });
+
 /**
- * @class Ext.menu.ColorPicker
- * @extends Ext.menu.Menu
- * <p>A menu containing a {@link Ext.picker.Color} Component.</p>
- * <p>Notes:</p><div class="mdetail-params"><ul>
- * <li>Although not listed here, the <b>constructor</b> for this class
- * accepts all of the configuration options of <b>{@link Ext.picker.Color}</b>.</li>
- * <li>If subclassing ColorMenu, any configuration options for the ColorPicker must be
- * applied to the <tt><b>initialConfig</b></tt> property of the ColorMenu.
- * Applying {@link Ext.picker.Color ColorPicker} configuration settings to
- * <b><tt>this</tt></b> will <b>not</b> affect the ColorPicker's configuration.</li>
- * </ul></div>
+ * A menu containing a Ext.picker.Color Component.
  *
- * {@img Ext.menu.ColorPicker/Ext.menu.ColorPicker.png Ext.menu.ColorPicker component}
+ * Notes:
  *
- * __Example Usage__
+ *   - Although not listed here, the **constructor** for this class accepts all of the
+ *     configuration options of {@link Ext.picker.Color}.
+ *   - If subclassing ColorMenu, any configuration options for the ColorPicker must be
+ *     applied to the **initialConfig** property of the ColorMenu. Applying
+ *     {@link Ext.picker.Color ColorPicker} configuration settings to `this` will **not**
+ *     affect the ColorPicker's configuration.
  *
+ * Example:
+ *
+ *     @example
  *     var colorPicker = Ext.create('Ext.menu.ColorPicker', {
  *         value: '000000'
  *     });
- *  
+ *
  *     Ext.create('Ext.menu.Menu', {
  *         width: 100,
  *         height: 90,
@@ -101864,8 +106119,6 @@ Ext.define('Ext.menu.Menu', {
  *             text: 'regular item'
  *         }]
  *     });
- *
- * @author Nicolas Ferrero
  */
  Ext.define('Ext.menu.ColorPicker', {
      extend: 'Ext.menu.Menu',
@@ -101878,13 +106131,13 @@ Ext.define('Ext.menu.Menu', {
 
     /**
      * @cfg {Boolean} hideOnClick
-     * False to continue showing the menu after a date is selected, defaults to true.
+     * False to continue showing the menu after a date is selected.
      */
     hideOnClick : true,
 
     /**
      * @cfg {String} pickerId
-     * An id to assign to the underlying color picker. Defaults to <tt>null</tt>.
+     * An id to assign to the underlying color picker.
      */
     pickerId : null,
 
@@ -101894,9 +106147,8 @@ Ext.define('Ext.menu.Menu', {
      */
 
     /**
+     * @property {Ext.picker.Color} picker
      * The {@link Ext.picker.Color} instance for this ColorMenu
-     * @property picker
-     * @type ColorPicker
      */
 
     /**
@@ -101910,8 +106162,11 @@ Ext.define('Ext.menu.Menu', {
      */
 
     initComponent : function(){
-        var me = this;
+        var me = this,
+            cfg = Ext.apply({}, me.initialConfig);
 
+        // Ensure we don't get duplicate listeners
+        delete cfg.listeners;
         Ext.apply(me, {
             plain: true,
             showSeparator: false,
@@ -101919,7 +106174,7 @@ Ext.define('Ext.menu.Menu', {
                 cls: Ext.baseCSSPrefix + 'menu-color-item',
                 id: me.pickerId,
                 xtype: 'colorpicker'
-            }, me.initialConfig)
+            }, cfg)
         });
 
         me.callParent(arguments);
@@ -101928,9 +106183,7 @@ Ext.define('Ext.menu.Menu', {
 
         /**
          * @event select
-         * Fires when a date is selected from the {@link #picker Ext.picker.Color}
-         * @param {Ext.picker.Color} picker The {@link #picker Ext.picker.Color}
-         * @param {String} color The 6-digit color hex code (without the # symbol)
+         * @alias Ext.picker.Color#select
          */
         me.relayEvents(me.picker, ['select']);
 
@@ -101948,28 +106201,25 @@ Ext.define('Ext.menu.Menu', {
     }
  });
 /**
- * @class Ext.menu.DatePicker
- * @extends Ext.menu.Menu
- * <p>A menu containing an {@link Ext.picker.Date} Component.</p>
- * <p>Notes:</p><div class="mdetail-params"><ul>
- * <li>Although not listed here, the <b>constructor</b> for this class
- * accepts all of the configuration options of <b>{@link Ext.picker.Date}</b>.</li>
- * <li>If subclassing DateMenu, any configuration options for the DatePicker must be
- * applied to the <tt><b>initialConfig</b></tt> property of the DateMenu.
- * Applying {@link Ext.picker.Date DatePicker} configuration settings to
- * <b><tt>this</tt></b> will <b>not</b> affect the DatePicker's configuration.</li>
- * </ul></div>
+ * A menu containing an Ext.picker.Date Component.
+ *
+ * Notes:
  *
- * {@img Ext.menu.DatePicker/Ext.menu.DatePicker.png Ext.menu.DatePicker component}
+ * - Although not listed here, the **constructor** for this class accepts all of the
+ *   configuration options of **{@link Ext.picker.Date}**.
+ * - If subclassing DateMenu, any configuration options for the DatePicker must be applied
+ *   to the **initialConfig** property of the DateMenu. Applying {@link Ext.picker.Date Date Picker}
+ *   configuration settings to **this** will **not** affect the Date Picker's configuration.
  *
- * __Example Usage__
+ * Example:
  *
+ *     @example
  *     var dateMenu = Ext.create('Ext.menu.DatePicker', {
  *         handler: function(dp, date){
- *             Ext.Msg.alert('Date Selected', 'You choose {0}.', Ext.Date.format(date, 'M j, Y'));
+ *             Ext.Msg.alert('Date Selected', 'You selected ' + Ext.Date.format(date, 'M j, Y'));
  *         }
  *     });
- *  
+ *
  *     Ext.create('Ext.menu.Menu', {
  *         width: 100,
  *         height: 90,
@@ -101985,8 +106235,6 @@ Ext.define('Ext.menu.Menu', {
  *             text: 'regular item'
  *         }]
  *     });
- *
- * @author Nicolas Ferrero
  */
  Ext.define('Ext.menu.DatePicker', {
      extend: 'Ext.menu.Menu',
@@ -101999,13 +106247,13 @@ Ext.define('Ext.menu.Menu', {
 
     /**
      * @cfg {Boolean} hideOnClick
-     * False to continue showing the menu after a date is selected, defaults to true.
+     * False to continue showing the menu after a date is selected.
      */
     hideOnClick : true,
 
     /**
      * @cfg {String} pickerId
-     * An id to assign to the underlying date picker. Defaults to <tt>null</tt>.
+     * An id to assign to the underlying date picker.
      */
     pickerId : null,
 
@@ -102015,9 +106263,8 @@ Ext.define('Ext.menu.Menu', {
      */
 
     /**
+     * @property {Ext.picker.Date} picker
      * The {@link Ext.picker.Date} instance for this DateMenu
-     * @property picker
-     * @type Ext.picker.Date
      */
 
     /**
@@ -102050,9 +106297,7 @@ Ext.define('Ext.menu.Menu', {
         me.picker = me.down('datepicker');
         /**
          * @event select
-         * Fires when a date is selected from the {@link #picker Ext.picker.Date}
-         * @param {Ext.picker.Date} picker The {@link #picker Ext.picker.Date}
-         * @param {Date} date The selected date
+         * @alias Ext.picker.Date#select
          */
         me.relayEvents(me.picker, ['select']);
 
@@ -102066,44 +106311,38 @@ Ext.define('Ext.menu.Menu', {
     }
  });
 /**
- * @class Ext.panel.Tool
- * @extends Ext.Component
-
-This class is used to display small visual icons in the header of a panel. There are a set of
-25 icons that can be specified by using the {@link #type} config. The {@link #handler} config
-can be used to provide a function that will respond to any click events. In general, this class
-will not be instantiated directly, rather it will be created by specifying the {@link Ext.panel.Panel#tools}
-configuration on the Panel itself.
-
-__Example Usage__
-
-    Ext.create('Ext.panel.Panel', {
-       width: 200,
-       height: 200,
-       renderTo: document.body,
-       title: 'A Panel',
-       tools: [{
-           type: 'help',
-           handler: function(){
-               // show help here
-           }
-       }, {
-           itemId: 'refresh',
-           type: 'refresh',
-           hidden: true,
-           handler: function(){
-               // do refresh
-           }
-       }, {
-           type: 'search',
-           handler: function(event, target, owner, tool){
-               // do search
-               owner.child('#refresh').show();
-           }
-       }]
-    });
-
- * @markdown
+ * This class is used to display small visual icons in the header of a panel. There are a set of
+ * 25 icons that can be specified by using the {@link #type} config. The {@link #handler} config
+ * can be used to provide a function that will respond to any click events. In general, this class
+ * will not be instantiated directly, rather it will be created by specifying the {@link Ext.panel.Panel#tools}
+ * configuration on the Panel itself.
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         width: 200,
+ *         height: 200,
+ *         renderTo: document.body,
+ *         title: 'A Panel',
+ *         tools: [{
+ *             type: 'help',
+ *             handler: function(){
+ *                 // show help here
+ *             }
+ *         }, {
+ *             itemId: 'refresh',
+ *             type: 'refresh',
+ *             hidden: true,
+ *             handler: function(){
+ *                 // do refresh
+ *             }
+ *         }, {
+ *             type: 'search',
+ *             handler: function(event, target, owner, tool){
+ *                 // do search
+ *                 owner.child('#refresh').show();
+ *             }
+ *         }]
+ *     });
  */
 Ext.define('Ext.panel.Tool', {
     extend: 'Ext.Component',
@@ -102115,65 +106354,67 @@ Ext.define('Ext.panel.Tool', {
     toolPressedCls: Ext.baseCSSPrefix + 'tool-pressed',
     toolOverCls: Ext.baseCSSPrefix + 'tool-over',
     ariaRole: 'button',
-    renderTpl: ['<img src="{blank}" class="{baseCls}-{type}" role="presentation"/>'],
-    
+    renderTpl: ['<img id="{id}-toolEl" src="{blank}" class="{baseCls}-{type}" role="presentation"/>'],
+
     /**
      * @cfg {Function} handler
-     * A function to execute when the tool is clicked.
-     * Arguments passed are:
-     * <ul>
-     * <li><b>event</b> : Ext.EventObject<div class="sub-desc">The click event.</div></li>
-     * <li><b>toolEl</b> : Ext.core.Element<div class="sub-desc">The tool Element.</div></li>
-     * <li><b>panel</b> : Ext.panel.Panel<div class="sub-desc">The host Panel</div></li>
-     * <li><b>tool</b> : Ext.panel.Tool<div class="sub-desc">The tool object</div></li>
-     * </ul>
+     * A function to execute when the tool is clicked. Arguments passed are:
+     *
+     * - **event** : Ext.EventObject - The click event.
+     * - **toolEl** : Ext.Element - The tool Element.
+     * - **owner** : Ext.panel.Header - The host panel header.
+     * - **tool** : Ext.panel.Tool - The tool object
      */
-    
+
     /**
      * @cfg {Object} scope
      * The scope to execute the {@link #handler} function. Defaults to the tool.
      */
-    
+
     /**
      * @cfg {String} type
      * The type of tool to render. The following types are available:
-     * <ul>
-     * <li>close</li>
-     * <li>collapse</li>
-     * <li>down</li>
-     * <li>expand</li>
-     * <li>gear</li>
-     * <li>help</li>
-     * <li>left</li>
-     * <li>maximize</li>
-     * <li>minimize</li>
-     * <li>minus</li>
-     * <li>move</li>
-     * <li>next</li>
-     * <li>pin</li>
-     * <li>plus</li>
-     * <li>prev</li>
-     * <li>print</li>
-     * <li>refresh</li>
-     * <li>resize</li>
-     * <li>restore</li>
-     * <li>right</li>
-     * <li>save</li>
-     * <li>search</li>
-     * <li>toggle</li>
-     * <li>unpin</li>
-     * <li>up</li>
-     * </ul>
+     *
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-close"></span> close
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-minimize"></span> minimize
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-maximize"></span> maximize
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-restore"></span> restore
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-toggle"></span> toggle
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-gear"></span> gear
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-prev"></span> prev
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-next"></span> next
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-pin"></span> pin
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-unpin"></span> unpin
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-right"></span> right
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-left"></span> left
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-down"></span> down
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-up"></span> up
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-refresh"></span> refresh
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-plus"></span> plus
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-minus"></span> minus
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-search"></span> search
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-save"></span> save
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-help"></span> help
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-print"></span> print
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-expand"></span> expand
+     * - <span class="x-tool"><img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" class="x-tool-collapse"></span> collapse
+     */
+
+    /**
+     * @cfg {String/Object} tooltip
+     * The tooltip for the tool - can be a string to be used as innerHTML (html tags are accepted) or QuickTips config
+     * object
      */
-    
-    /**
-     * @cfg {String/Object} tooltip 
-     * The tooltip for the tool - can be a string to be used as innerHTML (html tags are accepted) or QuickTips config object
+
+     /**
+     * @cfg {String} tooltipType
+     * The type of tooltip to use. Either 'qtip' (default) for QuickTips or 'title' for title attribute.
      */
-    
+    tooltipType: 'qtip',
+
     /**
      * @cfg {Boolean} stopEvent
-     * Defaults to true. Specify as false to allow click event to propagate.
+     * Specify as false to allow click event to propagate.
      */
     stopEvent: true,
 
@@ -102188,41 +106429,41 @@ Ext.define('Ext.panel.Tool', {
              */
             'click'
         );
-        
+
         //<debug>
         var types = [
-            'close', 
-            'collapse', 
-            'down', 
-            'expand', 
-            'gear', 
-            'help', 
-            'left', 
-            'maximize', 
-            'minimize', 
-            'minus', 
-            'move', 
-            'next', 
-            'pin', 
-            'plus', 
-            'prev', 
-            'print', 
-            'refresh', 
-            'resize', 
-            'restore', 
-            'right', 
-            'save', 
-            'search', 
+            'close',
+            'collapse',
+            'down',
+            'expand',
+            'gear',
+            'help',
+            'left',
+            'maximize',
+            'minimize',
+            'minus',
+            'move',
+            'next',
+            'pin',
+            'plus',
+            'prev',
+            'print',
+            'refresh',
+            'resize',
+            'restore',
+            'right',
+            'save',
+            'search',
             'toggle',
-            'unpin', 
+            'unpin',
             'up'
         ];
-        
+
         if (me.id && Ext.Array.indexOf(types, me.id) > -1 && Ext.global.console) {
             Ext.global.console.warn('When specifying a tool you should use the type option, the id can conflict now that tool is a Component');
         }
         //</debug>
-        
+
         me.type = me.type || me.id;
 
         Ext.applyIf(me.renderData, {
@@ -102230,22 +106471,29 @@ Ext.define('Ext.panel.Tool', {
             blank: Ext.BLANK_IMAGE_URL,
             type: me.type
         });
-        me.renderSelectors.toolEl = '.' + me.baseCls + '-' + me.type;
+
+        me.addChildEls('toolEl');
+
+        // alias qtip, should use tooltip since it's what we have in the docs
+        me.tooltip = me.tooltip || me.qtip;
         me.callParent();
     },
 
     // inherit docs
     afterRender: function() {
-        var me = this;
+        var me = this,
+            attr;
+
         me.callParent(arguments);
-        if (me.qtip) {
-            if (Ext.isObject(me.qtip)) {
+        if (me.tooltip) {
+            if (Ext.isObject(me.tooltip)) {
                 Ext.tip.QuickTipManager.register(Ext.apply({
                     target: me.id
-                }, me.qtip));
+                }, me.tooltip));
             }
             else {
-                me.toolEl.dom.qtip = me.qtip;
+                attr = me.tooltipType == 'qtip' ? 'data-qtip' : 'title';
+                me.toolEl.dom.setAttribute(attr, me.tooltip);
             }
         }
 
@@ -102259,13 +106507,13 @@ Ext.define('Ext.panel.Tool', {
     },
 
     /**
-     * Set the type of the tool. Allows the icon to be changed.
+     * Sets the type of the tool. Allows the icon to be changed.
      * @param {String} type The new type. See the {@link #type} config.
      * @return {Ext.panel.Tool} this
      */
     setType: function(type) {
         var me = this;
-        
+
         me.type = type;
         if (me.rendered) {
             me.toolEl.dom.className = me.baseCls + '-' + type;
@@ -102283,7 +106531,7 @@ Ext.define('Ext.panel.Tool', {
     },
 
     /**
-     * Fired when the tool element is clicked
+     * Called when the tool element is clicked
      * @private
      * @param {Ext.EventObject} e
      * @param {HTMLElement} target The target element
@@ -102291,7 +106539,7 @@ Ext.define('Ext.panel.Tool', {
     onClick: function(e, target) {
         var me = this,
             owner;
-            
+
         if (me.disabled) {
             return false;
         }
@@ -102309,17 +106557,17 @@ Ext.define('Ext.panel.Tool', {
         me.fireEvent('click', me, e);
         return true;
     },
-    
+
     // inherit docs
     onDestroy: function(){
         if (Ext.isObject(this.tooltip)) {
             Ext.tip.QuickTipManager.unregister(this.id);
-        }    
+        }
         this.callParent();
     },
 
     /**
-     * Called then the user pressing their mouse button down on a tool
+     * Called when the user presses their mouse button down on a tool
      * Adds the press class ({@link #toolPressedCls})
      * @private
      */
@@ -102378,45 +106626,40 @@ Ext.define('Ext.resizer.Handle', {
 });
 
 /**
- * @class Ext.resizer.Resizer
- * <p>Applies drag handles to an element or component to make it resizable. The
- * drag handles are inserted into the element (or component's element) and
- * positioned absolute.</p>
- *
- * <p>Textarea and img elements will be wrapped with an additional div because
- * these elements do not support child nodes. The original element can be accessed
- * through the originalTarget property.</p>
- *
- * <p>Here is the list of valid resize handles:</p>
- * <pre>
-Value   Description
-------  -------------------
- 'n'     north
- 's'     south
- 'e'     east
- 'w'     west
- 'nw'    northwest
- 'sw'    southwest
- 'se'    southeast
- 'ne'    northeast
- 'all'   all
-</pre>
+ * Applies drag handles to an element or component to make it resizable. The drag handles are inserted into the element
+ * (or component's element) and positioned absolute.
+ *
+ * Textarea and img elements will be wrapped with an additional div because these elements do not support child nodes.
+ * The original element can be accessed through the originalTarget property.
+ *
+ * Here is the list of valid resize handles:
+ *
+ *     Value   Description
+ *     ------  -------------------
+ *      'n'     north
+ *      's'     south
+ *      'e'     east
+ *      'w'     west
+ *      'nw'    northwest
+ *      'sw'    southwest
+ *      'se'    southeast
+ *      'ne'    northeast
+ *      'all'   all
+ *
  * {@img Ext.resizer.Resizer/Ext.resizer.Resizer.png Ext.resizer.Resizer component}
- * <p>Here's an example showing the creation of a typical Resizer:</p>
- * <pre><code>
-    <div id="elToResize" style="width:200px; height:100px; background-color:#000000;"></div>
-
-    Ext.create('Ext.resizer.Resizer', {
-        el: 'elToResize',
-        handles: 'all',
-        minWidth: 200,
-        minHeight: 100,
-        maxWidth: 500,
-        maxHeight: 400,
-        pinned: true
-    });
-</code></pre>
-*/
+ *
+ * Here's an example showing the creation of a typical Resizer:
+ *
+ *     Ext.create('Ext.resizer.Resizer', {
+ *         el: 'elToResize',
+ *         handles: 'all',
+ *         minWidth: 200,
+ *         minHeight: 100,
+ *         maxWidth: 500,
+ *         maxHeight: 400,
+ *         pinned: true
+ *     });
+ */
 Ext.define('Ext.resizer.Resizer', {
     mixins: {
         observable: 'Ext.util.Observable'
@@ -102428,88 +106671,96 @@ Ext.define('Ext.resizer.Resizer', {
     handleCls: Ext.baseCSSPrefix + 'resizable-handle',
     pinnedCls: Ext.baseCSSPrefix + 'resizable-pinned',
     overCls:   Ext.baseCSSPrefix + 'resizable-over',
-    proxyCls:  Ext.baseCSSPrefix + 'resizable-proxy',
     wrapCls:   Ext.baseCSSPrefix + 'resizable-wrap',
 
     /**
      * @cfg {Boolean} dynamic
-     * <p>Specify as true to update the {@link #target} (Element or {@link Ext.Component Component}) dynamically during dragging.
-     * This is <code>true</code> by default, but the {@link Ext.Component Component} class passes <code>false</code> when it
-     * is configured as {@link Ext.Component#resizable}.</p>
-     * <p>If specified as <code>false</code>, a proxy element is displayed during the resize operation, and the {@link #target}
-     * is updated on mouseup.</p>
+     * Specify as true to update the {@link #target} (Element or {@link Ext.Component Component}) dynamically during
+     * dragging. This is `true` by default, but the {@link Ext.Component Component} class passes `false` when it is
+     * configured as {@link Ext.Component#resizable}.
+     *
+     * If specified as `false`, a proxy element is displayed during the resize operation, and the {@link #target} is
+     * updated on mouseup.
      */
     dynamic: true,
 
     /**
-     * @cfg {String} handles String consisting of the resize handles to display. Defaults to 's e se' for
-     * Elements and fixed position Components. Defaults to 8 point resizing for floating Components (such as Windows).
-     * Specify either <code>'all'</code> or any of <code>'n s e w ne nw se sw'</code>.
+     * @cfg {String} handles
+     * String consisting of the resize handles to display. Defaults to 's e se' for Elements and fixed position
+     * Components. Defaults to 8 point resizing for floating Components (such as Windows). Specify either `'all'` or any
+     * of `'n s e w ne nw se sw'`.
      */
     handles: 's e se',
 
     /**
-     * @cfg {Number} height Optional. The height to set target to in pixels (defaults to null)
+     * @cfg {Number} height
+     * Optional. The height to set target to in pixels
      */
     height : null,
 
     /**
-     * @cfg {Number} width Optional. The width to set the target to in pixels (defaults to null)
+     * @cfg {Number} width
+     * Optional. The width to set the target to in pixels
      */
     width : null,
 
     /**
-     * @cfg {Number} heightIncrement The increment to snap the height resize in pixels.
-     * Defaults to <code>0</code>.
+     * @cfg {Number} heightIncrement
+     * The increment to snap the height resize in pixels.
      */
     heightIncrement : 0,
 
     /**
-     * @cfg {Number} widthIncrement The increment to snap the width resize in pixels
-     * Defaults to <code>0</code>.
+     * @cfg {Number} widthIncrement
+     * The increment to snap the width resize in pixels.
      */
     widthIncrement : 0,
 
     /**
-     * @cfg {Number} minHeight The minimum height for the element (defaults to 20)
+     * @cfg {Number} minHeight
+     * The minimum height for the element
      */
     minHeight : 20,
 
     /**
-     * @cfg {Number} minWidth The minimum width for the element (defaults to 20)
+     * @cfg {Number} minWidth
+     * The minimum width for the element
      */
     minWidth : 20,
 
     /**
-     * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
+     * @cfg {Number} maxHeight
+     * The maximum height for the element
      */
     maxHeight : 10000,
 
     /**
-     * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
+     * @cfg {Number} maxWidth
+     * The maximum width for the element
      */
     maxWidth : 10000,
 
     /**
-     * @cfg {Boolean} pinned True to ensure that the resize handles are always
-     * visible, false indicates resizing by cursor changes only (defaults to false)
+     * @cfg {Boolean} pinned
+     * True to ensure that the resize handles are always visible, false indicates resizing by cursor changes only
      */
     pinned: false,
 
     /**
-     * @cfg {Boolean} preserveRatio True to preserve the original ratio between height
-     * and width during resize (defaults to false)
+     * @cfg {Boolean} preserveRatio
+     * True to preserve the original ratio between height and width during resize
      */
     preserveRatio: false,
 
     /**
-     * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
+     * @cfg {Boolean} transparent
+     * True for transparent handles. This is only applied at config time.
      */
     transparent: false,
 
     /**
-     * @cfg {Mixed} constrainTo Optional. An element, or a {@link Ext.util.Region} into which the resize operation
-     * must be constrained.
+     * @cfg {Ext.Element/Ext.util.Region} constrainTo
+     * An element, or a {@link Ext.util.Region Region} into which the resize operation must be constrained.
      */
 
     possiblePositions: {
@@ -102524,13 +106775,13 @@ Ext.define('Ext.resizer.Resizer', {
     },
 
     /**
-     * @cfg {Mixed} target The Element or Component to resize.
+     * @cfg {Ext.Element/Ext.Component} target
+     * The Element or Component to resize.
      */
 
     /**
+     * @property {Ext.Element} el
      * Outer element for resizing behavior.
-     * @type Ext.core.Element
-     * @property el
      */
 
     constructor: function(config) {
@@ -102620,10 +106871,9 @@ Ext.define('Ext.resizer.Resizer', {
         tag = me.el.dom.tagName;
         if (tag == 'TEXTAREA' || tag == 'IMG') {
             /**
-             * Reference to the original resize target if the element of the original
-             * resize target was an IMG or a TEXTAREA which must be wrapped in a DIV.
-             * @type Mixed
-             * @property originalTarget
+             * @property {Ext.Element/Ext.Component} originalTarget
+             * Reference to the original resize target if the element of the original resize target was an IMG or a
+             * TEXTAREA which must be wrapped in a DIV.
              */
             me.originalTarget = me.target;
             me.target = me.el = me.el.wrap({
@@ -102646,8 +106896,7 @@ Ext.define('Ext.resizer.Resizer', {
         }
 
         /**
-         * @type Ext.resizer.ResizeTracker
-         * @property resizeTracker
+         * @property {Ext.resizer.ResizeTracker} resizeTracker
          */
         me.resizeTracker = Ext.create('Ext.resizer.ResizeTracker', {
             disabled: me.disabled,
@@ -102773,24 +107022,23 @@ Ext.define('Ext.resizer.Resizer', {
     },
 
     /**
-     * <p>Returns the element that was configured with the el or target config property.
-     * If a component was configured with the target property then this will return the
-     * element of this component.<p>
-     * <p>Textarea and img elements will be wrapped with an additional div because
-      * these elements do not support child nodes. The original element can be accessed
-     * through the originalTarget property.</p>
-     * @return {Element} element
+     * Returns the element that was configured with the el or target config property. If a component was configured with
+     * the target property then this will return the element of this component.
+     *
+     * Textarea and img elements will be wrapped with an additional div because these elements do not support child
+     * nodes. The original element can be accessed through the originalTarget property.
+     * @return {Ext.Element} element
      */
     getEl : function() {
         return this.el;
     },
 
     /**
-     * <p>Returns the element or component that was configured with the target config property.<p>
-     * <p>Textarea and img elements will be wrapped with an additional div because
-      * these elements do not support child nodes. The original element can be accessed
-     * through the originalTarget property.</p>
-     * @return {Element/Component}
+     * Returns the element or component that was configured with the target config property.
+     *
+     * Textarea and img elements will be wrapped with an additional div because these elements do not support child
+     * nodes. The original element can be accessed through the originalTarget property.
+     * @return {Ext.Element/Ext.Component}
      */
     getTarget: function() {
         return this.target;
@@ -102839,6 +107087,8 @@ Ext.define('Ext.resizer.ResizeTracker', {
 
     // Default to no constraint
     constrainTo: null,
+    
+    proxyCls:  Ext.baseCSSPrefix + 'resizable-proxy',
 
     constructor: function(config) {
         var me = this;
@@ -102895,15 +107145,45 @@ Ext.define('Ext.resizer.ResizeTracker', {
      * If dynamic is false, this will be a proxy, otherwise it will be our actual target.
      */
     getDynamicTarget: function() {
-        var d = this.target;
-        if (this.dynamic) {
-            return d;
-        } else if (!this.proxy) {
-            this.proxy = d.isComponent ? d.getProxy().addCls(Ext.baseCSSPrefix + 'resizable-proxy') : d.createProxy({tag: 'div', cls: Ext.baseCSSPrefix + 'resizable-proxy', id: d.id + '-rzproxy'}, Ext.getBody());
-            this.proxy.removeCls(Ext.baseCSSPrefix + 'proxy-el');
+        var me = this,
+            target = me.target;
+            
+        if (me.dynamic) {
+            return target;
+        } else if (!me.proxy) {
+            me.proxy = me.createProxy(target);
         }
-        this.proxy.show();
-        return this.proxy;
+        me.proxy.show();
+        return me.proxy;
+    },
+    
+    /**
+     * Create a proxy for this resizer
+     * @param {Ext.Component/Ext.Element} target The target
+     * @return {Ext.Element} A proxy element
+     */
+    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.baseCSSPrefix + 'reset'
+                });
+            }
+            proxy = target.createProxy({
+                tag: 'div',
+                cls: cls,
+                id: target.id + '-rzproxy'
+            }, renderTo);
+        }
+        proxy.removeCls(Ext.baseCSSPrefix + 'proxy-el');
+        return proxy;
     },
 
     onStart: function(e) {
@@ -103179,7 +107459,7 @@ Ext.define('Ext.resizer.SplitterTracker', {
             html: '&#160;'
         });
         overlay.unselectable();
-        overlay.setSize(Ext.core.Element.getViewWidth(true), Ext.core.Element.getViewHeight(true));
+        overlay.setSize(Ext.Element.getViewWidth(true), Ext.Element.getViewHeight(true));
         overlay.show();
         
         // store boxes of previous and next
@@ -103349,23 +107629,22 @@ Ext.define('Ext.resizer.SplitterTracker', {
 /**
  * @class Ext.selection.CellModel
  * @extends Ext.selection.Model
- * @private
  */
 Ext.define('Ext.selection.CellModel', {
     extend: 'Ext.selection.Model',
     alias: 'selection.cellmodel',
     requires: ['Ext.util.KeyNav'],
-    
+
     /**
      * @cfg {Boolean} enableKeyNav
-     * Turns on/off keyboard navigation within the grid. Defaults to true.
+     * Turns on/off keyboard navigation within the grid.
      */
     enableKeyNav: true,
-    
+
     /**
      * @cfg {Boolean} preventWrap
      * Set this configuration to true to prevent wrapping around of selection as
-     * a user navigates to the first or last column. Defaults to false.
+     * a user navigates to the first or last column.
      */
     preventWrap: false,
 
@@ -103380,7 +107659,7 @@ Ext.define('Ext.selection.CellModel', {
              * @param {Number} column The column index deselected
              */
             'deselect',
-            
+
             /**
              * @event select
              * Fired after a cell is selected
@@ -103391,7 +107670,7 @@ Ext.define('Ext.selection.CellModel', {
              */
             'select'
         );
-        this.callParent(arguments);    
+        this.callParent(arguments);
     },
 
     bindComponent: function(view) {
@@ -103414,7 +107693,7 @@ Ext.define('Ext.selection.CellModel', {
 
     initKeyNav: function(view) {
         var me = this;
-        
+
         if (!view.rendered) {
             view.on('render', Ext.Function.bind(me.initKeyNav, me, [view], 0), me, {single: true});
             return;
@@ -103435,7 +107714,7 @@ Ext.define('Ext.selection.CellModel', {
             scope: me
         });
     },
-    
+
     getHeaderCt: function() {
         return this.primaryView.headerCt;
     },
@@ -103451,11 +107730,11 @@ Ext.define('Ext.selection.CellModel', {
     onKeyLeft: function(e, t) {
         this.move('left', e);
     },
-    
+
     onKeyRight: function(e, t) {
         this.move('right', e);
     },
-    
+
     move: function(dir, e) {
         var me = this,
             pos = me.primaryView.walkCells(me.getCurrentPosition(), dir, e, me.preventWrap);
@@ -103471,14 +107750,14 @@ Ext.define('Ext.selection.CellModel', {
     getCurrentPosition: function() {
         return this.position;
     },
-    
+
     /**
      * Sets the current position
      * @param {Object} position The position to set.
      */
     setCurrentPosition: function(pos) {
         var me = this;
-        
+
         if (me.position) {
             me.onCellDeselect(me.position);
         }
@@ -103570,10 +107849,6 @@ Ext.define('Ext.selection.CellModel', {
 /**
  * @class Ext.selection.RowModel
  * @extends Ext.selection.Model
- *
- * Implement row based navigation via keyboard.
- *
- * Must synchronize across grid sections
  */
 Ext.define('Ext.selection.RowModel', {
     extend: 'Ext.selection.Model',
@@ -103590,9 +107865,17 @@ Ext.define('Ext.selection.RowModel', {
     /**
      * @cfg {Boolean} enableKeyNav
      *
-     * Turns on/off keyboard navigation within the grid. Defaults to true.
+     * Turns on/off keyboard navigation within the grid.
      */
     enableKeyNav: true,
+    
+    /**
+     * @cfg {Boolean} [ignoreRightMouseSelection=true]
+     * True to ignore selections that are made when using the right mouse button if there are
+     * records that are already selected. If no records are selected, selection will continue 
+     * as normal
+     */
+    ignoreRightMouseSelection: true,
 
     constructor: function(){
         this.addEvents(
@@ -103600,7 +107883,7 @@ Ext.define('Ext.selection.RowModel', {
              * @event beforedeselect
              * Fired before a record is deselected. If any listener returns false, the
              * deselection is cancelled.
-             * @param {Ext.selection.RowSelectionModel} this
+             * @param {Ext.selection.RowModel} this
              * @param {Ext.data.Model} record The deselected record
              * @param {Number} index The row index deselected
              */
@@ -103610,7 +107893,7 @@ Ext.define('Ext.selection.RowModel', {
              * @event beforeselect
              * Fired before a record is selected. If any listener returns false, the
              * selection is cancelled.
-             * @param {Ext.selection.RowSelectionModel} this
+             * @param {Ext.selection.RowModel} this
              * @param {Ext.data.Model} record The selected record
              * @param {Number} index The row index selected
              */
@@ -103619,7 +107902,7 @@ Ext.define('Ext.selection.RowModel', {
             /**
              * @event deselect
              * Fired after a record is deselected
-             * @param {Ext.selection.RowSelectionModel} this
+             * @param {Ext.selection.RowModel} this
              * @param {Ext.data.Model} record The deselected record
              * @param {Number} index The row index deselected
              */
@@ -103628,7 +107911,7 @@ Ext.define('Ext.selection.RowModel', {
             /**
              * @event select
              * Fired after a record is selected
-             * @param {Ext.selection.RowSelectionModel} this
+             * @param {Ext.selection.RowModel} this
              * @param {Ext.data.Model} record The selected record
              * @param {Number} index The row index selected
              */
@@ -103909,8 +108192,26 @@ Ext.define('Ext.selection.RowModel', {
     // we can take into account ctrlKey, shiftKey, etc
     onRowMouseDown: function(view, record, item, index, e) {
         view.el.focus();
+        if (!this.allowRightMouseSelection(e)) {
+            return;
+        }
         this.selectWithEvent(record, e);
     },
+    
+    /**
+     * Checks whether a selection should proceed based on the ignoreRightMouseSelection
+     * option.
+     * @private
+     * @param {Ext.EventObject} e The event
+     * @return {Boolean} False if the selection should not proceed
+     */
+    allowRightMouseSelection: function(e) {
+        var disallow = this.ignoreRightMouseSelection && e.button !== 0;
+        if (disallow) {
+            disallow = this.hasSelection();
+        }
+        return !disallow;
+    },
 
     // Allow the GridView to update the UI by
     // adding/removing a CSS class from the row.
@@ -104009,40 +108310,72 @@ Ext.define('Ext.selection.CheckboxModel', {
     mode: 'MULTI',
 
     /**
-     * @cfg {Mixed} injectCheckbox
+     * @cfg {Number/Boolean/String} injectCheckbox
      * Instructs the SelectionModel whether or not to inject the checkbox header
      * automatically or not. (Note: By not placing the checkbox in manually, the
      * grid view will need to be rendered 2x on initial render.)
      * Supported values are a Number index, false and the strings 'first' and 'last'.
-     * Default is 0.
      */
     injectCheckbox: 0,
 
     /**
      * @cfg {Boolean} checkOnly <tt>true</tt> if rows can only be selected by clicking on the
-     * checkbox column (defaults to <tt>false</tt>).
+     * checkbox column.
      */
     checkOnly: false,
 
+    headerWidth: 24,
+
     // private
     checkerOnCls: Ext.baseCSSPrefix + 'grid-hd-checker-on',
 
-    bindComponent: function() {
-        this.sortable = false;
-        this.callParent(arguments);
+    bindComponent: function(view) {
+        var me = this;
 
-        var view     = this.views[0],
+        me.sortable = false;
+        me.callParent(arguments);
+        if (!me.hasLockedHeader() || view.headerCt.lockedCt) {
+            // if we have a locked header, only hook up to the first
+            view.headerCt.on('headerclick', me.onHeaderClick, me);
+            me.addCheckbox(true);
+            me.mon(view.ownerCt, 'reconfigure', me.addCheckbox, me);
+        }
+    },
+
+    hasLockedHeader: function(){
+        var hasLocked = false;
+        Ext.each(this.views, function(view){
+            if (view.headerCt.lockedCt) {
+                hasLocked = true;
+                return false;
+            }
+        });
+        return hasLocked;
+    },
+
+    /**
+     * Add the header checkbox to the header row
+     * @private
+     * @param {Boolean} initial True if we're binding for the first time.
+     */
+    addCheckbox: function(initial){
+        var me = this,
+            checkbox = me.injectCheckbox,
+            view = me.views[0],
             headerCt = view.headerCt;
 
-        if (this.injectCheckbox !== false) {
-            if (this.injectCheckbox == 'first') {
-                this.injectCheckbox = 0;
-            } else if (this.injectCheckbox == 'last') {
-                this.injectCheckbox = headerCt.getColumnCount();
+        if (checkbox !== false) {
+            if (checkbox == 'first') {
+                checkbox = 0;
+            } else if (checkbox == 'last') {
+                checkbox = headerCt.getColumnCount();
             }
-            headerCt.add(this.injectCheckbox,  this.getHeaderConfig());
+            headerCt.add(checkbox,  me.getHeaderConfig());
+        }
+
+        if (initial !== true) {
+            view.refresh();
         }
-        headerCt.on('headerclick', this.onHeaderClick, this);
     },
 
     /**
@@ -104087,17 +108420,21 @@ Ext.define('Ext.selection.CheckboxModel', {
      * This should be used when injectCheckbox is set to false.
      */
     getHeaderConfig: function() {
+        var me = this;
+
         return {
             isCheckerHd: true,
             text : '&#160;',
-            width: 24,
+            width: me.headerWidth,
             sortable: false,
-            fixed: true,
+            draggable: false,
+            resizable: false,
             hideable: false,
             menuDisabled: true,
             dataIndex: '',
             cls: Ext.baseCSSPrefix + 'column-header-checkbox ',
-            renderer: Ext.Function.bind(this.renderer, this)
+            renderer: Ext.Function.bind(me.renderer, me),
+            locked: me.hasLockedHeader()
         };
     },
 
@@ -104116,6 +108453,10 @@ Ext.define('Ext.selection.CheckboxModel', {
         view.el.focus();
         var me = this,
             checker = e.getTarget('.' + Ext.baseCSSPrefix + 'grid-row-checker');
+            
+        if (!me.allowRightMouseSelection(e)) {
+            return;
+        }
 
         // checkOnly set, but we didn't click on a checker.
         if (me.checkOnly && !checker) {
@@ -104215,16 +108556,15 @@ Ext.define('Ext.selection.TreeModel', {
     },
     
     onKeyPress: function(e, t) {
-        var selected, checked;
+        var key = e.getKey(),
+            selected, 
+            checked;
         
-        if (e.getKey() === e.SPACE || e.getKey() === e.ENTER) {
+        if (key === e.SPACE || key === e.ENTER) {
             e.stopEvent();
             selected = this.getLastSelected();
-            if (selected && selected.isLeaf()) {
-                checked = selected.get('checked');
-                if (Ext.isBoolean(checked)) {
-                    selected.set('checked', !checked);
-                }
+            if (selected) {
+                this.view.onCheckChange(selected);
             }
         } else {
             this.callParent(arguments);
@@ -104237,30 +108577,31 @@ Ext.define('Ext.selection.TreeModel', {
  * @extends Ext.Base
  * @private
  * Represents a single thumb element on a Slider. This would not usually be created manually and would instead
- * be created internally by an {@link Ext.slider.Multi Ext.Slider}.
+ * be created internally by an {@link Ext.slider.Multi Multi slider}.
  */
 Ext.define('Ext.slider.Thumb', {
     requires: ['Ext.dd.DragTracker', 'Ext.util.Format'],
     /**
      * @private
-     * @property topThumbZIndex
-     * @type Number
+     * @property {Number} topThumbZIndex
      * The number used internally to set the z index of the top thumb (see promoteThumb for details)
      */
     topZIndex: 10000,
+
     /**
-     * @cfg {Ext.slider.MultiSlider} slider The Slider to render to (required)
+     * @cfg {Ext.slider.MultiSlider} slider (required)
+     * The Slider to render to.
      */
+
     /**
      * Creates new slider thumb.
      * @param {Object} config (optional) Config object.
      */
     constructor: function(config) {
         var me = this;
-        
+
         /**
-         * @property slider
-         * @type Ext.slider.MultiSlider
+         * @property {Ext.slider.MultiSlider} slider
          * The slider this thumb is contained within
          */
         Ext.apply(me, config || {}, {
@@ -104283,14 +108624,14 @@ Ext.define('Ext.slider.Thumb', {
      */
     render: function() {
         var me = this;
-        
+
         me.el = me.slider.innerEl.insertFirst({cls: me.cls});
         if (me.disabled) {
             me.disable();
         }
         me.initEvents();
     },
-    
+
     /**
      * @private
      * move the thumb
@@ -104316,7 +108657,7 @@ Ext.define('Ext.slider.Thumb', {
     bringToFront: function() {
         this.el.setStyle('zIndex', this.topZIndex);
     },
-    
+
     /**
      * @private
      * Send thumb dom element to back.
@@ -104324,13 +108665,13 @@ Ext.define('Ext.slider.Thumb', {
     sendToBack: function() {
         this.el.setStyle('zIndex', '');
     },
-    
+
     /**
      * Enables the thumb if it is currently disabled
      */
     enable: function() {
         var me = this;
-        
+
         me.disabled = false;
         if (me.el) {
             me.el.removeCls(me.slider.disabledCls);
@@ -104342,7 +108683,7 @@ Ext.define('Ext.slider.Thumb', {
      */
     disable: function() {
         var me = this;
-        
+
         me.disabled = true;
         if (me.el) {
             me.el.addCls(me.slider.disabledCls);
@@ -104391,7 +108732,7 @@ Ext.define('Ext.slider.Thumb', {
      */
     onDragStart: function(e){
         var me = this;
-        
+
         me.el.addCls(Ext.baseCSSPrefix + 'slider-thumb-drag');
         me.dragging = true;
         me.dragStartValue = me.value;
@@ -104419,7 +108760,7 @@ Ext.define('Ext.slider.Thumb', {
             if (below !== undefined && newValue <= below.value) {
                 newValue = below.value;
             }
-            
+
             if (above !== undefined && newValue >= above.value) {
                 newValue = above.value;
             }
@@ -104488,46 +108829,44 @@ Ext.define('Ext.slider.Thumb', {
 });
 
 /**
- * @class Ext.slider.Tip
- * @extends Ext.tip.Tip
- * Simple plugin for using an Ext.tip.Tip with a slider to show the slider value. In general this
- * class is not created directly, instead pass the {@link Ext.slider.Multi#useTips} and 
- * {@link Ext.slider.Multi#tipText} configuration options to the slider directly.
- * {@img Ext.slider.Tip/Ext.slider.Tip1.png Ext.slider.Tip component}
- * Example usage:
-<pre>
-    Ext.create('Ext.slider.Single', {
-        width: 214,
-        minValue: 0,
-        maxValue: 100,
-        useTips: true,
-        renderTo: Ext.getBody()
-    });   
-</pre>
+ * Simple plugin for using an Ext.tip.Tip with a slider to show the slider value. In general this class is not created
+ * directly, instead pass the {@link Ext.slider.Multi#useTips} and {@link Ext.slider.Multi#tipText} configuration
+ * options to the slider directly.
+ *
+ *     @example
+ *     Ext.create('Ext.slider.Single', {
+ *         width: 214,
+ *         minValue: 0,
+ *         maxValue: 100,
+ *         useTips: true,
+ *         renderTo: Ext.getBody()
+ *     });
+ *
  * Optionally provide your own tip text by passing tipText:
- <pre>
- new Ext.slider.Single({
-     width: 214,
-     minValue: 0,
-     maxValue: 100,
-     useTips: true,
-     tipText: function(thumb){
-         return Ext.String.format('<b>{0}% complete</b>', thumb.value);
-     }
- });
- </pre>
+ *
+ *     @example
+ *     Ext.create('Ext.slider.Single', {
+ *         width: 214,
+ *         minValue: 0,
+ *         maxValue: 100,
+ *         useTips: true,
+ *         tipText: function(thumb){
+ *             return Ext.String.format('**{0}% complete**', thumb.value);
+ *         },
+ *         renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.slider.Tip', {
     extend: 'Ext.tip.Tip',
     minWidth: 10,
     alias: 'widget.slidertip',
     offsets : [0, -10],
-    
+
     isSliderTip: true,
 
     init: function(slider) {
         var me = this;
-        
+
         slider.on({
             scope    : me,
             dragstart: me.onSlide,
@@ -104538,7 +108877,7 @@ Ext.define('Ext.slider.Tip', {
     },
     /**
      * @private
-     * Called whenever a dragstart or drag event is received on the associated Thumb. 
+     * Called whenever a dragstart or drag event is received on the associated Thumb.
      * Aligns the Tip with the Thumb's new position.
      * @param {Ext.slider.MultiSlider} slider The slider
      * @param {Ext.EventObject} e The Event object
@@ -104553,8 +108892,8 @@ Ext.define('Ext.slider.Tip', {
     },
 
     /**
-     * Used to create the text that appears in the Tip's body. By default this just returns
-     * the value of the Slider Thumb that the Tip is attached to. Override to customize.
+     * Used to create the text that appears in the Tip's body. By default this just returns the value of the Slider
+     * Thumb that the Tip is attached to. Override to customize.
      * @param {Ext.slider.Thumb} thumb The Thumb that the Tip is attached to
      * @return {String} The text to display in the tip
      */
@@ -104563,26 +108902,23 @@ Ext.define('Ext.slider.Tip', {
     }
 });
 /**
- * @class Ext.slider.Multi
- * @extends Ext.form.field.Base
- * <p>Slider which supports vertical or horizontal orientation, keyboard adjustments, configurable snapping, axis
- * clicking and animation. Can be added as an item to any container. In addition,
- * {@img Ext.slider.Multi/Ext.slider.Multi.png Ext.slider.Multi component}
- * <p>Example usage:</p>
+ * Slider which supports vertical or horizontal orientation, keyboard adjustments, configurable snapping, axis clicking
+ * and animation. Can be added as an item to any container.
+ *
  * Sliders can be created with more than one thumb handle by passing an array of values instead of a single one:
-<pre>
-    Ext.create('Ext.slider.Multi', {
-        width: 200,
       values: [25, 50, 75],
       increment: 5,
       minValue: 0,
       maxValue: 100,
-
-        //this defaults to true, setting to false allows the thumbs to pass each other
-        {@link #constrainThumbs}: false,
-        renderTo: Ext.getBody()
-    });
-</pre>
+ *
+ *     @example
+ *     Ext.create('Ext.slider.Multi', {
*         width: 200,
*         values: [25, 50, 75],
*         increment: 5,
*         minValue: 0,
+ *         maxValue: 100,
+ *
+ *         // this defaults to true, setting to false allows the thumbs to pass each other
+ *         constrainThumbs: false,
+ *         renderTo: Ext.getBody()
+ *     });
  */
 Ext.define('Ext.slider.Multi', {
     extend: 'Ext.form.field.Base',
@@ -104598,11 +108934,12 @@ Ext.define('Ext.slider.Multi', {
         'Ext.layout.component.field.Slider'
     ],
 
+    // note: {id} here is really {inputId}, but {cmpId} is available
     fieldSubTpl: [
-        '<div class="' + Ext.baseCSSPrefix + 'slider {fieldCls} {vertical}" aria-valuemin="{minValue}" aria-valuemax="{maxValue}" aria-valuenow="{value}" aria-valuetext="{value}">',
-            '<div class="' + Ext.baseCSSPrefix + 'slider-end" role="presentation">',
-                '<div class="' + Ext.baseCSSPrefix + 'slider-inner" role="presentation">',
-                    '<a class="' + Ext.baseCSSPrefix + 'slider-focus" href="#" tabIndex="-1" hidefocus="on" role="presentation"></a>',
+        '<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">',
+                    '<a id="{cmpId}-focusEl" class="' + Ext.baseCSSPrefix + 'slider-focus" href="#" tabIndex="-1" hidefocus="on" role="presentation"></a>',
                 '</div>',
             '</div>',
         '</div>',
@@ -104614,48 +108951,57 @@ Ext.define('Ext.slider.Multi', {
 
     /**
      * @cfg {Number} value
-     * A value with which to initialize the slider. Defaults to minValue. Setting this will only
-     * result in the creation of a single slider thumb; if you want multiple thumbs then use the
-     * {@link #values} config instead.
+     * A value with which to initialize the slider. Defaults to minValue. Setting this will only result in the creation
+     * of a single slider thumb; if you want multiple thumbs then use the {@link #values} config instead.
      */
 
     /**
-     * @cfg {Array} values
-     * Array of Number values with which to initalize the slider. A separate slider thumb will be created for
-     * each value in this array. This will take precedence over the single {@link #value} config.
+     * @cfg {Number[]} values
+     * Array of Number values with which to initalize the slider. A separate slider thumb will be created for each value
+     * in this array. This will take precedence over the single {@link #value} config.
      */
 
     /**
-     * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
+     * @cfg {Boolean} vertical
+     * Orient the Slider vertically rather than horizontally.
      */
     vertical: false,
+
     /**
-     * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
+     * @cfg {Number} minValue
+     * The minimum value for the Slider.
      */
     minValue: 0,
+
     /**
-     * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
+     * @cfg {Number} maxValue
+     * The maximum value for the Slider.
      */
     maxValue: 100,
+
     /**
-     * @cfg {Number/Boolean} decimalPrecision.
-     * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
-     * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
+     * @cfg {Number/Boolean} decimalPrecision The number of decimal places to which to round the Slider's value.
+     *
+     * To disable rounding, configure as **false**.
      */
     decimalPrecision: 0,
+
     /**
-     * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead.
+     * @cfg {Number} keyIncrement
+     * How many units to change the Slider when adjusting with keyboard navigation. If the increment
+     * config is larger, it will be used instead.
      */
     keyIncrement: 1,
+
     /**
-     * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
+     * @cfg {Number} increment
+     * How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
      */
     increment: 0,
 
     /**
      * @private
-     * @property clickRange
-     * @type Array
+     * @property {Number[]} clickRange
      * Determines whether or not a click to the slider component is considered to be a user request to change the value. Specified as an array of [top, bottom],
      * the click event's 'top' property is compared to these numbers and the click only considered a change request if it falls within them. e.g. if the 'top'
      * value of the click event is 4 or 16, the click is not considered a change request as it falls outside of the [5, 15] range
@@ -104663,22 +109009,26 @@ Ext.define('Ext.slider.Multi', {
     clickRange: [5,15],
 
     /**
-     * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
+     * @cfg {Boolean} clickToChange
+     * Determines whether or not clicking on the Slider axis will change the slider.
      */
     clickToChange : true,
+
     /**
-     * @cfg {Boolean} animate Turn on or off animation. Defaults to true
+     * @cfg {Boolean} animate
+     * Turn on or off animation.
      */
     animate: true,
 
     /**
+     * @property {Boolean} dragging
      * True while the thumb is in a drag operation
-     * @type Boolean
      */
     dragging: false,
 
     /**
-     * @cfg {Boolean} constrainThumbs True to disallow thumbs from overlapping one another. Defaults to true
+     * @cfg {Boolean} constrainThumbs
+     * True to disallow thumbs from overlapping one another.
      */
     constrainThumbs: true,
 
@@ -104686,14 +109036,14 @@ Ext.define('Ext.slider.Multi', {
 
     /**
      * @cfg {Boolean} useTips
-     * True to use an Ext.slider.Tip to display tips for the value. Defaults to <tt>true</tt>.
+     * True to use an Ext.slider.Tip to display tips for the value.
      */
     useTips : true,
 
     /**
      * @cfg {Function} tipText
-     * A function used to display custom text for the slider tip. Defaults to <tt>null</tt>, which will
-     * use the default on the plugin.
+     * A function used to display custom text for the slider tip. Defaults to null, which will use the default on the
+     * plugin.
      */
     tipText : null,
 
@@ -104724,8 +109074,7 @@ Ext.define('Ext.slider.Multi', {
             hasTip;
 
         /**
-         * @property thumbs
-         * @type Array
+         * @property {Array} thumbs
          * Array containing references to each thumb
          */
         me.thumbs = [];
@@ -104735,8 +109084,8 @@ Ext.define('Ext.slider.Multi', {
         me.addEvents(
             /**
              * @event beforechange
-             * Fires before the slider value is changed. By returning false from an event handler,
-             * you can cancel the event and prevent the slider from changing.
+             * Fires before the slider value is changed. By returning false from an event handler, you can cancel the
+             * event and prevent the slider from changing.
              * @param {Ext.slider.Multi} slider The slider
              * @param {Number} newValue The new value which the slider is being changed to.
              * @param {Number} oldValue The old value which the slider was previously.
@@ -104870,11 +109219,7 @@ Ext.define('Ext.slider.Multi', {
             value: me.value
         });
 
-        Ext.applyIf(me.renderSelectors, {
-            endEl: '.' + Ext.baseCSSPrefix + 'slider-end',
-            innerEl: '.' + Ext.baseCSSPrefix + 'slider-inner',
-            focusEl: '.' + Ext.baseCSSPrefix + 'slider-focus'
-        });
+        me.addChildEls('endEl', 'innerEl', 'focusEl');
 
         me.callParent(arguments);
 
@@ -105095,8 +109440,8 @@ Ext.define('Ext.slider.Multi', {
     },
 
     /**
-     * Sets the minimum value for the slider instance. If the current value is less than the
-     * minimum value, the current value will be changed.
+     * Sets the minimum value for the slider instance. If the current value is less than the minimum value, the current
+     * value will be changed.
      * @param {Number} val The new minimum value
      */
     setMinValue : function(val) {
@@ -105107,7 +109452,9 @@ Ext.define('Ext.slider.Multi', {
             t;
 
         me.minValue = val;
-        me.inputEl.dom.setAttribute('aria-valuemin', val);
+        if (me.rendered) {
+            me.inputEl.dom.setAttribute('aria-valuemin', val);
+        }
 
         for (; i < len; ++i) {
             t = thumbs[i];
@@ -105117,8 +109464,8 @@ Ext.define('Ext.slider.Multi', {
     },
 
     /**
-     * Sets the maximum value for the slider instance. If the current value is more than the
-     * maximum value, the current value will be changed.
+     * Sets the maximum value for the slider instance. If the current value is more than the maximum value, the current
+     * value will be changed.
      * @param {Number} val The new maximum value
      */
     setMaxValue : function(val) {
@@ -105129,7 +109476,9 @@ Ext.define('Ext.slider.Multi', {
             t;
 
         me.maxValue = val;
-        me.inputEl.dom.setAttribute('aria-valuemax', val);
+        if (me.rendered) {
+            me.inputEl.dom.setAttribute('aria-valuemax', val);
+        }
 
         for (; i < len; ++i) {
             t = thumbs[i];
@@ -105139,11 +109488,11 @@ Ext.define('Ext.slider.Multi', {
     },
 
     /**
-     * Programmatically sets the value of the Slider. Ensures that the value is constrained within
-     * the minValue and maxValue.
+     * Programmatically sets the value of the Slider. Ensures that the value is constrained within the minValue and
+     * maxValue.
      * @param {Number} index Index of the thumb to move
      * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
-     * @param {Boolean} animate Turn on or off animation, defaults to true
+     * @param {Boolean} [animate=true] Turn on or off animation
      */
     setValue : function(index, value, animate, changeComplete) {
         var me = this,
@@ -105264,10 +109613,9 @@ Ext.define('Ext.slider.Multi', {
     },
 
     /**
-     * Synchronizes thumbs position to the proper proportion of the total component width based
-     * on the current slider {@link #value}.  This will be called automatically when the Slider
-     * is resized by a layout, but if it is rendered auto width, this method can be called from
-     * another resize handler to sync the Slider if necessary.
+     * Synchronizes thumbs position to the proper proportion of the total component width based on the current slider
+     * {@link #value}. This will be called automatically when the Slider is resized by a layout, but if it is rendered
+     * auto width, this method can be called from another resize handler to sync the Slider if necessary.
      */
     syncThumbs : function() {
         if (this.rendered) {
@@ -105284,8 +109632,8 @@ Ext.define('Ext.slider.Multi', {
     /**
      * Returns the current value of the slider
      * @param {Number} index The index of the thumb to return a value for
-     * @return {Number/Array} The current value of the slider at the given index, or an array of
-     * all thumb values if no index is given.
+     * @return {Number/Number[]} The current value of the slider at the given index, or an array of all thumb values if
+     * no index is given.
      */
     getValue : function(index) {
         return Ext.isNumber(index) ? this.thumbs[index].value : this.getValues();
@@ -105293,7 +109641,7 @@ Ext.define('Ext.slider.Multi', {
 
     /**
      * Returns an array of values - one for the location of each thumb
-     * @return {Array} The set of thumb values
+     * @return {Number[]} The set of thumb values
      */
     getValues: function() {
         var values = [],
@@ -105328,7 +109676,7 @@ Ext.define('Ext.slider.Multi', {
     beforeDestroy : function() {
         var me = this;
 
-        Ext.destroyMembers(me.innerEl, me.endEl, me.focusEl);
+        Ext.destroy(me.innerEl, me.endEl, me.focusEl);
         Ext.each(me.thumbs, function(thumb) {
             Ext.destroy(thumb);
         }, me);
@@ -105364,23 +109712,19 @@ Ext.define('Ext.slider.Multi', {
 });
 
 /**
- * @class Ext.slider.Single
- * @extends Ext.slider.Multi
- * Slider which supports vertical or horizontal orientation, keyboard adjustments,
- * configurable snapping, axis clicking and animation. Can be added as an item to
- * any container. 
- * {@img Ext.slider.Single/Ext.slider.Single.png Ext.slider.Single component}
- * Example usage:
-<pre><code>
-    Ext.create('Ext.slider.Single', {
-        width: 200,
-        value: 50,
-        increment: 10,
-        minValue: 0,
-        maxValue: 100,
-        renderTo: Ext.getBody()
-    });
-</code></pre>
+ * Slider which supports vertical or horizontal orientation, keyboard adjustments, configurable snapping, axis clicking
+ * and animation. Can be added as an item to any container.
+ *
+ *     @example
+ *     Ext.create('Ext.slider.Single', {
+ *         width: 200,
+ *         value: 50,
+ *         increment: 10,
+ *         minValue: 0,
+ *         maxValue: 100,
+ *         renderTo: Ext.getBody()
+ *     });
+ *
  * The class Ext.slider.Single is aliased to Ext.Slider for backwards compatibility.
  */
 Ext.define('Ext.slider.Single', {
@@ -105393,23 +109737,23 @@ Ext.define('Ext.slider.Single', {
      * @return {Number} The current value of the slider
      */
     getValue: function() {
-        //just returns the value of the first thumb, which should be the only one in a single slider
+        // just returns the value of the first thumb, which should be the only one in a single slider
         return this.callParent([0]);
     },
 
     /**
-     * Programmatically sets the value of the Slider. Ensures that the value is constrained within
-     * the minValue and maxValue.
+     * Programmatically sets the value of the Slider. Ensures that the value is constrained within the minValue and
+     * maxValue.
      * @param {Number} value The value to set the slider to. (This will be constrained within minValue and maxValue)
-     * @param {Boolean} animate Turn on or off animation, defaults to true
+     * @param {Boolean} [animate] Turn on or off animation
      */
     setValue: function(value, animate) {
         var args = Ext.toArray(arguments),
             len  = args.length;
 
-        //this is to maintain backwards compatiblity for sliders with only one thunb. Usually you must pass the thumb
-        //index to setValue, but if we only have one thumb we inject the index here first if given the multi-slider
-        //signature without the required index. The index will always be 0 for a single slider
+        // this is to maintain backwards compatiblity for sliders with only one thunb. Usually you must pass the thumb
+        // index to setValue, but if we only have one thumb we inject the index here first if given the multi-slider
+        // signature without the required index. The index will always be 0 for a single slider
         if (len == 1 || (len <= 3 && typeof arguments[1] != 'number')) {
             args.unshift(0);
         }
@@ -105428,15 +109772,15 @@ Ext.define('Ext.slider.Single', {
  * @author Ed Spencer
  * @class Ext.tab.Tab
  * @extends Ext.button.Button
- * 
- * <p>Represents a single Tab in a {@link Ext.tab.Panel TabPanel}. A Tab is simply a slightly customized {@link Ext.button.Button Button}, 
- * styled to look like a tab. Tabs are optionally closable, and can also be disabled. 99% of the time you will not
+ *
+ * <p>Represents a single Tab in a {@link Ext.tab.Panel TabPanel}. A Tab is simply a slightly customized {@link Ext.button.Button Button},
+ * styled to look like a tab. Tabs are optionally closable, and can also be disabled. Typically you will not
  * need to create Tabs manually as the framework does so automatically when you use a {@link Ext.tab.Panel TabPanel}</p>
  */
 Ext.define('Ext.tab.Tab', {
     extend: 'Ext.button.Button',
     alias: 'widget.tab',
-    
+
     requires: [
         'Ext.layout.component.Tab',
         'Ext.util.KeyNav'
@@ -105450,14 +109794,14 @@ Ext.define('Ext.tab.Tab', {
 
     /**
      * @cfg {String} activeCls
-     * The CSS class to be applied to a Tab when it is active. Defaults to 'x-tab-active'.
+     * The CSS class to be applied to a Tab when it is active.
      * Providing your own CSS for this class enables you to customize the active state.
      */
     activeCls: 'active',
-    
+
     /**
      * @cfg {String} disabledCls
-     * The CSS class to be applied to a Tab when it is disabled. Defaults to 'x-tab-disabled'.
+     * The CSS class to be applied to a Tab when it is disabled.
      */
 
     /**
@@ -105467,19 +109811,18 @@ Ext.define('Ext.tab.Tab', {
     closableCls: 'closable',
 
     /**
-     * @cfg {Boolean} closable True to make the Tab start closable (the close icon will be visible). Defaults to true
+     * @cfg {Boolean} closable True to make the Tab start closable (the close icon will be visible).
      */
     closable: true,
 
     /**
-     * @cfg {String} closeText 
+     * @cfg {String} closeText
      * The accessible text label for the close button link; only used when {@link #closable} = true.
-     * Defaults to 'Close Tab'.
      */
     closeText: 'Close Tab',
 
     /**
-     * @property Boolean
+     * @property {Boolean} active
      * Read-only property indicating that this tab is currently active. This is NOT a public configuration.
      */
     active: false,
@@ -105493,19 +109836,21 @@ Ext.define('Ext.tab.Tab', {
     scale: false,
 
     position: 'top',
-    
+
     initComponent: function() {
         var me = this;
 
         me.addEvents(
             /**
              * @event activate
+             * Fired when the tab is activated.
              * @param {Ext.tab.Tab} this
              */
             'activate',
 
             /**
              * @event deactivate
+             * Fired when the tab is deactivated.
              * @param {Ext.tab.Tab} this
              */
             'deactivate',
@@ -105519,13 +109864,13 @@ Ext.define('Ext.tab.Tab', {
             'beforeclose',
 
             /**
-             * @event beforeclose
+             * @event close
              * Fires to indicate that the tab is to be closed, usually because the user has clicked the close button.
              * @param {Ext.tab.Tab} tab The Tab object
              */
             'close'
         );
-        
+
         me.callParent(arguments);
 
         if (me.card) {
@@ -105537,36 +109882,55 @@ Ext.define('Ext.tab.Tab', {
      * @ignore
      */
     onRender: function() {
-        var me = this;
-        
+        var me = this,
+            tabBar = me.up('tabbar'),
+            tabPanel = me.up('tabpanel');
+
         me.addClsWithUI(me.position);
-        
+
         // Set all the state classNames, as they need to include the UI
         // me.disabledCls = me.getClsWithUIs('disabled');
 
         me.syncClosableUI();
 
+        // Propagate minTabWidth and maxTabWidth settings from the owning TabBar then TabPanel
+        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;
+            }
+        }
+
         me.callParent(arguments);
-        
+
         if (me.active) {
             me.activate(true);
         }
 
         me.syncClosableElements();
-        
+
         me.keyNav = Ext.create('Ext.util.KeyNav', me.el, {
             enter: me.onEnterKey,
             del: me.onDeleteKey,
             scope: me
         });
     },
-    
+
     // inherit docs
     enable : function(silent) {
         var me = this;
 
         me.callParent(arguments);
-        
+
         me.removeClsWithUI(me.position + '-disabled');
 
         return me;
@@ -105575,14 +109939,14 @@ Ext.define('Ext.tab.Tab', {
     // inherit docs
     disable : function(silent) {
         var me = this;
-        
+
         me.callParent(arguments);
-        
+
         me.addClsWithUI(me.position + '-disabled');
 
         return me;
     },
-    
+
     /**
      * @ignore
      */
@@ -105706,7 +110070,7 @@ Ext.define('Ext.tab.Tab', {
             }
         }
     },
-    
+
     /**
      * Fires the close event on the tab.
      * @private
@@ -105714,33 +110078,33 @@ Ext.define('Ext.tab.Tab', {
     fireClose: function(){
         this.fireEvent('close', this);
     },
-    
+
     /**
      * @private
      */
     onEnterKey: function(e) {
         var me = this;
-        
+
         if (me.tabBar) {
             me.tabBar.onClick(e, me.el);
         }
     },
-    
+
    /**
      * @private
      */
     onDeleteKey: function(e) {
         var me = this;
-        
+
         if (me.closable) {
             me.onCloseClick();
         }
     },
-    
+
     // @private
     activate : function(supressEvent) {
         var me = this;
-        
+
         me.active = true;
         me.addClsWithUI([me.activeCls, me.position + '-' + me.activeCls]);
 
@@ -105752,10 +110116,10 @@ Ext.define('Ext.tab.Tab', {
     // @private
     deactivate : function(supressEvent) {
         var me = this;
-        
+
         me.active = false;
         me.removeClsWithUI([me.activeCls, me.position + '-' + me.activeCls]);
-        
+
         if (supressEvent !== true) {
             me.fireEvent('deactivate', me);
         }
@@ -105764,9 +110128,8 @@ Ext.define('Ext.tab.Tab', {
 
 /**
  * @author Ed Spencer
- * @class Ext.tab.Bar
- * @extends Ext.panel.Header
- * <p>TabBar is used internally by a {@link Ext.tab.Panel TabPanel} and wouldn't usually need to be created manually.</p>
+ * TabBar is used internally by a {@link Ext.tab.Panel TabPanel} and typically should not need to be created manually.
+ * The tab bar automatically removes the default title provided by {@link Ext.panel.Header}
  */
 Ext.define('Ext.tab.Bar', {
     extend: 'Ext.panel.Header',
@@ -105778,30 +110141,42 @@ Ext.define('Ext.tab.Bar', {
         'Ext.FocusManager'
     ],
 
+    isTabBar: true,
+    
+    /**
+     * @cfg {String} title @hide
+     */
+    
+    /**
+     * @cfg {String} iconCls @hide
+     */
+
     // @private
     defaultType: 'tab',
 
     /**
-     * @cfg Boolean plain
+     * @cfg {Boolean} plain
      * True to not show the full background on the tabbar
      */
     plain: false,
 
     // @private
     renderTpl: [
-        '<div class="{baseCls}-body<tpl if="ui"> {baseCls}-body-{ui}<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>',
-        '<div class="{baseCls}-strip<tpl if="ui"> {baseCls}-strip-{ui}<tpl for="uiCls"> {parent.baseCls}-strip-{parent.ui}-{.}</tpl></tpl>"></div>'
+        '<div id="{id}-body" class="{baseCls}-body <tpl if="bodyCls"> {bodyCls}</tpl> <tpl if="ui"> {baseCls}-body-{ui}<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></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>'
     ],
 
     /**
-     * @cfg {Number} minTabWidth The minimum width for each tab. Defaults to <tt>30</tt>.
+     * @cfg {Number} minTabWidth
+     * The minimum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#minTabWidth minTabWidth} value.
+     * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#minTabWidth minTabWidth} config on the TabPanel.
      */
-    minTabWidth: 30,
 
     /**
-     * @cfg {Number} maxTabWidth The maximum width for each tab. Defaults to <tt>undefined</tt>.
+     * @cfg {Number} maxTabWidth
+     * The maximum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#maxTabWidth maxTabWidth} value.
+     * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#maxTabWidth maxTabWidth} config on the TabPanel.
      */
-    maxTabWidth: undefined,
 
     // @private
     initComponent: function() {
@@ -105811,7 +110186,7 @@ Ext.define('Ext.tab.Bar', {
         if (me.plain) {
             me.setUI(me.ui + '-plain');
         }
-        
+
         me.addClsWithUI(me.dock);
 
         me.addEvents(
@@ -105819,46 +110194,49 @@ Ext.define('Ext.tab.Bar', {
              * @event change
              * Fired when the currently-active tab has changed
              * @param {Ext.tab.Bar} tabBar The TabBar
-             * @param {Ext.Tab} tab The new Tab
+             * @param {Ext.tab.Tab} tab The new Tab
              * @param {Ext.Component} card The card that was just shown in the TabPanel
              */
             'change'
         );
 
-        Ext.applyIf(me.renderSelectors, {
-            body : '.' + me.baseCls + '-body',
-            strip: '.' + me.baseCls + '-strip'
-        });
+        me.addChildEls('body', 'strip');
         me.callParent(arguments);
 
         // TabBar must override the Header's align setting.
         me.layout.align = (me.orientation == 'vertical') ? 'left' : 'top';
         me.layout.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.Scroller', me.layout);
-        me.items.removeAt(me.items.getCount() - 1);
-        me.items.removeAt(me.items.getCount() - 1);
-        
+
+        me.remove(me.titleCmp);
+        delete me.titleCmp;
+
         // Subscribe to Ext.FocusManager for key navigation
         keys = me.orientation == 'vertical' ? ['up', 'down'] : ['left', 'right'];
         Ext.FocusManager.subscribe(me, {
             keys: keys
         });
+
+        Ext.apply(me.renderData, {
+            bodyCls: me.bodyCls
+        });
     },
 
     // @private
     onAdd: function(tab) {
-        var me = this,
-            tabPanel = me.tabPanel,
-            hasOwner = !!tabPanel;
-
-        me.callParent(arguments);
-        tab.position = me.dock;
-        if (hasOwner) {
-            tab.minWidth = tabPanel.minTabWidth;
+        tab.position = this.dock;
+        this.callParent(arguments);
+    },
+    
+    onRemove: function(tab) {
+        var me = this;
+        
+        if (tab === me.previousTab) {
+            me.previousTab = null;
         }
-        else {
-            tab.minWidth = me.minTabWidth + (tab.iconCls ? 25 : 0);
+        if (me.items.getCount() === 0) {
+            me.activeTab = null;
         }
-        tab.maxWidth = me.maxTabWidth || (hasOwner ? tabPanel.maxTabWidth : undefined);
+        me.callParent(arguments);    
     },
 
     // @private
@@ -105871,12 +110249,12 @@ Ext.define('Ext.tab.Bar', {
             delegate: '.' + Ext.baseCSSPrefix + 'tab'
         });
         me.callParent(arguments);
-        
+
     },
 
     afterComponentLayout : function() {
         var me = this;
-        
+
         me.callParent(arguments);
         me.strip.setWidth(me.el.getWidth());
     },
@@ -105885,8 +110263,7 @@ Ext.define('Ext.tab.Bar', {
     onClick: function(e, target) {
         // The target might not be a valid tab el.
         var tab = Ext.getCmp(target.id),
-            tabPanel = this.tabPanel,
-            allowActive = true;
+            tabPanel = this.tabPanel;
 
         target = e.getTarget();
 
@@ -105908,20 +110285,20 @@ Ext.define('Ext.tab.Bar', {
     /**
      * @private
      * Closes the given tab by removing it from the TabBar and removing the corresponding card from the TabPanel
-     * @param {Ext.Tab} tab The tab to close
+     * @param {Ext.tab.Tab} tab The tab to close
      */
     closeTab: function(tab) {
         var me = this,
             card = tab.card,
             tabPanel = me.tabPanel,
             nextTab;
-            
+
         if (card && card.fireEvent('beforeclose', card) === false) {
             return false;
         }
 
         if (tab.active && me.items.getCount() > 1) {
-            nextTab = tab.next('tab') || me.items.items[0];
+            nextTab = me.previousTab || tab.next('tab') || me.items.first();
             me.setActiveTab(nextTab);
             if (tabPanel) {
                 tabPanel.setActiveTab(nextTab.card);
@@ -105939,7 +110316,7 @@ Ext.define('Ext.tab.Bar', {
             card.fireEvent('close', card);
             tabPanel.remove(card);
         }
-        
+
         if (nextTab) {
             nextTab.focus();
         }
@@ -105948,7 +110325,7 @@ Ext.define('Ext.tab.Bar', {
     /**
      * @private
      * Marks the given tab as active
-     * @param {Ext.Tab} tab The tab to mark active
+     * @param {Ext.tab.Tab} tab The tab to mark active
      */
     setActiveTab: function(tab) {
         if (tab.disabled) {
@@ -105956,297 +110333,297 @@ Ext.define('Ext.tab.Bar', {
         }
         var me = this;
         if (me.activeTab) {
+            me.previousTab = me.activeTab;
             me.activeTab.deactivate();
         }
         tab.activate();
-        
+
         if (me.rendered) {
             me.layout.layout();
-            tab.el.scrollIntoView(me.layout.getRenderTarget());
+            tab.el && tab.el.scrollIntoView(me.layout.getRenderTarget());
         }
         me.activeTab = tab;
         me.fireEvent('change', me, tab, tab.card);
     }
 });
+
 /**
  * @author Ed Spencer, Tommy Maintz, Brian Moeskau
- * @class Ext.tab.Panel
- * @extends Ext.panel.Panel
-
-A basic tab container. TabPanels can be used exactly like a standard {@link Ext.panel.Panel} for layout purposes, but also 
-have special support for containing child Components (`{@link Ext.container.Container#items items}`) that are managed 
-using a {@link Ext.layout.container.Card CardLayout layout manager}, and displayed as separate tabs.
-
-__Note:__
-
-By default, a tab's close tool _destroys_ the child tab Component and all its descendants. This makes the child tab 
-Component, and all its descendants __unusable__. To enable re-use of a tab, configure the TabPanel with `{@link #autoDestroy autoDestroy: false}`.
-
-__TabPanel's layout:__
-
-TabPanels use a Dock layout to position the {@link Ext.tab.Bar TabBar} at the top of the widget. Panels added to the TabPanel will have their 
-header hidden by default because the Tab will automatically take the Panel's configured title and icon.
-
-TabPanels use their {@link Ext.panel.Panel#header header} or {@link Ext.panel.Panel#footer footer} element (depending on the {@link #tabPosition} 
-configuration) to accommodate the tab selector buttons. This means that a TabPanel will not display any configured title, and will not display any 
-configured header {@link Ext.panel.Panel#tools tools}.
-
-To display a header, embed the TabPanel in a {@link Ext.panel.Panel Panel} which uses `{@link Ext.container.Container#layout layout:'fit'}`.
-
-__Controlling tabs:__
-Configuration options for the {@link Ext.tab.Tab} that represents the component can be passed in by specifying the tabConfig option:
-
-    Ext.create('Ext.tab.Panel', {
-        width: 400,
-        height: 400,
-        renderTo: document.body,
-        items: [{
-            title: 'Foo'
-        }, {
-            title: 'Bar',
-            tabConfig: {
-                title: 'Custom Title',
-                tooltip: 'A button tooltip'
-            }
-        }] 
-    });
-
-__Examples:__
-
-Here is a basic TabPanel rendered to the body. This also shows the useful configuration {@link #activeTab}, which allows you to set the active tab on render. 
-If you do not set an {@link #activeTab}, no tabs will be active by default.
-{@img Ext.tab.Panel/Ext.tab.Panel1.png TabPanel component}
-Example usage:
-
-    Ext.create('Ext.tab.Panel', {
-        width: 300,
-        height: 200,
-        activeTab: 0,
-        items: [
-            {
-                title: 'Tab 1',
-                bodyPadding: 10,
-                html : 'A simple tab'
-            },
-            {
-                title: 'Tab 2',
-                html : 'Another one'
-            }
-        ],
-        renderTo : Ext.getBody()
-    }); 
-    
-It is easy to control the visibility of items in the tab bar. Specify hidden: true to have the
-tab button hidden initially. Items can be subsequently hidden and show by accessing the
-tab property on the child item.
-
-Example usage:
-    
-    var tabs = Ext.create('Ext.tab.Panel', {
-        width: 400,
-        height: 400,
-        renderTo: document.body,
-        items: [{
-            title: 'Home',
-            html: 'Home',
-            itemId: 'home'
-        }, {
-            title: 'Users',
-            html: 'Users',
-            itemId: 'users',
-            hidden: true
-        }, {
-            title: 'Tickets',
-            html: 'Tickets',
-            itemId: 'tickets'
-        }]    
-    });
-    
-    setTimeout(function(){
-        tabs.child('#home').tab.hide();
-        var users = tabs.child('#users');
-        users.tab.show();
-        tabs.setActiveTab(users);
-    }, 1000);
-
-You can remove the background of the TabBar by setting the {@link #plain} property to `true`.
-
-Example usage:
-
-    Ext.create('Ext.tab.Panel', {
-        width: 300,
-        height: 200,
-        activeTab: 0,
-        plain: true,
-        items: [
-            {
-                title: 'Tab 1',
-                bodyPadding: 10,
-                html : 'A simple tab'
-            },
-            {
-                title: 'Tab 2',
-                html : 'Another one'
-            }
-        ],
-        renderTo : Ext.getBody()
-    }); 
-
-Another useful configuration of TabPanel is {@link #tabPosition}. This allows you to change the position where the tabs are displayed. The available 
-options for this are `'top'` (default) and `'bottom'`.
-{@img Ext.tab.Panel/Ext.tab.Panel2.png TabPanel component}
-Example usage:
-
-    Ext.create('Ext.tab.Panel', {
-        width: 300,
-        height: 200,
-        activeTab: 0,
-        bodyPadding: 10,        
-        tabPosition: 'bottom',
-        items: [
-            {
-                title: 'Tab 1',
-                html : 'A simple tab'
-            },
-            {
-                title: 'Tab 2',
-                html : 'Another one'
-            }
-        ],
-        renderTo : Ext.getBody()
-    }); 
-
-The {@link #setActiveTab} is a very useful method in TabPanel which will allow you to change the current active tab. You can either give it an index or 
-an instance of a tab.
-
-Example usage:
-
-    var tabs = Ext.create('Ext.tab.Panel', {
-        items: [
-            {
-                id   : 'my-tab',
-                title: 'Tab 1',
-                html : 'A simple tab'
-            },
-            {
-                title: 'Tab 2',
-                html : 'Another one'
-            }
-        ],
-        renderTo : Ext.getBody()
-    });
-    
-    var tab = Ext.getCmp('my-tab');
-    
-    Ext.create('Ext.button.Button', {
-        renderTo: Ext.getBody(),
-        text    : 'Select the first tab',
-        scope   : this,
-        handler : function() {
-            tabs.setActiveTab(tab);
-        }
-    });
-    
-    Ext.create('Ext.button.Button', {
-        text    : 'Select the second tab',
-        scope   : this,
-        handler : function() {
-            tabs.setActiveTab(1);
-        },
-        renderTo : Ext.getBody()        
-    });
-
-The {@link #getActiveTab} is a another useful method in TabPanel which will return the current active tab.
-
-Example usage:
-
-    var tabs = Ext.create('Ext.tab.Panel', {
-        items: [
-            {
-                title: 'Tab 1',
-                html : 'A simple tab'
-            },
-            {
-                title: 'Tab 2',
-                html : 'Another one'
-            }
-        ],
-        renderTo : Ext.getBody()        
-    });
-    
-    Ext.create('Ext.button.Button', {
-        text    : 'Get active tab',
-        scope   : this,
-        handler : function() {
-            var tab = tabs.getActiveTab();
-            alert('Current tab: ' + tab.title);
-        },
-        renderTo : Ext.getBody()        
-    });
-
-Adding a new tab is very simple with a TabPanel. You simple call the {@link #add} method with an config object for a panel.
-
-Example usage:
-
-    var tabs = Ext.Create('Ext.tab.Panel', {
-        items: [
-            {
-                title: 'Tab 1',
-                html : 'A simple tab'
-            },
-            {
-                title: 'Tab 2',
-                html : 'Another one'
-            }
-        ],
-        renderTo : Ext.getBody()        
-    });
-    
-    Ext.create('Ext.button.Button', {
-        text    : 'New tab',
-        scope   : this,
-        handler : function() {
-            var tab = tabs.add({
-                title: 'Tab ' + (tabs.items.length + 1), //we use the tabs.items property to get the length of current items/tabs
-                html : 'Another one'
-            });
-            
-            tabs.setActiveTab(tab);
-        },
-        renderTo : Ext.getBody()
-    });
-
-Additionally, removing a tab is very also simple with a TabPanel. You simple call the {@link #remove} method with an config object for a panel.
-
-Example usage:
-
-    var tabs = Ext.Create('Ext.tab.Panel', {        
-        items: [
-            {
-                title: 'Tab 1',
-                html : 'A simple tab'
-            },
-            {
-                id   : 'remove-this-tab',
-                title: 'Tab 2',
-                html : 'Another one'
-            }
-        ],
-        renderTo : Ext.getBody()
-    });
-    
-    Ext.Create('Ext.button.Button', {
-        text    : 'Remove tab',
-        scope   : this,
-        handler : function() {
-            var tab = Ext.getCmp('remove-this-tab');
-            tabs.remove(tab);
-        },
-        renderTo : Ext.getBody()
-    });
-
- * @extends Ext.Panel
- * @markdown
+ *
+ * A basic tab container. TabPanels can be used exactly like a standard {@link Ext.panel.Panel} for
+ * layout purposes, but also have special support for containing child Components
+ * (`{@link Ext.container.Container#items items}`) that are managed using a
+ * {@link Ext.layout.container.Card CardLayout layout manager}, and displayed as separate tabs.
+ *
+ * **Note:** By default, a tab's close tool _destroys_ the child tab Component and all its descendants.
+ * This makes the child tab Component, and all its descendants **unusable**.  To enable re-use of a tab,
+ * configure the TabPanel with `{@link #autoDestroy autoDestroy: false}`.
+ *
+ * ## TabPanel's layout
+ *
+ * TabPanels use a Dock layout to position the {@link Ext.tab.Bar TabBar} at the top of the widget.
+ * Panels added to the TabPanel will have their header hidden by default because the Tab will
+ * automatically take the Panel's configured title and icon.
+ *
+ * TabPanels use their {@link Ext.panel.Header header} or {@link Ext.panel.Panel#fbar footer}
+ * element (depending on the {@link #tabPosition} configuration) to accommodate the tab selector buttons.
+ * This means that a TabPanel will not display any configured title, and will not display any configured
+ * header {@link Ext.panel.Panel#tools tools}.
+ *
+ * To display a header, embed the TabPanel in a {@link Ext.panel.Panel Panel} which uses
+ * `{@link Ext.container.Container#layout layout: 'fit'}`.
+ *
+ * ## Controlling tabs
+ *
+ * Configuration options for the {@link Ext.tab.Tab} that represents the component can be passed in
+ * by specifying the tabConfig option:
+ *
+ *     @example
+ *     Ext.create('Ext.tab.Panel', {
+ *         width: 400,
+ *         height: 400,
+ *         renderTo: document.body,
+ *         items: [{
+ *             title: 'Foo'
+ *         }, {
+ *             title: 'Bar',
+ *             tabConfig: {
+ *                 title: 'Custom Title',
+ *                 tooltip: 'A button tooltip'
+ *             }
+ *         }]
+ *     });
+ *
+ * # Examples
+ *
+ * Here is a basic TabPanel rendered to the body. This also shows the useful configuration {@link #activeTab},
+ * which allows you to set the active tab on render. If you do not set an {@link #activeTab}, no tabs will be
+ * active by default.
+ *
+ *     @example
+ *     Ext.create('Ext.tab.Panel', {
+ *         width: 300,
+ *         height: 200,
+ *         activeTab: 0,
+ *         items: [
+ *             {
+ *                 title: 'Tab 1',
+ *                 bodyPadding: 10,
+ *                 html : 'A simple tab'
+ *             },
+ *             {
+ *                 title: 'Tab 2',
+ *                 html : 'Another one'
+ *             }
+ *         ],
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ * It is easy to control the visibility of items in the tab bar. Specify hidden: true to have the
+ * tab button hidden initially. Items can be subsequently hidden and show by accessing the
+ * tab property on the child item.
+ *
+ *     @example
+ *     var tabs = Ext.create('Ext.tab.Panel', {
+ *         width: 400,
+ *         height: 400,
+ *         renderTo: document.body,
+ *         items: [{
+ *             title: 'Home',
+ *             html: 'Home',
+ *             itemId: 'home'
+ *         }, {
+ *             title: 'Users',
+ *             html: 'Users',
+ *             itemId: 'users',
+ *             hidden: true
+ *         }, {
+ *             title: 'Tickets',
+ *             html: 'Tickets',
+ *             itemId: 'tickets'
+ *         }]
+ *     });
+ *
+ *     setTimeout(function(){
+ *         tabs.child('#home').tab.hide();
+ *         var users = tabs.child('#users');
+ *         users.tab.show();
+ *         tabs.setActiveTab(users);
+ *     }, 1000);
+ *
+ * You can remove the background of the TabBar by setting the {@link #plain} property to `true`.
+ *
+ *     @example
+ *     Ext.create('Ext.tab.Panel', {
+ *         width: 300,
+ *         height: 200,
+ *         activeTab: 0,
+ *         plain: true,
+ *         items: [
+ *             {
+ *                 title: 'Tab 1',
+ *                 bodyPadding: 10,
+ *                 html : 'A simple tab'
+ *             },
+ *             {
+ *                 title: 'Tab 2',
+ *                 html : 'Another one'
+ *             }
+ *         ],
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ * Another useful configuration of TabPanel is {@link #tabPosition}. This allows you to change the
+ * position where the tabs are displayed. The available options for this are `'top'` (default) and
+ * `'bottom'`.
+ *
+ *     @example
+ *     Ext.create('Ext.tab.Panel', {
+ *         width: 300,
+ *         height: 200,
+ *         activeTab: 0,
+ *         bodyPadding: 10,
+ *         tabPosition: 'bottom',
+ *         items: [
+ *             {
+ *                 title: 'Tab 1',
+ *                 html : 'A simple tab'
+ *             },
+ *             {
+ *                 title: 'Tab 2',
+ *                 html : 'Another one'
+ *             }
+ *         ],
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ * The {@link #setActiveTab} is a very useful method in TabPanel which will allow you to change the
+ * current active tab. You can either give it an index or an instance of a tab. For example:
+ *
+ *     @example
+ *     var tabs = Ext.create('Ext.tab.Panel', {
+ *         items: [
+ *             {
+ *                 id   : 'my-tab',
+ *                 title: 'Tab 1',
+ *                 html : 'A simple tab'
+ *             },
+ *             {
+ *                 title: 'Tab 2',
+ *                 html : 'Another one'
+ *             }
+ *         ],
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ *     var tab = Ext.getCmp('my-tab');
+ *
+ *     Ext.create('Ext.button.Button', {
+ *         renderTo: Ext.getBody(),
+ *         text    : 'Select the first tab',
+ *         scope   : this,
+ *         handler : function() {
+ *             tabs.setActiveTab(tab);
+ *         }
+ *     });
+ *
+ *     Ext.create('Ext.button.Button', {
+ *         text    : 'Select the second tab',
+ *         scope   : this,
+ *         handler : function() {
+ *             tabs.setActiveTab(1);
+ *         },
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ * The {@link #getActiveTab} is a another useful method in TabPanel which will return the current active tab.
+ *
+ *     @example
+ *     var tabs = Ext.create('Ext.tab.Panel', {
+ *         items: [
+ *             {
+ *                 title: 'Tab 1',
+ *                 html : 'A simple tab'
+ *             },
+ *             {
+ *                 title: 'Tab 2',
+ *                 html : 'Another one'
+ *             }
+ *         ],
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ *     Ext.create('Ext.button.Button', {
+ *         text    : 'Get active tab',
+ *         scope   : this,
+ *         handler : function() {
+ *             var tab = tabs.getActiveTab();
+ *             alert('Current tab: ' + tab.title);
+ *         },
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ * Adding a new tab is very simple with a TabPanel. You simple call the {@link #add} method with an config
+ * object for a panel.
+ *
+ *     @example
+ *     var tabs = Ext.create('Ext.tab.Panel', {
+ *         items: [
+ *             {
+ *                 title: 'Tab 1',
+ *                 html : 'A simple tab'
+ *             },
+ *             {
+ *                 title: 'Tab 2',
+ *                 html : 'Another one'
+ *             }
+ *         ],
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ *     Ext.create('Ext.button.Button', {
+ *         text    : 'New tab',
+ *         scope   : this,
+ *         handler : function() {
+ *             var tab = tabs.add({
+ *                 // we use the tabs.items property to get the length of current items/tabs
+ *                 title: 'Tab ' + (tabs.items.length + 1),
+ *                 html : 'Another one'
+ *             });
+ *
+ *             tabs.setActiveTab(tab);
+ *         },
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ * Additionally, removing a tab is very also simple with a TabPanel. You simple call the {@link #remove} method
+ * with an config object for a panel.
+ *
+ *     @example
+ *     var tabs = Ext.create('Ext.tab.Panel', {
+ *         items: [
+ *             {
+ *                 title: 'Tab 1',
+ *                 html : 'A simple tab'
+ *             },
+ *             {
+ *                 id   : 'remove-this-tab',
+ *                 title: 'Tab 2',
+ *                 html : 'Another one'
+ *             }
+ *         ],
+ *         renderTo : Ext.getBody()
+ *     });
+ *
+ *     Ext.create('Ext.button.Button', {
+ *         text    : 'Remove tab',
+ *         scope   : this,
+ *         handler : function() {
+ *             var tab = Ext.getCmp('remove-this-tab');
+ *             tabs.remove(tab);
+ *         },
+ *         renderTo : Ext.getBody()
+ *     });
  */
 Ext.define('Ext.tab.Panel', {
     extend: 'Ext.panel.Panel',
@@ -106256,55 +110633,76 @@ Ext.define('Ext.tab.Panel', {
     requires: ['Ext.layout.container.Card', 'Ext.tab.Bar'],
 
     /**
-     * @cfg {String} tabPosition The position where the tab strip should be rendered (defaults to <code>'top'</code>).
-     * In 4.0, The only other supported value is <code>'bottom'</code>.
+     * @cfg {String} tabPosition
+     * The position where the tab strip should be rendered. Can be `top` or `bottom`.
      */
     tabPosition : 'top',
-    
+
+    /**
+     * @cfg {String/Number} activeItem
+     * Doesn't apply for {@link Ext.tab.Panel TabPanel}, use {@link #activeTab} instead.
+     */
+
     /**
-     * @cfg {Object} tabBar Optional configuration object for the internal {@link Ext.tab.Bar}. If present, this is 
-     * passed straight through to the TabBar's constructor
+     * @cfg {String/Number/Ext.Component} activeTab
+     * The tab to activate initially. Either an ID, index or the tab component itself.
      */
 
     /**
-     * @cfg {Object} layout Optional configuration object for the internal {@link Ext.layout.container.Card card layout}.
+     * @cfg {Object} tabBar
+     * Optional configuration object for the internal {@link Ext.tab.Bar}.
+     * If present, this is passed straight through to the TabBar's constructor
+     */
+
+    /**
+     * @cfg {Object} layout
+     * Optional configuration object for the internal {@link Ext.layout.container.Card card layout}.
      * If present, this is passed straight through to the layout's constructor
      */
 
     /**
-     * @cfg {Boolean} removePanelHeader True to instruct each Panel added to the TabContainer to not render its header 
-     * element. This is to ensure that the title of the panel does not appear twice. Defaults to true.
+     * @cfg {Boolean} removePanelHeader
+     * True to instruct each Panel added to the TabContainer to not render its header element.
+     * This is to ensure that the title of the panel does not appear twice.
      */
     removePanelHeader: true,
 
     /**
-     * @cfg Boolean plain
-     * True to not show the full background on the TabBar
+     * @cfg {Boolean} plain
+     * True to not show the full background on the TabBar.
      */
     plain: false,
 
     /**
-     * @cfg {String} itemCls The class added to each child item of this TabPanel. Defaults to 'x-tabpanel-child'.
+     * @cfg {String} itemCls
+     * The class added to each child item of this TabPanel.
      */
     itemCls: 'x-tabpanel-child',
 
     /**
-     * @cfg {Number} minTabWidth The minimum width for a tab in the {@link #tabBar}. Defaults to <code>30</code>.
+     * @cfg {Number} minTabWidth
+     * The minimum width for a tab in the {@link #tabBar}.
      */
+    minTabWidth: undefined,
+
+    /**
+     * @cfg {Number} maxTabWidth The maximum width for each tab.
+     */
+    maxTabWidth: undefined,
 
     /**
      * @cfg {Boolean} deferredRender
-     * <p><tt>true</tt> by default to defer the rendering of child <tt>{@link Ext.container.Container#items items}</tt>
-     * to the browsers DOM until a tab is activated. <tt>false</tt> will render all contained
-     * <tt>{@link Ext.container.Container#items items}</tt> as soon as the {@link Ext.layout.container.Card layout}
-     * is rendered. If there is a significant amount of content or a lot of heavy controls being
-     * rendered into panels that are not displayed by default, setting this to <tt>true</tt> might
-     * improve performance.</p>
-     * <br><p>The <tt>deferredRender</tt> property is internally passed to the layout manager for
-     * TabPanels ({@link Ext.layout.container.Card}) as its {@link Ext.layout.container.Card#deferredRender}
-     * configuration value.</p>
-     * <br><p><b>Note</b>: leaving <tt>deferredRender</tt> as <tt>true</tt> means that the content
-     * within an unactivated tab will not be available</p>
+     *
+     * True by default to defer the rendering of child {@link Ext.container.Container#items items} to the browsers DOM
+     * until a tab is activated. False will render all contained {@link Ext.container.Container#items items} as soon as
+     * the {@link Ext.layout.container.Card layout} is rendered. If there is a significant amount of content or a lot of
+     * heavy controls being rendered into panels that are not displayed by default, setting this to true might improve
+     * performance.
+     *
+     * The deferredRender property is internally passed to the layout manager for TabPanels ({@link
+     * Ext.layout.container.Card}) as its {@link Ext.layout.container.Card#deferredRender} configuration value.
+     *
+     * **Note**: leaving deferredRender as true means that the content within an unactivated tab will not be available
      */
     deferredRender : true,
 
@@ -106321,9 +110719,7 @@ Ext.define('Ext.tab.Panel', {
         }, me.layout));
 
         /**
-         * @property tabBar
-         * @type Ext.TabBar
-         * Internal reference to the docked TabBar
+         * @property {Ext.tab.Bar} tabBar Internal reference to the docked TabBar
          */
         me.tabBar = Ext.create('Ext.tab.Bar', Ext.apply({}, me.tabBar, {
             dock: me.tabPosition,
@@ -106342,7 +110738,7 @@ Ext.define('Ext.tab.Panel', {
 
         me.addEvents(
             /**
-             * @event beforetabchange
+             * @event
              * Fires before a tab change (activated by {@link #setActiveTab}). Return false in any listener to cancel
              * the tabchange
              * @param {Ext.tab.Panel} tabPanel The TabPanel
@@ -106352,7 +110748,7 @@ Ext.define('Ext.tab.Panel', {
             'beforetabchange',
 
             /**
-             * @event tabchange
+             * @event
              * Fires when a new tab has been activated (activated by {@link #setActiveTab}).
              * @param {Ext.tab.Panel} tabPanel The TabPanel
              * @param {Ext.Component} newCard The newly activated item
@@ -106378,15 +110774,15 @@ Ext.define('Ext.tab.Panel', {
     afterInitialLayout: function() {
         var me = this,
             card = me.getComponent(me.activeTab);
-            
+
         if (card) {
             me.layout.setActiveItem(card);
         }
     },
 
     /**
-     * Makes the given card active (makes it the visible card in the TabPanel's CardLayout and highlights the Tab)
-     * @param {Ext.Component} card The card to make active
+     * Makes the given card active. Makes it the visible card in the TabPanel's CardLayout and highlights the Tab.
+     * @param {String/Number/Ext.Component} card The card to make active. Either an ID, index or the component itself.
      */
     setActiveTab: function(card) {
         var me = this,
@@ -106395,17 +110791,17 @@ Ext.define('Ext.tab.Panel', {
         card = me.getComponent(card);
         if (card) {
             previous = me.getActiveTab();
-            
+
             if (previous && previous !== card && me.fireEvent('beforetabchange', me, card, previous) === false) {
                 return false;
             }
-            
+
             me.tabBar.setActiveTab(card.tab);
             me.activeTab = card;
             if (me.rendered) {
                 me.layout.setActiveItem(card);
             }
-            
+
             if (previous && previous !== card) {
                 me.fireEvent('tabchange', me, card, previous);
             }
@@ -106414,8 +110810,8 @@ Ext.define('Ext.tab.Panel', {
 
     /**
      * Returns the item that is currently active inside this TabPanel. Note that before the TabPanel first activates a
-     * child component this will return whatever was configured in the {@link #activeTab} config option 
-     * @return {Ext.Component/Integer} The currently active item
+     * child component this will return whatever was configured in the {@link #activeTab} config option
+     * @return {String/Number/Ext.Component} The currently active item
      */
     getActiveTab: function() {
         return this.activeTab;
@@ -106423,7 +110819,7 @@ Ext.define('Ext.tab.Panel', {
 
     /**
      * Returns the {@link Ext.tab.Bar} currently used in this TabPanel
-     * @return {Ext.TabBar} The TabBar
+     * @return {Ext.tab.Bar} The TabBar
      */
     getTabBar: function() {
         return this.tabBar;
@@ -106444,13 +110840,13 @@ Ext.define('Ext.tab.Panel', {
                 hidden: item.hidden,
                 tabBar: me.tabBar
             };
-            
+
         if (item.closeText) {
             defaultConfig.closeText = item.closeText;
         }
         cfg = Ext.applyIf(cfg, defaultConfig);
         item.tab = me.tabBar.insert(index, cfg);
-        
+
         item.on({
             scope : me,
             enable: me.onItemEnable,
@@ -106477,7 +110873,7 @@ Ext.define('Ext.tab.Panel', {
             me.setActiveTab(0);
         }
     },
-    
+
     /**
      * @private
      * Enable corresponding tab when item is enabled.
@@ -106489,11 +110885,11 @@ Ext.define('Ext.tab.Panel', {
     /**
      * @private
      * Disable corresponding tab when item is enabled.
-     */    
+     */
     onItemDisable: function(item){
         item.tab.disable();
     },
-    
+
     /**
      * @private
      * Sets activeTab before item is shown.
@@ -106502,9 +110898,9 @@ Ext.define('Ext.tab.Panel', {
         if (item !== this.activeTab) {
             this.setActiveTab(item);
             return false;
-        }    
+        }
     },
-    
+
     /**
      * @private
      * Update the tab iconCls when panel iconCls has been set or changed.
@@ -106513,7 +110909,7 @@ Ext.define('Ext.tab.Panel', {
         item.tab.setIconCls(newIconCls);
         this.getTabBar().doLayout();
     },
-    
+
     /**
      * @private
      * Update the tab title when panel title has been set or changed.
@@ -106532,17 +110928,15 @@ Ext.define('Ext.tab.Panel', {
     doRemove: function(item, autoDestroy) {
         var me = this,
             items = me.items,
-            /**
-             * At this point the item hasn't been removed from the items collection.
-             * As such, if we want to check if there are no more tabs left, we have to
-             * check for one, as opposed to 0.
-             */
+            // At this point the item hasn't been removed from the items collection.
+            // As such, if we want to check if there are no more tabs left, we have to
+            // check for one, as opposed to 0.
             hasItemsLeft = items.getCount() > 1;
 
         if (me.destroying || !hasItemsLeft) {
             me.activeTab = null;
         } else if (item === me.activeTab) {
-             me.setActiveTab(item.next() || items.getAt(0)); 
+             me.setActiveTab(item.next() || items.getAt(0));
         }
         me.callParent(arguments);
 
@@ -106557,7 +110951,7 @@ Ext.define('Ext.tab.Panel', {
      */
     onRemove: function(item, autoDestroy) {
         var me = this;
-        
+
         item.un({
             scope : me,
             enable: me.onItemEnable,
@@ -106571,34 +110965,30 @@ Ext.define('Ext.tab.Panel', {
 });
 
 /**
- * @class Ext.toolbar.Spacer
- * @extends Ext.toolbar.Item
  * A simple element that adds extra horizontal space between items in a toolbar.
- * By default a 2px wide space is added via css specification:
+ * By default a 2px wide space is added via CSS specification:
  *
  *     .x-toolbar .x-toolbar-spacer {
- *         width:2px;
+ *         width: 2px;
  *     }
  *
- * ## Example
- *
- * {@img Ext.toolbar.Spacer/Ext.toolbar.Spacer.png Toolbar Spacer}
+ * Example:
  *
+ *     @example
  *     Ext.create('Ext.panel.Panel', {
  *         title: 'Toolbar Spacer Example',
  *         width: 300,
  *         height: 200,
  *         tbar : [
  *             'Item 1',
- *             {xtype: 'tbspacer'}, // or ' '
+ *             { xtype: 'tbspacer' }, // or ' '
  *             'Item 2',
  *             // space width is also configurable via javascript
- *             {xtype: 'tbspacer', width: 50}, // add a 50px space
+ *             { xtype: 'tbspacer', width: 50 }, // add a 50px space
  *             'Item 3'
  *         ],
  *         renderTo: Ext.getBody()
- *     });   
- *
+ *     });
  */
 Ext.define('Ext.toolbar.Spacer', {
     extend: 'Ext.Component',
@@ -106654,7 +111044,7 @@ Ext.define('Ext.tree.Column', {
                                 record.get('checked') ? 'aria-checked="true"' : ''
                             ));
                             if (record.get('checked')) {
-                                metaData.tdCls += (' ' + Ext.baseCSSPrefix + 'tree-checked');
+                                metaData.tdCls += (' ' + treePrefix + 'checked');
                             }
                         }
                         if (record.isLast()) {
@@ -106682,12 +111072,14 @@ Ext.define('Ext.tree.Column', {
                 record = record.parentNode;
             }
             if (href) {
-                formattedValue = format('<a href="{0}" target="{1}">{2}</a>', href, target, formattedValue);
+                buf.push('<a href="', href, '" target="', target, '">', formattedValue, '</a>');
+            } else {
+                buf.push(formattedValue);
             }
             if (cls) {
                 metaData.tdCls += ' ' + cls;
             }
-            return buf.join("") + formattedValue;
+            return buf.join('');
         };
         this.callParent(arguments);
     },
@@ -106697,8 +111089,7 @@ Ext.define('Ext.tree.Column', {
     }
 });
 /**
- * @class Ext.tree.View
- * @extends Ext.view.Table
+ * Used as a view by {@link Ext.tree.Panel TreePanel}.
  */
 Ext.define('Ext.tree.View', {
     extend: 'Ext.view.Table',
@@ -106711,15 +111102,22 @@ Ext.define('Ext.tree.View', {
     checkboxSelector: '.' + Ext.baseCSSPrefix + 'tree-checkbox',
     expanderIconOverCls: Ext.baseCSSPrefix + 'tree-expander-over',
 
+    // Class to add to the node wrap element used to hold nodes when a parent is being
+    // collapsed or expanded. During the animation, UI interaction is forbidden by testing
+    // for an ancestor node with this class.
+    nodeAnimWrapCls: Ext.baseCSSPrefix + 'tree-animator-wrap',
+
     blockRefresh: true,
 
     /** 
-     * @cfg {Boolean} rootVisible <tt>false</tt> to hide the root node (defaults to <tt>true</tt>)
+     * @cfg {Boolean} rootVisible
+     * False to hide the root node.
      */
     rootVisible: true,
 
     /** 
-     * @cfg {Boolean} animate <tt>true</tt> to enable animated expand/collapse (defaults to the value of {@link Ext#enableFx Ext.enableFx})
+     * @cfg {Boolean} animate
+     * True to enable animated expand/collapse (defaults to the value of {@link Ext#enableFx Ext.enableFx})
      */
 
     expandDuration: 250,
@@ -106752,7 +111150,17 @@ Ext.define('Ext.tree.View', {
         me.animQueue = {};
         me.callParent(arguments);
     },
-    
+
+    processUIEvent: function(e) {
+        // If the clicked node is part of an animation, ignore the click.
+        // This is because during a collapse animation, the associated Records
+        // will already have been removed from the Store, and the event is not processable.
+        if (e.getTarget('.' + this.nodeAnimWrapCls, this.el)) {
+            return false;
+        }
+        return this.callParent(arguments);
+    },
+
     onClear: function(){
         this.store.removeAll();    
     },
@@ -106768,7 +111176,6 @@ Ext.define('Ext.tree.View', {
     
     onRender: function() {
         var me = this,
-            opts = {delegate: me.expanderSelector},
             el;
 
         me.callParent(arguments);
@@ -106788,14 +111195,20 @@ Ext.define('Ext.tree.View', {
     },
 
     onCheckboxChange: function(e, t) {
-        var item = e.getTarget(this.getItemSelector(), this.getTargetEl()),
-            record, value;
+        var me = this,
+            item = e.getTarget(me.getItemSelector(), me.getTargetEl());
             
         if (item) {
-            record = this.getRecord(item);
-            value = !record.get('checked');
-            record.set('checked', value);
-            this.fireEvent('checkchange', record, value);
+            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);
         }
     },
 
@@ -106831,7 +111244,7 @@ Ext.define('Ext.tree.View', {
             tag: 'tr',
             html: [
                 '<td colspan="' + headerCt.getColumnCount() + '">',
-                    '<div class="' + Ext.baseCSSPrefix + 'tree-animator-wrap' + '">',
+                    '<div class="' + this.nodeAnimWrapCls + '">',
                         '<table class="' + Ext.baseCSSPrefix + 'grid-table" style="width: ' + headerCt.getFullWidth() + 'px;"><tbody>',
                             thHtml,
                         '</tbody></table>',
@@ -106918,6 +111331,36 @@ Ext.define('Ext.tree.View', {
         }
     },
     
+    beginBulkUpdate: function(){
+        this.bulkUpdate = true;
+        this.ownerCt.changingScrollbars = true;  
+    },
+    
+    endBulkUpdate: function(){
+        var me = this,
+            ownerCt = me.ownerCt;
+        
+        me.bulkUpdate = false;
+        me.ownerCt.changingScrollbars = true;  
+        me.resetScrollers();  
+    },
+    
+    onRemove : function(ds, record, index) {
+        var me = this,
+            bulk = me.bulkUpdate;
+
+        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) {
         // If we are adding records which have a parent that is currently expanding
         // lets add them to the animation wrap
@@ -107005,10 +111448,12 @@ Ext.define('Ext.tree.View', {
     },
     
     resetScrollers: function(){
-        var panel = this.panel;
-        
-        panel.determineScrollbars();
-        panel.invalidateScroller();
+        if (!this.bulkUpdate) {
+            var panel = this.panel;
+            
+            panel.determineScrollbars();
+            panel.invalidateScroller();
+        }
     },
 
     onBeforeCollapse: function(parent, records, index) {
@@ -107106,7 +111551,7 @@ Ext.define('Ext.tree.View', {
     },
     
     /**
-     * Expand a record that is loaded in the view.
+     * Expands a record that is loaded in the view.
      * @param {Ext.data.Model} record The record to expand
      * @param {Boolean} deep (optional) True to expand nodes all the way down the tree hierarchy.
      * @param {Function} callback (optional) The function to run after the expand is completed
@@ -107117,7 +111562,7 @@ Ext.define('Ext.tree.View', {
     },
     
     /**
-     * Collapse a record that is loaded in the view.
+     * Collapses a record that is loaded in the view.
      * @param {Ext.data.Model} record The record to collapse
      * @param {Boolean} deep (optional) True to collapse nodes all the way up the tree hierarchy.
      * @param {Function} callback (optional) The function to run after the collapse is completed
@@ -107128,8 +111573,8 @@ Ext.define('Ext.tree.View', {
     },
     
     /**
-     * Toggle a record between expanded and collapsed.
-     * @param {Ext.data.Record} recordInstance
+     * Toggles a record between expanded and collapsed.
+     * @param {Ext.data.Model} recordInstance
      */
     toggle: function(record) {
         this[record.isExpanded() ? 'collapse' : 'expand'](record);
@@ -107186,17 +111631,14 @@ Ext.define('Ext.tree.View', {
 /**
  * The TreePanel provides tree-structured UI representation of tree-structured data.
  * A TreePanel must be bound to a {@link Ext.data.TreeStore}. TreePanel's support
- * multiple columns through the {@link #columns} configuration. 
- * 
- * Simple TreePanel using inline data.
+ * multiple columns through the {@link #columns} configuration.
  *
- * {@img Ext.tree.Panel/Ext.tree.Panel1.png Ext.tree.Panel component}
- * 
- * Code:
+ * Simple TreePanel using inline data:
  *
+ *     @example
  *     var store = Ext.create('Ext.data.TreeStore', {
  *         root: {
- *             expanded: true, 
+ *             expanded: true,
  *             children: [
  *                 { text: "detention", leaf: true },
  *                 { text: "homework", expanded: true, children: [
@@ -107206,16 +111648,19 @@ Ext.define('Ext.tree.View', {
  *                 { text: "buy lottery tickets", leaf: true }
  *             ]
  *         }
- *     });     
+ *     });
  *
  *     Ext.create('Ext.tree.Panel', {
  *         title: 'Simple Tree',
  *         width: 200,
  *         height: 150,
  *         store: store,
- *         rootVisible: false,        
+ *         rootVisible: false,
  *         renderTo: Ext.getBody()
  *     });
+ *
+ * For the tree node config options (like `text`, `leaf`, `expanded`), see the documentation of
+ * {@link Ext.data.NodeInterface NodeInterface} config options.
  */
 Ext.define('Ext.tree.Panel', {
     extend: 'Ext.panel.Table',
@@ -107224,46 +111669,46 @@ Ext.define('Ext.tree.Panel', {
     requires: ['Ext.tree.View', 'Ext.selection.TreeModel', 'Ext.tree.Column'],
     viewType: 'treeview',
     selType: 'treemodel',
-    
+
     treeCls: Ext.baseCSSPrefix + 'tree-panel',
 
     deferRowRender: false,
 
     /**
-     * @cfg {Boolean} lines False to disable tree lines. Defaults to true.
+     * @cfg {Boolean} lines False to disable tree lines.
      */
     lines: true,
-    
+
     /**
-     * @cfg {Boolean} useArrows True to use Vista-style arrows in the tree. Defaults to false.
+     * @cfg {Boolean} useArrows True to use Vista-style arrows in the tree.
      */
     useArrows: false,
-    
+
     /**
-     * @cfg {Boolean} singleExpand True if only 1 node per branch may be expanded. Defaults to false.
+     * @cfg {Boolean} singleExpand True if only 1 node per branch may be expanded.
      */
     singleExpand: false,
-    
+
     ddConfig: {
         enableDrag: true,
         enableDrop: true
     },
-    
-    /** 
+
+    /**
      * @cfg {Boolean} animate True to enable animated expand/collapse. Defaults to the value of {@link Ext#enableFx}.
      */
-            
-    /** 
-     * @cfg {Boolean} rootVisible False to hide the root node. Defaults to true.
+
+    /**
+     * @cfg {Boolean} rootVisible False to hide the root node.
      */
     rootVisible: true,
-    
-    /** 
-     * @cfg {Boolean} displayField The field inside the model that will be used as the node's text. Defaults to 'text'.
-     */    
+
+    /**
+     * @cfg {Boolean} displayField The field inside the model that will be used as the node's text.
+     */
     displayField: 'text',
 
-    /** 
+    /**
      * @cfg {Ext.data.Model/Ext.data.NodeInterface/Object} root
      * Allows you to not specify a store on this TreePanel. This is useful for creating a simple tree with preloaded
      * data without having to specify a TreeStore and Model. A store and model will be created and root will be passed
@@ -107283,7 +111728,7 @@ Ext.define('Ext.tree.Panel', {
      *     });
      */
     root: null,
-    
+
     // Required for the Lockable Mixin. These are the configurations which will be copied to the
     // normal and locked sub tablepanels
     normalCfgCopy: ['displayField', 'root', 'singleExpand', 'useArrows', 'lines', 'rootVisible', 'scroll'],
@@ -107292,11 +111737,11 @@ Ext.define('Ext.tree.Panel', {
     /**
      * @cfg {Boolean} hideHeaders True to hide the headers. Defaults to `undefined`.
      */
-    
+
     /**
      * @cfg {Boolean} folderSort True to automatically prepend a leaf sorter to the store. Defaults to `undefined`.
-     */ 
-    
+     */
+
     constructor: function(config) {
         config = config || {};
         if (config.animate === undefined) {
@@ -107304,10 +111749,10 @@ Ext.define('Ext.tree.Panel', {
         }
         this.enableAnimations = config.animate;
         delete config.animate;
-        
+
         this.callParent([config]);
     },
-    
+
     initComponent: function() {
         var me = this,
             cls = [me.treeCls];
@@ -107316,13 +111761,13 @@ Ext.define('Ext.tree.Panel', {
             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) {
@@ -107338,14 +111783,14 @@ Ext.define('Ext.tree.Panel', {
             if (me.folderSort !== undefined) {
                 me.store.folderSort = me.folderSort;
                 me.store.sort();
-            }            
+            }
         }
-        
+
         // I'm not sure if we want to this. It might be confusing
         // if (me.initialConfig.rootVisible === undefined && !me.getRootNode()) {
         //     me.rootVisible = false;
         // }
-        
+
         me.viewConfig = Ext.applyIf(me.viewConfig || {}, {
             rootVisible: me.rootVisible,
             animate: me.enableAnimations,
@@ -107353,141 +111798,101 @@ Ext.define('Ext.tree.Panel', {
             node: me.store.getRootNode(),
             hideHeaders: me.hideHeaders
         });
-        
+
         me.mon(me.store, {
             scope: me,
             rootchange: me.onRootChange,
             clear: me.onClear
         });
-    
+
         me.relayEvents(me.store, [
             /**
              * @event beforeload
-             * Event description
-             * @param {Ext.data.Store} store This Store
-             * @param {Ext.data.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to load the Store
+             * @alias Ext.data.Store#beforeload
              */
             'beforeload',
 
             /**
              * @event load
-             * Fires whenever the store reads data from a remote data source.
-             * @param {Ext.data.store} this
-             * @param {Array} records An array of records
-             * @param {Boolean} successful True if the operation was successful.
+             * @alias Ext.data.Store#load
              */
-            'load'   
+            'load'
         ]);
-        
+
         me.store.on({
             /**
              * @event itemappend
-             * Fires when a new child node is appended to a node in the tree.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The newly appended node
-             * @param {Number} index The index of the newly appended node
+             * @alias Ext.data.TreeStore#append
              */
             append: me.createRelayer('itemappend'),
-            
+
             /**
              * @event itemremove
-             * Fires when a child node is removed from a node in the tree
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node removed
+             * @alias Ext.data.TreeStore#remove
              */
             remove: me.createRelayer('itemremove'),
-            
+
             /**
              * @event itemmove
-             * Fires when a node is moved to a new location in the tree
-             * @param {Tree} tree The owner tree
-             * @param {Node} node The node moved
-             * @param {Node} oldParent The old parent of this node
-             * @param {Node} newParent The new parent of this node
-             * @param {Number} index The index it was moved to
+             * @alias Ext.data.TreeStore#move
              */
             move: me.createRelayer('itemmove'),
-            
+
             /**
              * @event iteminsert
-             * Fires when a new child node is inserted in a node in tree
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node inserted
-             * @param {Node} refNode The child node the node was inserted before
+             * @alias Ext.data.TreeStore#insert
              */
             insert: me.createRelayer('iteminsert'),
-            
+
             /**
              * @event beforeitemappend
-             * Fires before a new child is appended to a node in this tree, return false to cancel the append.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node to be appended
+             * @alias Ext.data.TreeStore#beforeappend
              */
             beforeappend: me.createRelayer('beforeitemappend'),
-            
+
             /**
              * @event beforeitemremove
-             * Fires before a child is removed from a node in this tree, return false to cancel the remove.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node to be removed
+             * @alias Ext.data.TreeStore#beforeremove
              */
             beforeremove: me.createRelayer('beforeitemremove'),
-            
+
             /**
              * @event beforeitemmove
-             * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
-             * @param {Tree} tree The owner tree
-             * @param {Node} node The node being moved
-             * @param {Node} oldParent The parent of the node
-             * @param {Node} newParent The new parent the node is moving to
-             * @param {Number} index The index it is being moved to
+             * @alias Ext.data.TreeStore#beforemove
              */
             beforemove: me.createRelayer('beforeitemmove'),
-            
+
             /**
              * @event beforeiteminsert
-             * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
-             * @param {Tree} tree The owner tree
-             * @param {Node} parent The parent node
-             * @param {Node} node The child node to be inserted
-             * @param {Node} refNode The child node the node is being inserted before
+             * @alias Ext.data.TreeStore#beforeinsert
              */
             beforeinsert: me.createRelayer('beforeiteminsert'),
-             
+
             /**
              * @event itemexpand
-             * Fires when a node is expanded.
-             * @param {Node} this The expanding node
+             * @alias Ext.data.TreeStore#expand
              */
             expand: me.createRelayer('itemexpand'),
-             
+
             /**
              * @event itemcollapse
-             * Fires when a node is collapsed.
-             * @param {Node} this The collapsing node
+             * @alias Ext.data.TreeStore#collapse
              */
             collapse: me.createRelayer('itemcollapse'),
-             
+
             /**
              * @event beforeitemexpand
-             * Fires before a node is expanded.
-             * @param {Node} this The expanding node
+             * @alias Ext.data.TreeStore#beforeexpand
              */
             beforeexpand: me.createRelayer('beforeitemexpand'),
-             
+
             /**
              * @event beforeitemcollapse
-             * Fires before a node is collapsed.
-             * @param {Node} this The collapsing node
+             * @alias Ext.data.TreeStore#beforecollapse
              */
             beforecollapse: me.createRelayer('beforeitemcollapse')
         });
-        
+
         // If the user specifies the headers collection manually then dont inject our own
         if (!me.columns) {
             if (me.initialConfig.hideHeaders === undefined) {
@@ -107497,16 +111902,16 @@ Ext.define('Ext.tree.Panel', {
                 xtype    : 'treecolumn',
                 text     : 'Name',
                 flex     : 1,
-                dataIndex: me.displayField         
+                dataIndex: me.displayField
             }];
         }
-        
+
         if (me.cls) {
             cls.push(me.cls);
         }
         me.cls = cls.join(' ');
         me.callParent();
-        
+
         me.relayEvents(me.getView(), [
             /**
              * @event checkchange
@@ -107516,7 +111921,7 @@ Ext.define('Ext.tree.Panel', {
              */
             'checkchange'
         ]);
-            
+
         // If the root is not visible and there is no rootnode defined, then just lets load the store
         if (!me.getView().rootVisible && !me.getRootNode()) {
             me.setRootNode({
@@ -107524,44 +111929,61 @@ Ext.define('Ext.tree.Panel', {
             });
         }
     },
-    
+
     onClear: function(){
         this.view.onClear();
     },
-    
+
+    /**
+     * Sets root node of this tree.
+     * @param {Ext.data.Model/Ext.data.NodeInterface/Object} root
+     * @return {Ext.data.NodeInterface} The new root
+     */
     setRootNode: function() {
         return this.store.setRootNode.apply(this.store, arguments);
     },
-    
+
+    /**
+     * Returns the root node for this tree.
+     * @return {Ext.data.NodeInterface}
+     */
     getRootNode: function() {
         return this.store.getRootNode();
     },
-    
+
     onRootChange: function(root) {
         this.view.setRootNode(root);
     },
 
     /**
      * Retrieve an array of checked records.
-     * @return {Array} An array containing the checked records
+     * @return {Ext.data.Model[]} An array containing the checked records
      */
     getChecked: function() {
         return this.getView().getChecked();
     },
-    
+
     isItemChecked: function(rec) {
         return rec.get('checked');
     },
-        
+
     /**
      * Expand all nodes
      * @param {Function} callback (optional) A function to execute when the expand finishes.
      * @param {Object} scope (optional) The scope of the callback function
      */
     expandAll : function(callback, scope) {
-        var root = this.getRootNode();
+        var root = this.getRootNode(),
+            animate = this.enableAnimations,
+            view = this.getView();
         if (root) {
+            if (!animate) {
+                view.beginBulkUpdate();
+            }
             root.expand(true, callback, scope);
+            if (!animate) {
+                view.endBulkUpdate();
+            }
         }
     },
 
@@ -107571,14 +111993,22 @@ Ext.define('Ext.tree.Panel', {
      * @param {Object} scope (optional) The scope of the callback function
      */
     collapseAll : function(callback, scope) {
-        var root = this.getRootNode();
+        var root = this.getRootNode(),
+            animate = this.enableAnimations,
+            view = this.getView();
+
         if (root) {
-            if (this.getView().rootVisible) {
-                root.collapse(true, callback, scope);
+            if (!animate) {
+                view.beginBulkUpdate();
             }
-            else {
+            if (view.rootVisible) {
+                root.collapse(true, callback, scope);
+            } else {
                 root.collapseChildren(true, callback, scope);
             }
+            if (!animate) {
+                view.endBulkUpdate();
+            }
         }
     },
 
@@ -107598,22 +112028,22 @@ Ext.define('Ext.tree.Panel', {
             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]) {
             // invalid root
             Ext.callback(callback, scope || me, [false, current]);
             return;
         }
-        
+
         expander = function(){
             if (++index === keys.length) {
                 Ext.callback(callback, scope || me, [true, current]);
@@ -107629,9 +112059,9 @@ Ext.define('Ext.tree.Panel', {
         };
         current.expand(false, expander);
     },
-    
+
     /**
-     * Expand the tree to the path of a particular node, then selectt.
+     * Expand the tree to the path of a particular node, then select it.
      * @param {String} path The path to select. The path should include a leading separator.
      * @param {String} field (optional) The field to get the data from. Defaults to the model idProperty.
      * @param {String} separator (optional) A separator to use. Defaults to `'/'`.
@@ -107643,13 +112073,13 @@ Ext.define('Ext.tree.Panel', {
         var me = this,
             keys,
             last;
-        
+
         field = field || me.getRootNode().idProperty;
         separator = separator || '/';
-        
+
         keys = path.split(separator);
         last = keys.pop();
-        
+
         me.expandPath(keys.join(separator), field, separator, function(success, node){
             var doSuccess = false;
             if (success && node) {
@@ -107832,26 +112262,26 @@ Ext.define('Ext.tree.ViewDropZone', {
     /**
      * @cfg {Boolean} allowParentInsert
      * Allow inserting a dragged node between an expanded parent node and its first child that will become a
-     * sibling of the parent when dropped (defaults to false)
+     * sibling of the parent when dropped.
      */
     allowParentInserts: false,
  
     /**
      * @cfg {String} allowContainerDrop
-     * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
+     * True if drops on the tree container (outside of a specific tree node) are allowed.
      */
     allowContainerDrops: false,
 
     /**
      * @cfg {String} appendOnly
-     * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
+     * True if the tree should only allow append drops (use for trees which are sorted).
      */
     appendOnly: false,
 
     /**
      * @cfg {String} expandDelay
      * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
-     * over the target (defaults to 500)
+     * over the target.
      */
     expandDelay : 500,
 
@@ -108105,27 +112535,44 @@ Ext.define('Ext.tree.ViewDropZone', {
     }
 });
 /**
- * @class Ext.tree.ViewDDPlugin
- * @extends Ext.AbstractPlugin
- * <p>This plugin provides drag and/or drop functionality for a TreeView.</p>
- * <p>It creates a specialized instance of {@link Ext.dd.DragZone DragZone} which knows how to drag out of a {@link Ext.tree.View TreeView}
- * and loads the data object which is passed to a cooperating {@link Ext.dd.DragZone DragZone}'s methods with the following properties:<ul>
- * <li>copy : Boolean
- *  <div class="sub-desc">The value of the TreeView's <code>copy</code> property, or <code>true</code> if the TreeView was configured
- *  with <code>allowCopy: true</code> <u>and</u> the control key was pressed when the drag operation was begun.</div></li>
- * <li>view : TreeView
- *  <div class="sub-desc">The source TreeView from which the drag originated.</div></li>
- * <li>ddel : HtmlElement
- *  <div class="sub-desc">The drag proxy element which moves with the mouse</div></li>
- * <li>item : HtmlElement
- *  <div class="sub-desc">The TreeView node upon which the mousedown event was registered.</div></li>
- * <li>records : Array
- *  <div class="sub-desc">An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source TreeView.</div></li>
- * </ul></p>
- * <p>It also creates a specialized instance of {@link Ext.dd.DropZone} which cooperates with other DropZones which are members of the same
- * ddGroup which processes such data objects.</p>
- * <p>Adding this plugin to a view means that two new events may be fired from the client TreeView, <code>{@link #event-beforedrop beforedrop}</code> and
- * <code>{@link #event-drop drop}</code></p>
+ * This plugin provides drag and/or drop functionality for a TreeView.
+ *
+ * It creates a specialized instance of {@link Ext.dd.DragZone DragZone} which knows how to drag out of a
+ * {@link Ext.tree.View TreeView} and loads the data object which is passed to a cooperating
+ * {@link Ext.dd.DragZone DragZone}'s methods with the following properties:
+ *
+ *   - copy : Boolean
+ *
+ *     The value of the TreeView's `copy` property, or `true` if the TreeView was configured with `allowCopy: true` *and*
+ *     the control key was pressed when the drag operation was begun.
+ *
+ *   - view : TreeView
+ *
+ *     The source TreeView from which the drag originated.
+ *
+ *   - ddel : HtmlElement
+ *
+ *     The drag proxy element which moves with the mouse
+ *
+ *   - item : HtmlElement
+ *
+ *     The TreeView node upon which the mousedown event was registered.
+ *
+ *   - records : Array
+ *
+ *     An Array of {@link Ext.data.Model Models} representing the selected data being dragged from the source TreeView.
+ *
+ * It also creates a specialized instance of {@link Ext.dd.DropZone} which cooperates with other DropZones which are
+ * members of the same ddGroup which processes such data objects.
+ *
+ * Adding this plugin to a view means that two new events may be fired from the client TreeView, {@link #beforedrop} and
+ * {@link #drop}.
+ *
+ * Note that the plugin must be added to the tree view, not to the tree panel. For example using viewConfig:
+ *
+ *     viewConfig: {
+ *         plugins: { ptype: 'treeviewdragdrop' }
+ *     }
  */
 Ext.define('Ext.tree.plugin.TreeViewDragDrop', {
     extend: 'Ext.AbstractPlugin',
@@ -108138,145 +112585,155 @@ Ext.define('Ext.tree.plugin.TreeViewDragDrop', {
 
     /**
      * @event beforedrop
-     * <p><b>This event is fired through the TreeView. Add listeners to the TreeView object</b></p>
-     * <p>Fired when a drop gesture has been triggered by a mouseup event in a valid drop position in the TreeView.
-     * @param {HtmlElement} node The TreeView node <b>if any</b> over which the mouse was positioned.</p>
-     * <p>Returning <code>false</code> to this event signals that the drop gesture was invalid, and if the drag proxy
-     * will animate back to the point from which the drag began.</p>
-     * <p>Returning <code>0</code> To this event signals that the data transfer operation should not take place, but
-     * that the gesture was valid, and that the repair operation should not take place.</p>
-     * <p>Any other return value continues with the data transfer operation.</p>
-     * @param {Object} data The data object gathered at mousedown time by the cooperating {@link Ext.dd.DragZone DragZone}'s
-     * {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following properties:<ul>
-     * <li>copy : Boolean
-     *  <div class="sub-desc">The value of the TreeView's <code>copy</code> property, or <code>true</code> if the TreeView was configured
-     *  with <code>allowCopy: true</code> and the control key was pressed when the drag operation was begun</div></li>
-     * <li>view : TreeView
-     *  <div class="sub-desc">The source TreeView from which the drag originated.</div></li>
-     * <li>ddel : HtmlElement
-     *  <div class="sub-desc">The drag proxy element which moves with the mouse</div></li>
-     * <li>item : HtmlElement
-     *  <div class="sub-desc">The TreeView node upon which the mousedown event was registered.</div></li>
-     * <li>records : Array
-     *  <div class="sub-desc">An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source TreeView.</div></li>
-     * </ul>
+     *
+     * **This event is fired through the TreeView. Add listeners to the TreeView object**
+     *
+     * Fired when a drop gesture has been triggered by a mouseup event in a valid drop position in the TreeView.
+     *
+     * @param {HTMLElement} node The TreeView node **if any** over which the mouse was positioned.
+     *
+     * Returning `false` to this event signals that the drop gesture was invalid, and if the drag proxy will animate
+     * back to the point from which the drag began.
+     *
+     * Returning `0` To this event signals that the data transfer operation should not take place, but that the gesture
+     * was valid, and that the repair operation should not take place.
+     *
+     * Any other return value continues with the data transfer operation.
+     *
+     * @param {Object} data The data object gathered at mousedown time by the cooperating
+     * {@link Ext.dd.DragZone DragZone}'s {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following
+     * properties:
+     * @param {Boolean} data.copy The value of the TreeView's `copy` property, or `true` if the TreeView was configured with
+     * `allowCopy: true` and the control key was pressed when the drag operation was begun
+     * @param {Ext.tree.View} data.view The source TreeView from which the drag originated.
+     * @param {HTMLElement} data.ddel The drag proxy element which moves with the mouse
+     * @param {HTMLElement} data.item The TreeView node upon which the mousedown event was registered.
+     * @param {Ext.data.Model[]} data.records An Array of {@link Ext.data.Model Model}s representing the selected data being
+     * dragged from the source TreeView.
+     *
      * @param {Ext.data.Model} overModel The Model over which the drop gesture took place.
-     * @param {String} dropPosition <code>"before"</code>, <code>"after"</code> or <code>"append"</code> depending on whether the mouse is above or below the midline of the node,
-     * or the node is a branch node which accepts new child nodes.
-     * @param {Function} dropFunction <p>A function to call to complete the data transfer operation and either move or copy Model instances from the source
-     * View's Store to the destination View's Store.</p>
-     * <p>This is useful when you want to perform some kind of asynchronous processing before confirming
-     * the drop, such as an {@link Ext.window.MessageBox#confirm confirm} call, or an Ajax request.</p>
-     * <p>Return <code>0</code> from this event handler, and call the <code>dropFunction</code> at any time to perform the data transfer.</p>
+     *
+     * @param {String} dropPosition `"before"`, `"after"` or `"append"` depending on whether the mouse is above or below
+     * the midline of the node, or the node is a branch node which accepts new child nodes.
+     *
+     * @param {Function} dropFunction A function to call to complete the data transfer operation and either move or copy
+     * Model instances from the source View's Store to the destination View's Store.
+     *
+     * This is useful when you want to perform some kind of asynchronous processing before confirming the drop, such as
+     * an {@link Ext.window.MessageBox#confirm confirm} call, or an Ajax request.
+     *
+     * Return `0` from this event handler, and call the `dropFunction` at any time to perform the data transfer.
      */
 
     /**
      * @event drop
-     * <b>This event is fired through the TreeView. Add listeners to the TreeView object</b>
-     * Fired when a drop operation has been completed and the data has been moved or copied.
-     * @param {HtmlElement} node The TreeView node <b>if any</b> over which the mouse was positioned.
-     * @param {Object} data The data object gathered at mousedown time by the cooperating {@link Ext.dd.DragZone DragZone}'s
-     * {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following properties:<ul>
-     * <li>copy : Boolean
-     *  <div class="sub-desc">The value of the TreeView's <code>copy</code> property, or <code>true</code> if the TreeView was configured
-     *  with <code>allowCopy: true</code> and the control key was pressed when the drag operation was begun</div></li>
-     * <li>view : TreeView
-     *  <div class="sub-desc">The source TreeView from which the drag originated.</div></li>
-     * <li>ddel : HtmlElement
-     *  <div class="sub-desc">The drag proxy element which moves with the mouse</div></li>
-     * <li>item : HtmlElement
-     *  <div class="sub-desc">The TreeView node upon which the mousedown event was registered.</div></li>
-     * <li>records : Array
-     *  <div class="sub-desc">An Array of {@link Ext.data.Model Model}s representing the selected data being dragged from the source TreeView.</div></li>
-     * </ul>
+     *
+     * **This event is fired through the TreeView. Add listeners to the TreeView object** Fired when a drop operation
+     * has been completed and the data has been moved or copied.
+     *
+     * @param {HTMLElement} node The TreeView node **if any** over which the mouse was positioned.
+     *
+     * @param {Object} data The data object gathered at mousedown time by the cooperating
+     * {@link Ext.dd.DragZone DragZone}'s {@link Ext.dd.DragZone#getDragData getDragData} method it contains the following
+     * properties:
+     * @param {Boolean} data.copy The value of the TreeView's `copy` property, or `true` if the TreeView was configured with
+     * `allowCopy: true` and the control key was pressed when the drag operation was begun
+     * @param {Ext.tree.View} data.view The source TreeView from which the drag originated.
+     * @param {HTMLElement} data.ddel The drag proxy element which moves with the mouse
+     * @param {HTMLElement} data.item The TreeView node upon which the mousedown event was registered.
+     * @param {Ext.data.Model[]} data.records An Array of {@link Ext.data.Model Model}s representing the selected data being
+     * dragged from the source TreeView.
+     *
      * @param {Ext.data.Model} overModel The Model over which the drop gesture took place.
-     * @param {String} dropPosition <code>"before"</code>, <code>"after"</code> or <code>"append"</code> depending on whether the mouse is above or below the midline of the node,
-     * or the node is a branch node which accepts new child nodes.
+     *
+     * @param {String} dropPosition `"before"`, `"after"` or `"append"` depending on whether the mouse is above or below
+     * the midline of the node, or the node is a branch node which accepts new child nodes.
      */
 
     dragText : '{0} selected node{1}',
 
     /**
      * @cfg {Boolean} allowParentInsert
-     * Allow inserting a dragged node between an expanded parent node and its first child that will become a
-     * sibling of the parent when dropped (defaults to false)
+     * Allow inserting a dragged node between an expanded parent node and its first child that will become a sibling of
+     * the parent when dropped.
      */
     allowParentInserts: false,
 
     /**
      * @cfg {String} allowContainerDrop
-     * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
+     * True if drops on the tree container (outside of a specific tree node) are allowed.
      */
     allowContainerDrops: false,
 
     /**
      * @cfg {String} appendOnly
-     * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
+     * True if the tree should only allow append drops (use for trees which are sorted).
      */
     appendOnly: false,
 
     /**
      * @cfg {String} ddGroup
-     * A named drag drop group to which this object belongs.  If a group is specified, then both the DragZones and DropZone
-     * used by this plugin will only interact with other drag drop objects in the same group (defaults to 'TreeDD').
+     * A named drag drop group to which this object belongs. If a group is specified, then both the DragZones and
+     * DropZone used by this plugin will only interact with other drag drop objects in the same group.
      */
     ddGroup : "TreeDD",
 
     /**
      * @cfg {String} dragGroup
-     * <p>The ddGroup to which the DragZone will belong.</p>
-     * <p>This defines which other DropZones the DragZone will interact with. Drag/DropZones only interact with other Drag/DropZones
-     * which are members of the same ddGroup.</p>
+     * The ddGroup to which the DragZone will belong.
+     *
+     * This defines which other DropZones the DragZone will interact with. Drag/DropZones only interact with other
+     * Drag/DropZones which are members of the same ddGroup.
      */
 
     /**
      * @cfg {String} dropGroup
-     * <p>The ddGroup to which the DropZone will belong.</p>
-     * <p>This defines which other DragZones the DropZone will interact with. Drag/DropZones only interact with other Drag/DropZones
-     * which are members of the same ddGroup.</p>
+     * The ddGroup to which the DropZone will belong.
+     *
+     * This defines which other DragZones the DropZone will interact with. Drag/DropZones only interact with other
+     * Drag/DropZones which are members of the same ddGroup.
      */
 
     /**
      * @cfg {String} expandDelay
-     * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
-     * over the target (defaults to 1000)
+     * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node over the
+     * target.
      */
     expandDelay : 1000,
 
     /**
      * @cfg {Boolean} enableDrop
-     * <p>Defaults to <code>true</code></p>
-     * <p>Set to <code>false</code> to disallow the View from accepting drop gestures</p>
+     * Set to `false` to disallow the View from accepting drop gestures.
      */
     enableDrop: true,
 
     /**
      * @cfg {Boolean} enableDrag
-     * <p>Defaults to <code>true</code></p>
-     * <p>Set to <code>false</code> to disallow dragging items from the View </p>
+     * Set to `false` to disallow dragging items from the View.
      */
     enableDrag: true,
-    
+
     /**
-     * @cfg {String} nodeHighlightColor The color to use when visually highlighting the dragged
-     * or dropped node (defaults to 'c3daf9' - light blue). The color must be a 6 digit hex value, without
-     * a preceding '#'. See also {@link #nodeHighlightOnDrop} and {@link #nodeHighlightOnRepair}.
+     * @cfg {String} nodeHighlightColor
+     * The color to use when visually highlighting the dragged or dropped node (default value is light blue).
+     * The color must be a 6 digit hex value, without a preceding '#'. See also {@link #nodeHighlightOnDrop} and
+     * {@link #nodeHighlightOnRepair}.
      */
     nodeHighlightColor: 'c3daf9',
-    
+
     /**
-     * @cfg {Boolean} nodeHighlightOnDrop Whether or not to highlight any nodes after they are
+     * @cfg {Boolean} nodeHighlightOnDrop
+     * Whether or not to highlight any nodes after they are
      * successfully dropped on their target. Defaults to the value of `Ext.enableFx`.
      * See also {@link #nodeHighlightColor} and {@link #nodeHighlightOnRepair}.
-     * @markdown
      */
     nodeHighlightOnDrop: Ext.enableFx,
-    
+
     /**
-     * @cfg {Boolean} nodeHighlightOnRepair Whether or not to highlight any nodes after they are
+     * @cfg {Boolean} nodeHighlightOnRepair
+     * Whether or not to highlight any nodes after they are
      * repaired from an unsuccessful drag/drop. Defaults to the value of `Ext.enableFx`.
      * See also {@link #nodeHighlightColor} and {@link #nodeHighlightOnDrop}.
-     * @markdown
      */
     nodeHighlightOnRepair: Ext.enableFx,
 
@@ -108338,7 +112795,7 @@ Ext.define('Ext.util.Cookies', {
      * for the cookie may be optionally specified (for example: expiration,
      * access restriction, SSL).
      * @param {String} name The name of the cookie to set. 
-     * @param {Mixed} value The value to set for the cookie.
+     * @param {Object} value The value to set for the cookie.
      * @param {Object} expires (Optional) Specify an expiration date the
      * cookie is to persist until.  Note that the specified Date object will
      * be converted to Greenwich Mean Time (GMT). 
@@ -108375,7 +112832,7 @@ Ext.define('Ext.util.Cookies', {
      * var validStatus = Ext.util.Cookies.get("valid");
      * </code></pre>
      * @param {String} name The name of the cookie to get
-     * @return {Mixed} Returns the cookie value for the specified name;
+     * @return {Object} Returns the cookie value for the specified name;
      * null if the cookie name does not exist.
      */
     get : function(name){
@@ -108443,13 +112900,13 @@ Ext.define('Ext.util.CSS', function() {
             this.rules = {};
             this.initialized = false;
         },
+
         /**
          * Creates a stylesheet from a text blob of rules.
          * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
          * @param {String} cssText The text containing the css rules
          * @param {String} id An id to add to the stylesheet for later removal
-         * @return {StyleSheet}
+         * @return {CSSStyleSheet}
          */
         createStyleSheet : function(cssText, id) {
             var ss,
@@ -108528,7 +112985,7 @@ Ext.define('Ext.util.CSS', function() {
                 for (; i >= 0; --i) {
                     selectorText = ssRules[i].selectorText;
                     if (selectorText) {
+
                         // Split in case there are multiple, comma-delimited selectors
                         selectorText = selectorText.split(',');
                         selectors = selectorText.length;
@@ -108557,7 +113014,7 @@ Ext.define('Ext.util.CSS', function() {
                         if (!ds[i].disabled) {
                             this.cacheStyleSheet(ds[i]);
                         }
-                    } catch(e) {} 
+                    } catch(e) {}
                 }
             }
             return rules;
@@ -108565,9 +113022,9 @@ Ext.define('Ext.util.CSS', function() {
 
         /**
          * Gets an an individual CSS rule by selector(s)
-         * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
+         * @param {String/String[]} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
          * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
-         * @return {CSSRule} The CSS rule or null if one is not found
+         * @return {CSSStyleRule} The CSS rule or null if one is not found
          */
         getRule: function(selector, refreshCache) {
             var rs = this.getRules(refreshCache);
@@ -108584,7 +113041,7 @@ Ext.define('Ext.util.CSS', function() {
 
         /**
          * Updates a rule property
-         * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
+         * @param {String/String[]} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
          * @param {String} property The css property
          * @param {String} value The new value for the property
          * @return {Boolean} true If a rule was found and updated
@@ -108609,28 +113066,27 @@ Ext.define('Ext.util.CSS', function() {
 }());
 /**
  * @class Ext.util.History
-
-History management component that allows you to register arbitrary tokens that signify application
-history state on navigation actions.  You can then handle the history {@link #change} event in order
-to reset your application UI to the appropriate state when the user navigates forward or backward through
-the browser history stack.
-
-__Initializing__
-The {@link #init} method of the History object must be called before using History. This sets up the internal
-state and must be the first thing called before using History.
-
-__Setup__
-The History objects requires elements on the page to keep track of the browser history. For older versions of IE,
-an IFrame is required to do the tracking. For other browsers, a hidden field can be used. The history objects expects
-these to be on the page before the {@link #init} method is called. The following markup is suggested in order
-to support all browsers:
-
-    <form id="history-form" class="x-hide-display">
-        <input type="hidden" id="x-history-field" />
-        <iframe id="x-history-frame"></iframe>
-    </form>
-
- * @markdown
+ *
+ * History management component that allows you to register arbitrary tokens that signify application
+ * history state on navigation actions.  You can then handle the history {@link #change} event in order
+ * to reset your application UI to the appropriate state when the user navigates forward or backward through
+ * the browser history stack.
+ *
+ * ## Initializing
+ * The {@link #init} method of the History object must be called before using History. This sets up the internal
+ * state and must be the first thing called before using History.
+ *
+ * ## Setup
+ * The History objects requires elements on the page to keep track of the browser history. For older versions of IE,
+ * an IFrame is required to do the tracking. For other browsers, a hidden field can be used. The history objects expects
+ * these to be on the page before the {@link #init} method is called. The following markup is suggested in order
+ * to support all browsers:
+ *
+ *     <form id="history-form" class="x-hide-display">
+ *         <input type="hidden" id="x-history-field" />
+ *         <iframe id="x-history-frame"></iframe>
+ *     </form>
+ *
  * @singleton
  */
 Ext.define('Ext.util.History', {
@@ -108639,7 +113095,7 @@ Ext.define('Ext.util.History', {
     mixins: {
         observable: 'Ext.util.Observable'
     },
-    
+
     constructor: function() {
         var me = this;
         me.oldIEMode = Ext.isIE6 || Ext.isIE7 || !Ext.isStrict && Ext.isIE8;
@@ -108648,18 +113104,18 @@ Ext.define('Ext.util.History', {
         me.ready = false;
         me.currentToken = null;
     },
-    
+
     getHash: function() {
         var href = window.location.href,
             i = href.indexOf("#");
-            
+
         return i >= 0 ? href.substr(i + 1) : null;
     },
 
     doSave: function() {
         this.hiddenField.value = this.currentToken;
     },
-    
+
 
     handleStateChange: function(token) {
         this.currentToken = token;
@@ -108667,8 +113123,8 @@ Ext.define('Ext.util.History', {
     },
 
     updateIFrame: function(token) {
-        var html = '<html><body><div id="state">' + 
-                    Ext.util.Format.htmlEncode(token) + 
+        var html = '<html><body><div id="state">' +
+                    Ext.util.Format.htmlEncode(token) +
                     '</div></body></html>';
 
         try {
@@ -108685,17 +113141,17 @@ Ext.define('Ext.util.History', {
     checkIFrame: function () {
         var me = this,
             contentWindow = me.iframe.contentWindow;
-            
+
         if (!contentWindow || !contentWindow.document) {
             Ext.Function.defer(this.checkIFrame, 10, this);
             return;
         }
-       
+
         var doc = contentWindow.document,
             elem = doc.getElementById("state"),
             oldToken = elem ? elem.innerText : null,
             oldHash = me.getHash();
-           
+
         Ext.TaskManager.start({
             run: function () {
                 var doc = contentWindow.document,
@@ -108713,17 +113169,17 @@ Ext.define('Ext.util.History', {
                     oldHash = newHash;
                     me.updateIFrame(newHash);
                 }
-            }, 
+            },
             interval: 50,
             scope: me
         });
         me.ready = true;
-        me.fireEvent('ready', me);            
+        me.fireEvent('ready', me);
     },
 
     startUp: function () {
         var me = this;
-        
+
         me.currentToken = me.hiddenField.value || this.getHash();
 
         if (me.oldIEMode) {
@@ -108745,7 +113201,7 @@ Ext.define('Ext.util.History', {
             me.ready = true;
             me.fireEvent('ready', me);
         }
-        
+
     },
 
     /**
@@ -108765,29 +113221,29 @@ Ext.define('Ext.util.History', {
      * Initialize the global History instance.
      * @param {Boolean} onReady (optional) A callback function that will be called once the history
      * component is fully initialized.
-     * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the callback is executed. Defaults to the browser window.
+     * @param {Object} scope (optional) The scope (`this` reference) in which the callback is executed. Defaults to the browser window.
      */
     init: function (onReady, scope) {
         var me = this;
-        
+
         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.oldIEMode) {
             me.iframe = Ext.getDom(me.iframeId);
         }
-        
+
         me.addEvents(
             /**
              * @event ready
@@ -108802,7 +113258,7 @@ Ext.define('Ext.util.History', {
              */
             'change'
         );
-        
+
         if (onReady) {
             me.on('ready', onReady, scope, {single: true});
         }
@@ -108811,28 +113267,28 @@ Ext.define('Ext.util.History', {
 
     /**
      * Add a new token to the history stack. This can be any arbitrary value, although it would
-     * commonly be the concatenation of a component id and another id marking the specifc history
-     * state of that component.  Example usage:
-     * <pre><code>
-// Handle tab changes on a TabPanel
-tabPanel.on('tabchange', function(tabPanel, tab){
-Ext.History.add(tabPanel.id + ':' + tab.id);
-});
-</code></pre>
+     * commonly be the concatenation of a component id and another id marking the specific history
+     * state of that component. Example usage:
+     *
+     *     // Handle tab changes on a TabPanel
+     *     tabPanel.on('tabchange', function(tabPanel, tab){
+     *          Ext.History.add(tabPanel.id + ':' + tab.id);
+     *     });
+     *
      * @param {String} token The value that defines a particular application-specific history state
-     * @param {Boolean} preventDuplicates When true, if the passed token matches the current token
+     * @param {Boolean} [preventDuplicates=true] When true, if the passed token matches the current token
      * it will not save a new history step. Set to false if the same state can be saved more than once
-     * at the same history stack location (defaults to true).
+     * at the same history stack location.
      */
     add: function (token, preventDup) {
         var me = this;
-        
+
         if (preventDup !== false) {
             if (me.getToken() === token) {
                 return true;
             }
         }
-        
+
         if (me.oldIEMode) {
             return me.updateIFrame(token);
         } else {