docs/src/Roo_bootstrap_Card.js.html
[roojs1] / roojs-debug.js
index 5602bf3..7c8eec2 100644 (file)
@@ -16004,2553 +16004,3010 @@ Roo.extend(Roo.BoxComponent, Roo.Component, {
         return {x : x, y: y};
     }
 });/*
- * Original code for Roojs - LGPL
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
  * <script type="text/javascript">
  */
+ (function(){ 
 /**
- * @class Roo.XComponent
- * A delayed Element creator...
- * Or a way to group chunks of interface together.
- * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
- *  used in conjunction with XComponent.build() it will create an instance of each element,
- *  then call addxtype() to build the User interface.
- * 
- * Mypart.xyx = new Roo.XComponent({
-
-    parent : 'Mypart.xyz', // empty == document.element.!!
-    order : '001',
-    name : 'xxxx'
-    region : 'xxxx'
-    disabled : function() {} 
-     
-    tree : function() { // return an tree of xtype declared components
-        var MODULE = this;
-        return 
-        {
-            xtype : 'NestedLayoutPanel',
-            // technicall
-        }
-     ]
- *})
- *
- *
- * It can be used to build a big heiracy, with parent etc.
- * or you can just use this to render a single compoent to a dom element
- * MYPART.render(Roo.Element | String(id) | dom_element )
- *
- *
- * Usage patterns.
- *
- * Classic Roo
- *
- * Roo is designed primarily as a single page application, so the UI build for a standard interface will
- * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
- *
- * Each sub module is expected to have a parent pointing to the class name of it's parent module.
- *
- * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
- * - if mulitple topModules exist, the last one is defined as the top module.
- *
- * Embeded Roo
- * 
- * When the top level or multiple modules are to embedded into a existing HTML page,
- * the parent element can container '#id' of the element where the module will be drawn.
- *
- * Bootstrap Roo
- *
- * Unlike classic Roo, the bootstrap tends not to be used as a single page.
- * it relies more on a include mechanism, where sub modules are included into an outer page.
- * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
- * 
- * Bootstrap Roo Included elements
- *
- * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
- * hence confusing the component builder as it thinks there are multiple top level elements. 
- *
- * String Over-ride & Translations
- *
- * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
- * and also the 'overlaying of string values - needed when different versions of the same application with different text content
- * are needed. @see Roo.XComponent.overlayString  
- * 
- * 
- * 
- * @extends Roo.util.Observable
+ * @class Roo.Layer
+ * @extends Roo.Element
+ * An extended {@link Roo.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 create a shadow element with default class "x-layer-shadow", or
+ * you can pass a string with a CSS class name. False turns off the shadow.
+ * @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 3)
  * @constructor
- * @param cfg {Object} configuration of component
- * 
+ * @param {Object} config An object with config options.
+ * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
  */
-Roo.XComponent = function(cfg) {
-    Roo.apply(this, cfg);
-    this.addEvents({ 
-        /**
-            * @event built
-            * Fires when this the componnt is built
-            * @param {Roo.XComponent} c the component
-            */
-        'built' : true
-        
-    });
-    this.region = this.region || 'center'; // default..
-    Roo.XComponent.register(this);
-    this.modules = false;
-    this.el = false; // where the layout goes..
-    
-    
-}
-Roo.extend(Roo.XComponent, Roo.util.Observable, {
-    /**
-     * @property el
-     * The created element (with Roo.factory())
-     * @type {Roo.Layout}
-     */
-    el  : false,
-    
-    /**
-     * @property el
-     * for BC  - use el in new code
-     * @type {Roo.Layout}
-     */
-    panel : false,
-    
-    /**
-     * @property layout
-     * for BC  - use el in new code
-     * @type {Roo.Layout}
-     */
-    layout : false,
-    
-     /**
-     * @cfg {Function|boolean} disabled
-     * If this module is disabled by some rule, return true from the funtion
-     */
-    disabled : false,
-    
-    /**
-     * @cfg {String} parent 
-     * Name of parent element which it get xtype added to..
-     */
-    parent: false,
-    
-    /**
-     * @cfg {String} order
-     * Used to set the order in which elements are created (usefull for multiple tabs)
-     */
-    
-    order : false,
-    /**
-     * @cfg {String} name
-     * String to display while loading.
-     */
-    name : false,
-    /**
-     * @cfg {String} region
-     * Region to render component to (defaults to center)
-     */
-    region : 'center',
-    
-    /**
-     * @cfg {Array} items
-     * A single item array - the first element is the root of the tree..
-     * It's done this way to stay compatible with the Xtype system...
-     */
-    items : false,
-    
-    /**
-     * @property _tree
-     * The method that retuns the tree of parts that make up this compoennt 
-     * @type {function}
-     */
-    _tree  : false,
-    
-     /**
-     * render
-     * render element to dom or tree
-     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
-     */
-    
-    render : function(el)
-    {
-        
-        el = el || false;
-        var hp = this.parent ? 1 : 0;
-        Roo.debug &&  Roo.log(this);
-        
-        var tree = this._tree ? this._tree() : this.tree();
 
-        
-        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
-            // if parent is a '#.....' string, then let's use that..
-            var ename = this.parent.substr(1);
-            this.parent = false;
-            Roo.debug && Roo.log(ename);
-            switch (ename) {
-                case 'bootstrap-body':
-                    if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
-                        // this is the BorderLayout standard?
-                       this.parent = { el : true };
-                       break;
-                    }
-                    if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
-                        // need to insert stuff...
-                        this.parent =  {
-                             el : new Roo.bootstrap.layout.Border({
-                                 el : document.body, 
-                     
-                                 center: {
-                                    titlebar: false,
-                                    autoScroll:false,
-                                    closeOnTab: true,
-                                    tabPosition: 'top',
-                                      //resizeTabs: true,
-                                    alwaysShowTabs: true,
-                                    hideTabs: false
-                                     //minTabWidth: 140
-                                 }
-                             })
-                        
-                         };
-                         break;
-                    }
-                         
-                    if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
-                        this.parent = { el :  new  Roo.bootstrap.Body() };
-                        Roo.debug && Roo.log("setting el to doc body");
-                         
-                    } else {
-                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
-                    }
-                    break;
-                case 'bootstrap':
-                    this.parent = { el : true};
-                    // fall through
-                default:
-                    el = Roo.get(ename);
-                    if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
-                        this.parent = { el : true};
-                    }
-                    
-                    break;
-            }
-                
-            
-            if (!el && !this.parent) {
-                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
-                return;
-            }
-        }
-        
-        Roo.debug && Roo.log("EL:");
-        Roo.debug && Roo.log(el);
-        Roo.debug && Roo.log("this.parent.el:");
-        Roo.debug && Roo.log(this.parent.el);
-        
+Roo.Layer = function(config, existingEl){
+    config = config || {};
+    var dh = Roo.DomHelper;
+    var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
+    if(existingEl){
+        this.dom = Roo.getDom(existingEl);
+    }
+    if(!this.dom){
+        var o = config.dh || {tag: "div", cls: "x-layer"};
+        this.dom = dh.append(pel, o);
+    }
+    if(config.cls){
+        this.addClass(config.cls);
+    }
+    this.constrain = config.constrain !== false;
+    this.visibilityMode = Roo.Element.VISIBILITY;
+    if(config.id){
+        this.id = this.dom.id = config.id;
+    }else{
+        this.id = Roo.id(this.dom);
+    }
+    this.zindex = config.zindex || this.getZIndex();
+    this.position("absolute", this.zindex);
+    if(config.shadow){
+        this.shadowOffset = config.shadowOffset || 4;
+        this.shadow = new Roo.Shadow({
+            offset : this.shadowOffset,
+            mode : config.shadow
+        });
+    }else{
+        this.shadowOffset = 0;
+    }
+    this.useShim = config.shim !== false && Roo.useShims;
+    this.useDisplay = config.useDisplay;
+    this.hide();
+};
 
-        // altertive root elements ??? - we need a better way to indicate these.
-        var is_alt = Roo.XComponent.is_alt ||
-                    (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
-                    (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
-                    (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
-        
-        
-        
-        if (!this.parent && is_alt) {
-            //el = Roo.get(document.body);
-            this.parent = { el : true };
+var supr = Roo.Element.prototype;
+
+// shims are shared among layer to keep from having 100 iframes
+var shims = [];
+
+Roo.extend(Roo.Layer, Roo.Element, {
+
+    getZIndex : function(){
+        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
+    },
+
+    getShim : function(){
+        if(!this.useShim){
+            return null;
         }
-            
-            
-        
-        if (!this.parent) {
-            
-            Roo.debug && Roo.log("no parent - creating one");
-            
-            el = el ? Roo.get(el) : false;     
-            
-            if (typeof(Roo.BorderLayout) == 'undefined' ) {
-                
-                this.parent =  {
-                    el : new Roo.bootstrap.layout.Border({
-                        el: el || document.body,
-                    
-                        center: {
-                            titlebar: false,
-                            autoScroll:false,
-                            closeOnTab: true,
-                            tabPosition: 'top',
-                             //resizeTabs: true,
-                            alwaysShowTabs: false,
-                            hideTabs: true,
-                            minTabWidth: 140,
-                            overflow: 'visible'
-                         }
-                     })
-                };
-            } else {
-            
-                // it's a top level one..
-                this.parent =  {
-                    el : new Roo.BorderLayout(el || document.body, {
-                        center: {
-                            titlebar: false,
-                            autoScroll:false,
-                            closeOnTab: true,
-                            tabPosition: 'top',
-                             //resizeTabs: true,
-                            alwaysShowTabs: el && hp? false :  true,
-                            hideTabs: el || !hp ? true :  false,
-                            minTabWidth: 140
-                         }
-                    })
-                };
-            }
+        if(this.shim){
+            return this.shim;
         }
-        
-        if (!this.parent.el) {
-                // probably an old style ctor, which has been disabled.
-                return;
-
+        var shim = shims.shift();
+        if(!shim){
+            shim = this.createShim();
+            shim.enableDisplayMode('block');
+            shim.dom.style.display = 'none';
+            shim.dom.style.visibility = 'visible';
         }
-               // The 'tree' method is  '_tree now' 
-            
-        tree.region = tree.region || this.region;
-        var is_body = false;
-        if (this.parent.el === true) {
-            // bootstrap... - body..
-            if (el) {
-                tree.el = el;
-            }
-            this.parent.el = Roo.factory(tree);
-            is_body = true;
+        var pn = this.dom.parentNode;
+        if(shim.dom.parentNode != pn){
+            pn.insertBefore(shim.dom, this.dom);
         }
-        
-        this.el = this.parent.el.addxtype(tree, undefined, is_body);
-        this.fireEvent('built', this);
-        
-        this.panel = this.el;
-        this.layout = this.panel.layout;
-        this.parentLayout = this.parent.layout  || false;  
-         
-    }
-    
-});
-
-Roo.apply(Roo.XComponent, {
-    /**
-     * @property  hideProgress
-     * true to disable the building progress bar.. usefull on single page renders.
-     * @type Boolean
-     */
-    hideProgress : false,
-    /**
-     * @property  buildCompleted
-     * True when the builder has completed building the interface.
-     * @type Boolean
-     */
-    buildCompleted : false,
-     
-    /**
-     * @property  topModule
-     * the upper most module - uses document.element as it's constructor.
-     * @type Object
-     */
-     
-    topModule  : false,
-      
-    /**
-     * @property  modules
-     * array of modules to be created by registration system.
-     * @type {Array} of Roo.XComponent
-     */
-    
-    modules : [],
-    /**
-     * @property  elmodules
-     * array of modules to be created by which use #ID 
-     * @type {Array} of Roo.XComponent
-     */
-     
-    elmodules : [],
+        shim.setStyle('z-index', this.getZIndex()-2);
+        this.shim = shim;
+        return shim;
+    },
 
-     /**
-     * @property  is_alt
-     * Is an alternative Root - normally used by bootstrap or other systems,
-     *    where the top element in the tree can wrap 'body' 
-     * @type {boolean}  (default false)
-     */
-     
-    is_alt : false,
-    /**
-     * @property  build_from_html
-     * Build elements from html - used by bootstrap HTML stuff 
-     *    - this is cleared after build is completed
-     * @type {boolean}    (default false)
-     */
-     
-    build_from_html : false,
-    /**
-     * Register components to be built later.
-     *
-     * This solves the following issues
-     * - Building is not done on page load, but after an authentication process has occured.
-     * - Interface elements are registered on page load
-     * - Parent Interface elements may not be loaded before child, so this handles that..
-     * 
-     *
-     * example:
-     * 
-     * MyApp.register({
-          order : '000001',
-          module : 'Pman.Tab.projectMgr',
-          region : 'center',
-          parent : 'Pman.layout',
-          disabled : false,  // or use a function..
-        })
-     
-     * * @param {Object} details about module
-     */
-    register : function(obj) {
-               
-        Roo.XComponent.event.fireEvent('register', obj);
-        switch(typeof(obj.disabled) ) {
-                
-            case 'undefined':
-                break;
-            
-            case 'function':
-                if ( obj.disabled() ) {
-                        return;
-                }
-                break;
-            
-            default:
-                if (obj.disabled || obj.region == '#disabled') {
-                        return;
-                }
-                break;
+    hideShim : function(){
+        if(this.shim){
+            this.shim.setDisplayed(false);
+            shims.push(this.shim);
+            delete this.shim;
         }
-               
-        this.modules.push(obj);
-         
     },
-    /**
-     * convert a string to an object..
-     * eg. 'AAA.BBB' -> finds AAA.BBB
 
-     */
-    
-    toObject : function(str)
-    {
-        if (!str || typeof(str) == 'object') {
-            return str;
-        }
-        if (str.substring(0,1) == '#') {
-            return str;
+    disableShadow : function(){
+        if(this.shadow){
+            this.shadowDisabled = true;
+            this.shadow.hide();
+            this.lastShadowOffset = this.shadowOffset;
+            this.shadowOffset = 0;
         }
+    },
 
-        var ar = str.split('.');
-        var rt, o;
-        rt = ar.shift();
-            /** eval:var:o */
-        try {
-            eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
-        } catch (e) {
-            throw "Module not found : " + str;
-        }
-        
-        if (o === false) {
-            throw "Module not found : " + str;
-        }
-        Roo.each(ar, function(e) {
-            if (typeof(o[e]) == 'undefined') {
-                throw "Module not found : " + str;
+    enableShadow : function(show){
+        if(this.shadow){
+            this.shadowDisabled = false;
+            this.shadowOffset = this.lastShadowOffset;
+            delete this.lastShadowOffset;
+            if(show){
+                this.sync(true);
             }
-            o = o[e];
-        });
-        
-        return o;
-        
+        }
     },
-    
-    
-    /**
-     * move modules into their correct place in the tree..
-     * 
-     */
-    preBuild : function ()
-    {
-        var _t = this;
-        Roo.each(this.modules , function (obj)
-        {
-            Roo.XComponent.event.fireEvent('beforebuild', obj);
-            
-            var opar = obj.parent;
-            try { 
-                obj.parent = this.toObject(opar);
-            } catch(e) {
-                Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
-                return;
+
+    // private
+    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
+    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
+    sync : function(doShow){
+        var sw = this.shadow;
+        if(!this.updating && this.isVisible() && (sw || this.useShim)){
+            var sh = this.getShim();
+
+            var w = this.getWidth(),
+                h = this.getHeight();
+
+            var l = this.getLeft(true),
+                t = this.getTop(true);
+
+            if(sw && !this.shadowDisabled){
+                if(doShow && !sw.isVisible()){
+                    sw.show(this);
+                }else{
+                    sw.realign(l, t, w, h);
+                }
+                if(sh){
+                    if(doShow){
+                       sh.show();
+                    }
+                    // fit the shim behind the shadow, so it is shimmed too
+                    var a = sw.adjusts, s = sh.dom.style;
+                    s.left = (Math.min(l, l+a.l))+"px";
+                    s.top = (Math.min(t, t+a.t))+"px";
+                    s.width = (w+a.w)+"px";
+                    s.height = (h+a.h)+"px";
+                }
+            }else if(sh){
+                if(doShow){
+                   sh.show();
+                }
+                sh.setSize(w, h);
+                sh.setLeftTop(l, t);
             }
             
-            if (!obj.parent) {
-                Roo.debug && Roo.log("GOT top level module");
-                Roo.debug && Roo.log(obj);
-                obj.modules = new Roo.util.MixedCollection(false, 
-                    function(o) { return o.order + '' }
-                );
-                this.topModule = obj;
-                return;
+        }
+    },
+
+    // private
+    destroy : function(){
+        this.hideShim();
+        if(this.shadow){
+            this.shadow.hide();
+        }
+        this.removeAllListeners();
+        var pn = this.dom.parentNode;
+        if(pn){
+            pn.removeChild(this.dom);
+        }
+        Roo.Element.uncache(this.id);
+    },
+
+    remove : function(){
+        this.destroy();
+    },
+
+    // private
+    beginUpdate : function(){
+        this.updating = true;
+    },
+
+    // private
+    endUpdate : function(){
+        this.updating = false;
+        this.sync(true);
+    },
+
+    // private
+    hideUnders : function(negOffset){
+        if(this.shadow){
+            this.shadow.hide();
+        }
+        this.hideShim();
+    },
+
+    // private
+    constrainXY : function(){
+        if(this.constrain){
+            var vw = Roo.lib.Dom.getViewWidth(),
+                vh = Roo.lib.Dom.getViewHeight();
+            var s = Roo.get(document).getScroll();
+
+            var xy = this.getXY();
+            var x = xy[0], y = xy[1];   
+            var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
+            // only move it if it needs it
+            var moved = false;
+            // first validate right/bottom
+            if((x + w) > vw+s.left){
+                x = vw - w - this.shadowOffset;
+                moved = true;
             }
-                       // parent is a string (usually a dom element name..)
-            if (typeof(obj.parent) == 'string') {
-                this.elmodules.push(obj);
-                return;
+            if((y + h) > vh+s.top){
+                y = vh - h - this.shadowOffset;
+                moved = true;
             }
-            if (obj.parent.constructor != Roo.XComponent) {
-                Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
+            // then make sure top/left isn't negative
+            if(x < s.left){
+                x = s.left;
+                moved = true;
             }
-            if (!obj.parent.modules) {
-                obj.parent.modules = new Roo.util.MixedCollection(false, 
-                    function(o) { return o.order + '' }
-                );
+            if(y < s.top){
+                y = s.top;
+                moved = true;
             }
-            if (obj.parent.disabled) {
-                obj.disabled = true;
+            if(moved){
+                if(this.avoidY){
+                    var ay = this.avoidY;
+                    if(y <= ay && (y+h) >= ay){
+                        y = ay-h-5;   
+                    }
+                }
+                xy = [x, y];
+                this.storeXY(xy);
+                supr.setXY.call(this, xy);
+                this.sync();
             }
-            obj.parent.modules.add(obj);
-        }, this);
+        }
     },
-    
-     /**
-     * make a list of modules to build.
-     * @return {Array} list of modules. 
-     */ 
-    
-    buildOrder : function()
-    {
-        var _this = this;
-        var cmp = function(a,b) {   
-            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
-        };
-        if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
-            throw "No top level modules to build";
+
+    isVisible : function(){
+        return this.visible;    
+    },
+
+    // private
+    showAction : function(){
+        this.visible = true; // track visibility to prevent getStyle calls
+        if(this.useDisplay === true){
+            this.setDisplayed("");
+        }else if(this.lastXY){
+            supr.setXY.call(this, this.lastXY);
+        }else if(this.lastLT){
+            supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
         }
-        
-        // make a flat list in order of modules to build.
-        var mods = this.topModule ? [ this.topModule ] : [];
-               
-        
-       // elmodules (is a list of DOM based modules )
-        Roo.each(this.elmodules, function(e) {
-            mods.push(e);
-            if (!this.topModule &&
-                typeof(e.parent) == 'string' &&
-                e.parent.substring(0,1) == '#' &&
-                Roo.get(e.parent.substr(1))
-               ) {
-                
-                _this.topModule = e;
-            }
-            
-        });
+    },
 
-        
-        // add modules to their parents..
-        var addMod = function(m) {
-            Roo.debug && Roo.log("build Order: add: " + m.name);
-                
-            mods.push(m);
-            if (m.modules && !m.disabled) {
-                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
-                m.modules.keySort('ASC',  cmp );
-                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
-    
-                m.modules.each(addMod);
-            } else {
-                Roo.debug && Roo.log("build Order: no child modules");
-            }
-            // not sure if this is used any more..
-            if (m.finalize) {
-                m.finalize.name = m.name + " (clean up) ";
-                mods.push(m.finalize);
-            }
-            
+    // private
+    hideAction : function(){
+        this.visible = false;
+        if(this.useDisplay === true){
+            this.setDisplayed(false);
+        }else{
+            this.setLeftTop(-10000,-10000);
         }
-        if (this.topModule && this.topModule.modules) { 
-            this.topModule.modules.keySort('ASC',  cmp );
-            this.topModule.modules.each(addMod);
-        } 
-        return mods;
     },
-    
-     /**
-     * Build the registered modules.
-     * @param {Object} parent element.
-     * @param {Function} optional method to call after module has been added.
-     * 
-     */ 
-   
-    build : function(opts) 
-    {
-        
-        if (typeof(opts) != 'undefined') {
-            Roo.apply(this,opts);
-        }
-        
-        this.preBuild();
-        var mods = this.buildOrder();
-      
-        //this.allmods = mods;
-        //Roo.debug && Roo.log(mods);
-        //return;
-        if (!mods.length) { // should not happen
-            throw "NO modules!!!";
-        }
-        
-        
-        var msg = "Building Interface...";
-        // flash it up as modal - so we store the mask!?
-        if (!this.hideProgress && Roo.MessageBox) {
-            Roo.MessageBox.show({ title: 'loading' });
-            Roo.MessageBox.show({
-               title: "Please wait...",
-               msg: msg,
-               width:450,
-               progress:true,
-              buttons : false,
-               closable:false,
-               modal: false
-              
-            });
+
+    // overridden Element method
+    setVisible : function(v, a, d, c, e){
+        if(v){
+            this.showAction();
         }
-        var total = mods.length;
-        
-        var _this = this;
-        var progressRun = function() {
-            if (!mods.length) {
-                Roo.debug && Roo.log('hide?');
-                if (!this.hideProgress && Roo.MessageBox) {
-                    Roo.MessageBox.hide();
+        if(a && v){
+            var cb = function(){
+                this.sync(true);
+                if(c){
+                    c();
                 }
-                Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
-                
-                Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
-                
-                // THE END...
-                return false;   
-            }
-            
-            var m = mods.shift();
-            
-            
-            Roo.debug && Roo.log(m);
-            // not sure if this is supported any more.. - modules that are are just function
-            if (typeof(m) == 'function') { 
-                m.call(this);
-                return progressRun.defer(10, _this);
-            } 
-            
-            
-            msg = "Building Interface " + (total  - mods.length) + 
-                    " of " + total + 
-                    (m.name ? (' - ' + m.name) : '');
-                       Roo.debug && Roo.log(msg);
-            if (!_this.hideProgress &&  Roo.MessageBox) { 
-                Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
+            }.createDelegate(this);
+            supr.setVisible.call(this, true, true, d, cb, e);
+        }else{
+            if(!v){
+                this.hideUnders(true);
             }
-            
-         
-            // is the module disabled?
-            var disabled = (typeof(m.disabled) == 'function') ?
-                m.disabled.call(m.module.disabled) : m.disabled;    
-            
-            
-            if (disabled) {
-                return progressRun(); // we do not update the display!
+            var cb = c;
+            if(a){
+                cb = function(){
+                    this.hideAction();
+                    if(c){
+                        c();
+                    }
+                }.createDelegate(this);
             }
-            
-            // now build 
-            
-                       
-                       
-            m.render();
-            // it's 10 on top level, and 1 on others??? why...
-            return progressRun.defer(10, _this);
-             
-        }
-        progressRun.defer(1, _this);
-     
-        
-        
-    },
-    /**
-     * Overlay a set of modified strings onto a component
-     * This is dependant on our builder exporting the strings and 'named strings' elements.
-     * 
-     * @param {Object} element to overlay on - eg. Pman.Dialog.Login
-     * @param {Object} associative array of 'named' string and it's new value.
-     * 
-     */
-       overlayStrings : function( component, strings )
-    {
-        if (typeof(component['_named_strings']) == 'undefined') {
-            throw "ERROR: component does not have _named_strings";
-        }
-        for ( var k in strings ) {
-            var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
-            if (md !== false) {
-                component['_strings'][md] = strings[k];
-            } else {
-                Roo.log('could not find named string: ' + k + ' in');
-                Roo.log(component);
+            supr.setVisible.call(this, v, a, d, cb, e);
+            if(v){
+                this.sync(true);
+            }else if(!a){
+                this.hideAction();
             }
-            
         }
-        
     },
-    
-       
-       /**
-        * Event Object.
-        *
-        *
-        */
-       event: false, 
-    /**
-        * wrapper for event.on - aliased later..  
-        * Typically use to register a event handler for register:
-        *
-        * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
-        *
-        */
-    on : false
-   
-    
-    
-});
 
-Roo.XComponent.event = new Roo.util.Observable({
-               events : { 
-                       /**
-                        * @event register
-                        * Fires when an Component is registered,
-                        * set the disable property on the Component to stop registration.
-                        * @param {Roo.XComponent} c the component being registerd.
-                        * 
-                        */
-                       'register' : true,
-            /**
-                        * @event beforebuild
-                        * Fires before each Component is built
-                        * can be used to apply permissions.
-                        * @param {Roo.XComponent} c the component being registerd.
-                        * 
-                        */
-                       'beforebuild' : true,
-                       /**
-                        * @event buildcomplete
-                        * Fires on the top level element when all elements have been built
-                        * @param {Roo.XComponent} the top level component.
-                        */
-                       'buildcomplete' : true
-                       
-               }
-});
+    storeXY : function(xy){
+        delete this.lastLT;
+        this.lastXY = xy;
+    },
 
-Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
- //
- /**
- * marked - a markdown parser
- * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
- * https://github.com/chjj/marked
- */
+    storeLeftTop : function(left, top){
+        delete this.lastXY;
+        this.lastLT = [left, top];
+    },
 
+    // private
+    beforeFx : function(){
+        this.beforeAction();
+        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    },
 
-/**
- *
- * Roo.Markdown - is a very crude wrapper around marked..
- *
- * usage:
- * 
- * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
- * 
- * Note: move the sample code to the bottom of this
- * file before uncommenting it.
- *
- */
+    // private
+    afterFx : function(){
+        Roo.Layer.superclass.afterFx.apply(this, arguments);
+        this.sync(this.isVisible());
+    },
 
-Roo.Markdown = {};
-Roo.Markdown.toHtml = function(text) {
-    
-    var c = new Roo.Markdown.marked.setOptions({
-            renderer: new Roo.Markdown.marked.Renderer(),
-            gfm: true,
-            tables: true,
-            breaks: false,
-            pedantic: false,
-            sanitize: false,
-            smartLists: true,
-            smartypants: false
-          });
-    // A FEW HACKS!!?
-    
-    text = text.replace(/\\\n/g,' ');
-    return Roo.Markdown.marked(text);
-};
-//
-// converter
-//
-// Wraps all "globals" so that the only thing
-// exposed is makeHtml().
-//
-(function() {
-    
-     /**
-         * eval:var:escape
-         * eval:var:unescape
-         * eval:var:replace
-         */
-      
-    /**
-     * Helpers
-     */
-    
-    var escape = function (html, encode) {
-      return html
-        .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
-        .replace(/</g, '&lt;')
-        .replace(/>/g, '&gt;')
-        .replace(/"/g, '&quot;')
-        .replace(/'/g, '&#39;');
-    }
-    
-    var unescape = function (html) {
-        // explicitly match decimal, hex, and named HTML entities 
-      return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
-        n = n.toLowerCase();
-        if (n === 'colon') { return ':'; }
-        if (n.charAt(0) === '#') {
-          return n.charAt(1) === 'x'
-            ? String.fromCharCode(parseInt(n.substring(2), 16))
-            : String.fromCharCode(+n.substring(1));
+    // private
+    beforeAction : function(){
+        if(!this.updating && this.shadow){
+            this.shadow.hide();
         }
-        return '';
-      });
-    }
-    
-    var replace = function (regex, opt) {
-      regex = regex.source;
-      opt = opt || '';
-      return function self(name, val) {
-        if (!name) { return new RegExp(regex, opt); }
-        val = val.source || val;
-        val = val.replace(/(^|[^\[])\^/g, '$1');
-        regex = regex.replace(name, val);
-        return self;
-      };
-    }
+    },
 
+    // overridden Element method
+    setLeft : function(left){
+        this.storeLeftTop(left, this.getTop(true));
+        supr.setLeft.apply(this, arguments);
+        this.sync();
+    },
 
-         /**
-         * eval:var:noop
-    */
-    var noop = function () {}
-    noop.exec = noop;
-    
-         /**
-         * eval:var:merge
-    */
-    var merge = function (obj) {
-      var i = 1
-        , target
-        , key;
-    
-      for (; i < arguments.length; i++) {
-        target = arguments[i];
-        for (key in target) {
-          if (Object.prototype.hasOwnProperty.call(target, key)) {
-            obj[key] = target[key];
-          }
+    setTop : function(top){
+        this.storeLeftTop(this.getLeft(true), top);
+        supr.setTop.apply(this, arguments);
+        this.sync();
+    },
+
+    setLeftTop : function(left, top){
+        this.storeLeftTop(left, top);
+        supr.setLeftTop.apply(this, arguments);
+        this.sync();
+    },
+
+    setXY : function(xy, a, d, c, e){
+        this.fixDisplay();
+        this.beforeAction();
+        this.storeXY(xy);
+        var cb = this.createCB(c);
+        supr.setXY.call(this, xy, a, d, cb, e);
+        if(!a){
+            cb();
         }
-      }
-    
-      return obj;
-    }
-    
+    },
+
+    // private
+    createCB : function(c){
+        var el = this;
+        return function(){
+            el.constrainXY();
+            el.sync(true);
+            if(c){
+                c();
+            }
+        };
+    },
+
+    // overridden Element method
+    setX : function(x, a, d, c, e){
+        this.setXY([x, this.getY()], a, d, c, e);
+    },
+
+    // overridden Element method
+    setY : function(y, a, d, c, e){
+        this.setXY([this.getX(), y], a, d, c, e);
+    },
+
+    // overridden Element method
+    setSize : function(w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setSize.call(this, w, h, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setWidth : function(w, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setWidth.call(this, w, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setHeight : function(h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setHeight.call(this, h, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setBounds : function(x, y, w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        if(!a){
+            this.storeXY([x, y]);
+            supr.setXY.call(this, [x, y]);
+            supr.setSize.call(this, w, h, a, d, cb, e);
+            cb();
+        }else{
+            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
+        }
+        return this;
+    },
     
     /**
-     * Block-Level Grammar
+     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
+     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
+     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
+     * @param {Number} zindex The new z-index to set
+     * @return {this} The Layer
      */
+    setZIndex : function(zindex){
+        this.zindex = zindex;
+        this.setStyle("z-index", zindex + 2);
+        if(this.shadow){
+            this.shadow.setZIndex(zindex + 1);
+        }
+        if(this.shim){
+            this.shim.setStyle("z-index", zindex);
+        }
+    }
+});
+})();/*
+ * Original code for Roojs - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.XComponent
+ * A delayed Element creator...
+ * Or a way to group chunks of interface together.
+ * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
+ *  used in conjunction with XComponent.build() it will create an instance of each element,
+ *  then call addxtype() to build the User interface.
+ * 
+ * Mypart.xyx = new Roo.XComponent({
+
+    parent : 'Mypart.xyz', // empty == document.element.!!
+    order : '001',
+    name : 'xxxx'
+    region : 'xxxx'
+    disabled : function() {} 
+     
+    tree : function() { // return an tree of xtype declared components
+        var MODULE = this;
+        return 
+        {
+            xtype : 'NestedLayoutPanel',
+            // technicall
+        }
+     ]
+ *})
+ *
+ *
+ * It can be used to build a big heiracy, with parent etc.
+ * or you can just use this to render a single compoent to a dom element
+ * MYPART.render(Roo.Element | String(id) | dom_element )
+ *
+ *
+ * Usage patterns.
+ *
+ * Classic Roo
+ *
+ * Roo is designed primarily as a single page application, so the UI build for a standard interface will
+ * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
+ *
+ * Each sub module is expected to have a parent pointing to the class name of it's parent module.
+ *
+ * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
+ * - if mulitple topModules exist, the last one is defined as the top module.
+ *
+ * Embeded Roo
+ * 
+ * When the top level or multiple modules are to embedded into a existing HTML page,
+ * the parent element can container '#id' of the element where the module will be drawn.
+ *
+ * Bootstrap Roo
+ *
+ * Unlike classic Roo, the bootstrap tends not to be used as a single page.
+ * it relies more on a include mechanism, where sub modules are included into an outer page.
+ * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
+ * 
+ * Bootstrap Roo Included elements
+ *
+ * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
+ * hence confusing the component builder as it thinks there are multiple top level elements. 
+ *
+ * String Over-ride & Translations
+ *
+ * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
+ * and also the 'overlaying of string values - needed when different versions of the same application with different text content
+ * are needed. @see Roo.XComponent.overlayString  
+ * 
+ * 
+ * 
+ * @extends Roo.util.Observable
+ * @constructor
+ * @param cfg {Object} configuration of component
+ * 
+ */
+Roo.XComponent = function(cfg) {
+    Roo.apply(this, cfg);
+    this.addEvents({ 
+        /**
+            * @event built
+            * Fires when this the componnt is built
+            * @param {Roo.XComponent} c the component
+            */
+        'built' : true
+        
+    });
+    this.region = this.region || 'center'; // default..
+    Roo.XComponent.register(this);
+    this.modules = false;
+    this.el = false; // where the layout goes..
     
-    
-    
-    
-    var block = {
-      newline: /^\n+/,
-      code: /^( {4}[^\n]+\n*)+/,
-      fences: noop,
-      hr: /^( *[-*_]){3,} *(?:\n+|$)/,
-      heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
-      nptable: noop,
-      lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
-      blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
-      list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
-      html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
-      def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
-      table: noop,
-      paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
-      text: /^[^\n]+/
-    };
-    
-    block.bullet = /(?:[*+-]|\d+\.)/;
-    block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
-    block.item = replace(block.item, 'gm')
-      (/bull/g, block.bullet)
-      ();
-    
-    block.list = replace(block.list)
-      (/bull/g, block.bullet)
-      ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
-      ('def', '\\n+(?=' + block.def.source + ')')
-      ();
-    
-    block.blockquote = replace(block.blockquote)
-      ('def', block.def)
-      ();
-    
-    block._tag = '(?!(?:'
-      + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
-      + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
-      + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
-    
-    block.html = replace(block.html)
-      ('comment', /<!--[\s\S]*?-->/)
-      ('closed', /<(tag)[\s\S]+?<\/\1>/)
-      ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
-      (/tag/g, block._tag)
-      ();
-    
-    block.paragraph = replace(block.paragraph)
-      ('hr', block.hr)
-      ('heading', block.heading)
-      ('lheading', block.lheading)
-      ('blockquote', block.blockquote)
-      ('tag', '<' + block._tag)
-      ('def', block.def)
-      ();
-    
+    
+}
+Roo.extend(Roo.XComponent, Roo.util.Observable, {
     /**
-     * Normal Block Grammar
+     * @property el
+     * The created element (with Roo.factory())
+     * @type {Roo.Layout}
      */
-    
-    block.normal = merge({}, block);
+    el  : false,
     
     /**
-     * GFM Block Grammar
+     * @property el
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
      */
-    
-    block.gfm = merge({}, block.normal, {
-      fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
-      paragraph: /^/,
-      heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
-    });
-    
-    block.gfm.paragraph = replace(block.paragraph)
-      ('(?!', '(?!'
-        + block.gfm.fences.source.replace('\\1', '\\2') + '|'
-        + block.list.source.replace('\\1', '\\3') + '|')
-      ();
+    panel : false,
     
     /**
-     * GFM + Tables Block Grammar
+     * @property layout
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
      */
+    layout : false,
     
-    block.tables = merge({}, block.gfm, {
-      nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
-      table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
-    });
+     /**
+     * @cfg {Function|boolean} disabled
+     * If this module is disabled by some rule, return true from the funtion
+     */
+    disabled : false,
     
     /**
-     * Block Lexer
+     * @cfg {String} parent 
+     * Name of parent element which it get xtype added to..
      */
-    
-    var Lexer = function (options) {
-      this.tokens = [];
-      this.tokens.links = {};
-      this.options = options || marked.defaults;
-      this.rules = block.normal;
-    
-      if (this.options.gfm) {
-        if (this.options.tables) {
-          this.rules = block.tables;
-        } else {
-          this.rules = block.gfm;
-        }
-      }
-    }
+    parent: false,
     
     /**
-     * Expose Block Rules
+     * @cfg {String} order
+     * Used to set the order in which elements are created (usefull for multiple tabs)
      */
     
-    Lexer.rules = block;
-    
+    order : false,
     /**
-     * Static Lex Method
+     * @cfg {String} name
+     * String to display while loading.
      */
-    
-    Lexer.lex = function(src, options) {
-      var lexer = new Lexer(options);
-      return lexer.lex(src);
-    };
-    
+    name : false,
     /**
-     * Preprocessing
+     * @cfg {String} region
+     * Region to render component to (defaults to center)
      */
-    
-    Lexer.prototype.lex = function(src) {
-      src = src
-        .replace(/\r\n|\r/g, '\n')
-        .replace(/\t/g, '    ')
-        .replace(/\u00a0/g, ' ')
-        .replace(/\u2424/g, '\n');
-    
-      return this.token(src, true);
-    };
+    region : 'center',
     
     /**
-     * Lexing
+     * @cfg {Array} items
+     * A single item array - the first element is the root of the tree..
+     * It's done this way to stay compatible with the Xtype system...
      */
+    items : false,
     
-    Lexer.prototype.token = function(src, top, bq) {
-      var src = src.replace(/^ +$/gm, '')
-        , next
-        , loose
-        , cap
-        , bull
-        , b
-        , item
-        , space
-        , i
-        , l;
-    
-      while (src) {
-        // newline
-        if (cap = this.rules.newline.exec(src)) {
-          src = src.substring(cap[0].length);
-          if (cap[0].length > 1) {
-            this.tokens.push({
-              type: 'space'
-            });
-          }
-        }
-    
-        // code
-        if (cap = this.rules.code.exec(src)) {
-          src = src.substring(cap[0].length);
-          cap = cap[0].replace(/^ {4}/gm, '');
-          this.tokens.push({
-            type: 'code',
-            text: !this.options.pedantic
-              ? cap.replace(/\n+$/, '')
-              : cap
-          });
-          continue;
-        }
+    /**
+     * @property _tree
+     * The method that retuns the tree of parts that make up this compoennt 
+     * @type {function}
+     */
+    _tree  : false,
     
-        // fences (gfm)
-        if (cap = this.rules.fences.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'code',
-            lang: cap[2],
-            text: cap[3] || ''
-          });
-          continue;
-        }
+     /**
+     * render
+     * render element to dom or tree
+     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
+     */
     
-        // heading
-        if (cap = this.rules.heading.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'heading',
-            depth: cap[1].length,
-            text: cap[2]
-          });
-          continue;
+    render : function(el)
+    {
+        
+        el = el || false;
+        var hp = this.parent ? 1 : 0;
+        Roo.debug &&  Roo.log(this);
+        
+        var tree = this._tree ? this._tree() : this.tree();
+
+        
+        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
+            // if parent is a '#.....' string, then let's use that..
+            var ename = this.parent.substr(1);
+            this.parent = false;
+            Roo.debug && Roo.log(ename);
+            switch (ename) {
+                case 'bootstrap-body':
+                    if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
+                        // this is the BorderLayout standard?
+                       this.parent = { el : true };
+                       break;
+                    }
+                    if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
+                        // need to insert stuff...
+                        this.parent =  {
+                             el : new Roo.bootstrap.layout.Border({
+                                 el : document.body, 
+                     
+                                 center: {
+                                    titlebar: false,
+                                    autoScroll:false,
+                                    closeOnTab: true,
+                                    tabPosition: 'top',
+                                      //resizeTabs: true,
+                                    alwaysShowTabs: true,
+                                    hideTabs: false
+                                     //minTabWidth: 140
+                                 }
+                             })
+                        
+                         };
+                         break;
+                    }
+                         
+                    if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
+                        this.parent = { el :  new  Roo.bootstrap.Body() };
+                        Roo.debug && Roo.log("setting el to doc body");
+                         
+                    } else {
+                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
+                    }
+                    break;
+                case 'bootstrap':
+                    this.parent = { el : true};
+                    // fall through
+                default:
+                    el = Roo.get(ename);
+                    if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
+                        this.parent = { el : true};
+                    }
+                    
+                    break;
+            }
+                
+            
+            if (!el && !this.parent) {
+                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
+                return;
+            }
         }
-    
-        // table no leading pipe (gfm)
-        if (top && (cap = this.rules.nptable.exec(src))) {
-          src = src.substring(cap[0].length);
-    
-          item = {
-            type: 'table',
-            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
-            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
-            cells: cap[3].replace(/\n$/, '').split('\n')
-          };
-    
-          for (i = 0; i < item.align.length; i++) {
-            if (/^ *-+: *$/.test(item.align[i])) {
-              item.align[i] = 'right';
-            } else if (/^ *:-+: *$/.test(item.align[i])) {
-              item.align[i] = 'center';
-            } else if (/^ *:-+ *$/.test(item.align[i])) {
-              item.align[i] = 'left';
+        
+        Roo.debug && Roo.log("EL:");
+        Roo.debug && Roo.log(el);
+        Roo.debug && Roo.log("this.parent.el:");
+        Roo.debug && Roo.log(this.parent.el);
+        
+
+        // altertive root elements ??? - we need a better way to indicate these.
+        var is_alt = Roo.XComponent.is_alt ||
+                    (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
+                    (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
+                    (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
+        
+        
+        
+        if (!this.parent && is_alt) {
+            //el = Roo.get(document.body);
+            this.parent = { el : true };
+        }
+            
+            
+        
+        if (!this.parent) {
+            
+            Roo.debug && Roo.log("no parent - creating one");
+            
+            el = el ? Roo.get(el) : false;     
+            
+            if (typeof(Roo.BorderLayout) == 'undefined' ) {
+                
+                this.parent =  {
+                    el : new Roo.bootstrap.layout.Border({
+                        el: el || document.body,
+                    
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: false,
+                            hideTabs: true,
+                            minTabWidth: 140,
+                            overflow: 'visible'
+                         }
+                     })
+                };
             } else {
-              item.align[i] = null;
+            
+                // it's a top level one..
+                this.parent =  {
+                    el : new Roo.BorderLayout(el || document.body, {
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: el && hp? false :  true,
+                            hideTabs: el || !hp ? true :  false,
+                            minTabWidth: 140
+                         }
+                    })
+                };
             }
-          }
-    
-          for (i = 0; i < item.cells.length; i++) {
-            item.cells[i] = item.cells[i].split(/ *\| */);
-          }
-    
-          this.tokens.push(item);
-    
-          continue;
         }
-    
-        // lheading
-        if (cap = this.rules.lheading.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'heading',
-            depth: cap[2] === '=' ? 1 : 2,
-            text: cap[1]
-          });
-          continue;
+        
+        if (!this.parent.el) {
+                // probably an old style ctor, which has been disabled.
+                return;
+
         }
-    
-        // hr
-        if (cap = this.rules.hr.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'hr'
-          });
-          continue;
+               // The 'tree' method is  '_tree now' 
+            
+        tree.region = tree.region || this.region;
+        var is_body = false;
+        if (this.parent.el === true) {
+            // bootstrap... - body..
+            if (el) {
+                tree.el = el;
+            }
+            this.parent.el = Roo.factory(tree);
+            is_body = true;
         }
+        
+        this.el = this.parent.el.addxtype(tree, undefined, is_body);
+        this.fireEvent('built', this);
+        
+        this.panel = this.el;
+        this.layout = this.panel.layout;
+        this.parentLayout = this.parent.layout  || false;  
+         
+    }
     
-        // blockquote
-        if (cap = this.rules.blockquote.exec(src)) {
-          src = src.substring(cap[0].length);
-    
-          this.tokens.push({
-            type: 'blockquote_start'
-          });
-    
-          cap = cap[0].replace(/^ *> ?/gm, '');
-    
-          // Pass `top` to keep the current
-          // "toplevel" state. This is exactly
-          // how markdown.pl works.
-          this.token(cap, top, true);
+});
+
+Roo.apply(Roo.XComponent, {
+    /**
+     * @property  hideProgress
+     * true to disable the building progress bar.. usefull on single page renders.
+     * @type Boolean
+     */
+    hideProgress : false,
+    /**
+     * @property  buildCompleted
+     * True when the builder has completed building the interface.
+     * @type Boolean
+     */
+    buildCompleted : false,
+     
+    /**
+     * @property  topModule
+     * the upper most module - uses document.element as it's constructor.
+     * @type Object
+     */
+     
+    topModule  : false,
+      
+    /**
+     * @property  modules
+     * array of modules to be created by registration system.
+     * @type {Array} of Roo.XComponent
+     */
     
-          this.tokens.push({
-            type: 'blockquote_end'
-          });
-    
-          continue;
+    modules : [],
+    /**
+     * @property  elmodules
+     * array of modules to be created by which use #ID 
+     * @type {Array} of Roo.XComponent
+     */
+     
+    elmodules : [],
+
+     /**
+     * @property  is_alt
+     * Is an alternative Root - normally used by bootstrap or other systems,
+     *    where the top element in the tree can wrap 'body' 
+     * @type {boolean}  (default false)
+     */
+     
+    is_alt : false,
+    /**
+     * @property  build_from_html
+     * Build elements from html - used by bootstrap HTML stuff 
+     *    - this is cleared after build is completed
+     * @type {boolean}    (default false)
+     */
+     
+    build_from_html : false,
+    /**
+     * Register components to be built later.
+     *
+     * This solves the following issues
+     * - Building is not done on page load, but after an authentication process has occured.
+     * - Interface elements are registered on page load
+     * - Parent Interface elements may not be loaded before child, so this handles that..
+     * 
+     *
+     * example:
+     * 
+     * MyApp.register({
+          order : '000001',
+          module : 'Pman.Tab.projectMgr',
+          region : 'center',
+          parent : 'Pman.layout',
+          disabled : false,  // or use a function..
+        })
+     
+     * * @param {Object} details about module
+     */
+    register : function(obj) {
+               
+        Roo.XComponent.event.fireEvent('register', obj);
+        switch(typeof(obj.disabled) ) {
+                
+            case 'undefined':
+                break;
+            
+            case 'function':
+                if ( obj.disabled() ) {
+                        return;
+                }
+                break;
+            
+            default:
+                if (obj.disabled || obj.region == '#disabled') {
+                        return;
+                }
+                break;
         }
+               
+        this.modules.push(obj);
+         
+    },
+    /**
+     * convert a string to an object..
+     * eg. 'AAA.BBB' -> finds AAA.BBB
+
+     */
     
-        // list
-        if (cap = this.rules.list.exec(src)) {
-          src = src.substring(cap[0].length);
-          bull = cap[2];
-    
-          this.tokens.push({
-            type: 'list_start',
-            ordered: bull.length > 1
-          });
-    
-          // Get each top-level item.
-          cap = cap[0].match(this.rules.item);
-    
-          next = false;
-          l = cap.length;
-          i = 0;
-    
-          for (; i < l; i++) {
-            item = cap[i];
+    toObject : function(str)
+    {
+        if (!str || typeof(str) == 'object') {
+            return str;
+        }
+        if (str.substring(0,1) == '#') {
+            return str;
+        }
+
+        var ar = str.split('.');
+        var rt, o;
+        rt = ar.shift();
+            /** eval:var:o */
+        try {
+            eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
+        } catch (e) {
+            throw "Module not found : " + str;
+        }
+        
+        if (o === false) {
+            throw "Module not found : " + str;
+        }
+        Roo.each(ar, function(e) {
+            if (typeof(o[e]) == 'undefined') {
+                throw "Module not found : " + str;
+            }
+            o = o[e];
+        });
+        
+        return o;
+        
+    },
     
-            // Remove the list item's bullet
-            // so it is seen as the next token.
-            space = item.length;
-            item = item.replace(/^ *([*+-]|\d+\.) +/, '');
     
-            // Outdent whatever the
-            // list item contains. Hacky.
-            if (~item.indexOf('\n ')) {
-              space -= item.length;
-              item = !this.options.pedantic
-                ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
-                : item.replace(/^ {1,4}/gm, '');
+    /**
+     * move modules into their correct place in the tree..
+     * 
+     */
+    preBuild : function ()
+    {
+        var _t = this;
+        Roo.each(this.modules , function (obj)
+        {
+            Roo.XComponent.event.fireEvent('beforebuild', obj);
+            
+            var opar = obj.parent;
+            try { 
+                obj.parent = this.toObject(opar);
+            } catch(e) {
+                Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
+                return;
             }
-    
-            // Determine whether the next list item belongs here.
-            // Backpedal if it does not belong in this list.
-            if (this.options.smartLists && i !== l - 1) {
-              b = block.bullet.exec(cap[i + 1])[0];
-              if (bull !== b && !(bull.length > 1 && b.length > 1)) {
-                src = cap.slice(i + 1).join('\n') + src;
-                i = l - 1;
-              }
+            
+            if (!obj.parent) {
+                Roo.debug && Roo.log("GOT top level module");
+                Roo.debug && Roo.log(obj);
+                obj.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
+                this.topModule = obj;
+                return;
             }
-    
-            // Determine whether item is loose or not.
-            // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
-            // for discount behavior.
-            loose = next || /\n\n(?!\s*$)/.test(item);
-            if (i !== l - 1) {
-              next = item.charAt(item.length - 1) === '\n';
-              if (!loose) { loose = next; }
+                       // parent is a string (usually a dom element name..)
+            if (typeof(obj.parent) == 'string') {
+                this.elmodules.push(obj);
+                return;
             }
+            if (obj.parent.constructor != Roo.XComponent) {
+                Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
+            }
+            if (!obj.parent.modules) {
+                obj.parent.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
+            }
+            if (obj.parent.disabled) {
+                obj.disabled = true;
+            }
+            obj.parent.modules.add(obj);
+        }, this);
+    },
     
-            this.tokens.push({
-              type: loose
-                ? 'loose_item_start'
-                : 'list_item_start'
-            });
-    
-            // Recurse.
-            this.token(item, false, bq);
-    
-            this.tokens.push({
-              type: 'list_item_end'
-            });
-          }
-    
-          this.tokens.push({
-            type: 'list_end'
-          });
-    
-          continue;
-        }
-    
-        // html
-        if (cap = this.rules.html.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: this.options.sanitize
-              ? 'paragraph'
-              : 'html',
-            pre: !this.options.sanitizer
-              && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
-            text: cap[0]
-          });
-          continue;
-        }
+     /**
+     * make a list of modules to build.
+     * @return {Array} list of modules. 
+     */ 
     
-        // def
-        if ((!bq && top) && (cap = this.rules.def.exec(src))) {
-          src = src.substring(cap[0].length);
-          this.tokens.links[cap[1].toLowerCase()] = {
-            href: cap[2],
-            title: cap[3]
-          };
-          continue;
+    buildOrder : function()
+    {
+        var _this = this;
+        var cmp = function(a,b) {   
+            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
+        };
+        if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
+            throw "No top level modules to build";
         }
+        
+        // make a flat list in order of modules to build.
+        var mods = this.topModule ? [ this.topModule ] : [];
+               
+        
+       // elmodules (is a list of DOM based modules )
+        Roo.each(this.elmodules, function(e) {
+            mods.push(e);
+            if (!this.topModule &&
+                typeof(e.parent) == 'string' &&
+                e.parent.substring(0,1) == '#' &&
+                Roo.get(e.parent.substr(1))
+               ) {
+                
+                _this.topModule = e;
+            }
+            
+        });
+
+        
+        // add modules to their parents..
+        var addMod = function(m) {
+            Roo.debug && Roo.log("build Order: add: " + m.name);
+                
+            mods.push(m);
+            if (m.modules && !m.disabled) {
+                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
+                m.modules.keySort('ASC',  cmp );
+                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
     
-        // table (gfm)
-        if (top && (cap = this.rules.table.exec(src))) {
-          src = src.substring(cap[0].length);
-    
-          item = {
-            type: 'table',
-            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
-            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
-            cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
-          };
-    
-          for (i = 0; i < item.align.length; i++) {
-            if (/^ *-+: *$/.test(item.align[i])) {
-              item.align[i] = 'right';
-            } else if (/^ *:-+: *$/.test(item.align[i])) {
-              item.align[i] = 'center';
-            } else if (/^ *:-+ *$/.test(item.align[i])) {
-              item.align[i] = 'left';
+                m.modules.each(addMod);
             } else {
-              item.align[i] = null;
+                Roo.debug && Roo.log("build Order: no child modules");
             }
-          }
-    
-          for (i = 0; i < item.cells.length; i++) {
-            item.cells[i] = item.cells[i]
-              .replace(/^ *\| *| *\| *$/g, '')
-              .split(/ *\| */);
-          }
-    
-          this.tokens.push(item);
-    
-          continue;
+            // not sure if this is used any more..
+            if (m.finalize) {
+                m.finalize.name = m.name + " (clean up) ";
+                mods.push(m.finalize);
+            }
+            
         }
+        if (this.topModule && this.topModule.modules) { 
+            this.topModule.modules.keySort('ASC',  cmp );
+            this.topModule.modules.each(addMod);
+        } 
+        return mods;
+    },
     
-        // top-level paragraph
-        if (top && (cap = this.rules.paragraph.exec(src))) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'paragraph',
-            text: cap[1].charAt(cap[1].length - 1) === '\n'
-              ? cap[1].slice(0, -1)
-              : cap[1]
-          });
-          continue;
+     /**
+     * Build the registered modules.
+     * @param {Object} parent element.
+     * @param {Function} optional method to call after module has been added.
+     * 
+     */ 
+   
+    build : function(opts) 
+    {
+        
+        if (typeof(opts) != 'undefined') {
+            Roo.apply(this,opts);
         }
-    
-        // text
-        if (cap = this.rules.text.exec(src)) {
-          // Top-level should never reach here.
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'text',
-            text: cap[0]
-          });
-          continue;
+        
+        this.preBuild();
+        var mods = this.buildOrder();
+      
+        //this.allmods = mods;
+        //Roo.debug && Roo.log(mods);
+        //return;
+        if (!mods.length) { // should not happen
+            throw "NO modules!!!";
         }
-    
-        if (src) {
-          throw new
-            Error('Infinite loop on byte: ' + src.charCodeAt(0));
+        
+        
+        var msg = "Building Interface...";
+        // flash it up as modal - so we store the mask!?
+        if (!this.hideProgress && Roo.MessageBox) {
+            Roo.MessageBox.show({ title: 'loading' });
+            Roo.MessageBox.show({
+               title: "Please wait...",
+               msg: msg,
+               width:450,
+               progress:true,
+              buttons : false,
+               closable:false,
+               modal: false
+              
+            });
         }
-      }
-    
-      return this.tokens;
-    };
-    
+        var total = mods.length;
+        
+        var _this = this;
+        var progressRun = function() {
+            if (!mods.length) {
+                Roo.debug && Roo.log('hide?');
+                if (!this.hideProgress && Roo.MessageBox) {
+                    Roo.MessageBox.hide();
+                }
+                Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
+                
+                Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
+                
+                // THE END...
+                return false;   
+            }
+            
+            var m = mods.shift();
+            
+            
+            Roo.debug && Roo.log(m);
+            // not sure if this is supported any more.. - modules that are are just function
+            if (typeof(m) == 'function') { 
+                m.call(this);
+                return progressRun.defer(10, _this);
+            } 
+            
+            
+            msg = "Building Interface " + (total  - mods.length) + 
+                    " of " + total + 
+                    (m.name ? (' - ' + m.name) : '');
+                       Roo.debug && Roo.log(msg);
+            if (!_this.hideProgress &&  Roo.MessageBox) { 
+                Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
+            }
+            
+         
+            // is the module disabled?
+            var disabled = (typeof(m.disabled) == 'function') ?
+                m.disabled.call(m.module.disabled) : m.disabled;    
+            
+            
+            if (disabled) {
+                return progressRun(); // we do not update the display!
+            }
+            
+            // now build 
+            
+                       
+                       
+            m.render();
+            // it's 10 on top level, and 1 on others??? why...
+            return progressRun.defer(10, _this);
+             
+        }
+        progressRun.defer(1, _this);
+     
+        
+        
+    },
     /**
-     * Inline-Level Grammar
+     * Overlay a set of modified strings onto a component
+     * This is dependant on our builder exporting the strings and 'named strings' elements.
+     * 
+     * @param {Object} element to overlay on - eg. Pman.Dialog.Login
+     * @param {Object} associative array of 'named' string and it's new value.
+     * 
      */
+       overlayStrings : function( component, strings )
+    {
+        if (typeof(component['_named_strings']) == 'undefined') {
+            throw "ERROR: component does not have _named_strings";
+        }
+        for ( var k in strings ) {
+            var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
+            if (md !== false) {
+                component['_strings'][md] = strings[k];
+            } else {
+                Roo.log('could not find named string: ' + k + ' in');
+                Roo.log(component);
+            }
+            
+        }
+        
+    },
     
-    var inline = {
-      escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
-      autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
-      url: noop,
-      tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
-      link: /^!?\[(inside)\]\(href\)/,
-      reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
-      nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
-      strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
-      em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
-      code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
-      br: /^ {2,}\n(?!\s*$)/,
-      del: noop,
-      text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
-    };
+       
+       /**
+        * Event Object.
+        *
+        *
+        */
+       event: false, 
+    /**
+        * wrapper for event.on - aliased later..  
+        * Typically use to register a event handler for register:
+        *
+        * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
+        *
+        */
+    on : false
+   
     
-    inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
-    inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
     
-    inline.link = replace(inline.link)
-      ('inside', inline._inside)
-      ('href', inline._href)
-      ();
+});
+
+Roo.XComponent.event = new Roo.util.Observable({
+               events : { 
+                       /**
+                        * @event register
+                        * Fires when an Component is registered,
+                        * set the disable property on the Component to stop registration.
+                        * @param {Roo.XComponent} c the component being registerd.
+                        * 
+                        */
+                       'register' : true,
+            /**
+                        * @event beforebuild
+                        * Fires before each Component is built
+                        * can be used to apply permissions.
+                        * @param {Roo.XComponent} c the component being registerd.
+                        * 
+                        */
+                       'beforebuild' : true,
+                       /**
+                        * @event buildcomplete
+                        * Fires on the top level element when all elements have been built
+                        * @param {Roo.XComponent} the top level component.
+                        */
+                       'buildcomplete' : true
+                       
+               }
+});
+
+Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
+ //
+ /**
+ * marked - a markdown parser
+ * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
+ * https://github.com/chjj/marked
+ */
+
+
+/**
+ *
+ * Roo.Markdown - is a very crude wrapper around marked..
+ *
+ * usage:
+ * 
+ * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
+ * 
+ * Note: move the sample code to the bottom of this
+ * file before uncommenting it.
+ *
+ */
+
+Roo.Markdown = {};
+Roo.Markdown.toHtml = function(text) {
     
-    inline.reflink = replace(inline.reflink)
-      ('inside', inline._inside)
-      ();
+    var c = new Roo.Markdown.marked.setOptions({
+            renderer: new Roo.Markdown.marked.Renderer(),
+            gfm: true,
+            tables: true,
+            breaks: false,
+            pedantic: false,
+            sanitize: false,
+            smartLists: true,
+            smartypants: false
+          });
+    // A FEW HACKS!!?
+    
+    text = text.replace(/\\\n/g,' ');
+    return Roo.Markdown.marked(text);
+};
+//
+// converter
+//
+// Wraps all "globals" so that the only thing
+// exposed is makeHtml().
+//
+(function() {
     
+     /**
+         * eval:var:escape
+         * eval:var:unescape
+         * eval:var:replace
+         */
+      
     /**
-     * Normal Inline Grammar
+     * Helpers
      */
     
-    inline.normal = merge({}, inline);
+    var escape = function (html, encode) {
+      return html
+        .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/"/g, '&quot;')
+        .replace(/'/g, '&#39;');
+    }
     
-    /**
-     * Pedantic Inline Grammar
-     */
+    var unescape = function (html) {
+        // explicitly match decimal, hex, and named HTML entities 
+      return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
+        n = n.toLowerCase();
+        if (n === 'colon') { return ':'; }
+        if (n.charAt(0) === '#') {
+          return n.charAt(1) === 'x'
+            ? String.fromCharCode(parseInt(n.substring(2), 16))
+            : String.fromCharCode(+n.substring(1));
+        }
+        return '';
+      });
+    }
     
-    inline.pedantic = merge({}, inline.normal, {
-      strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
-      em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
-    });
+    var replace = function (regex, opt) {
+      regex = regex.source;
+      opt = opt || '';
+      return function self(name, val) {
+        if (!name) { return new RegExp(regex, opt); }
+        val = val.source || val;
+        val = val.replace(/(^|[^\[])\^/g, '$1');
+        regex = regex.replace(name, val);
+        return self;
+      };
+    }
+
+
+         /**
+         * eval:var:noop
+    */
+    var noop = function () {}
+    noop.exec = noop;
     
-    /**
-     * GFM Inline Grammar
-     */
+         /**
+         * eval:var:merge
+    */
+    var merge = function (obj) {
+      var i = 1
+        , target
+        , key;
     
-    inline.gfm = merge({}, inline.normal, {
-      escape: replace(inline.escape)('])', '~|])')(),
-      url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
-      del: /^~~(?=\S)([\s\S]*?\S)~~/,
-      text: replace(inline.text)
-        (']|', '~]|')
-        ('|', '|https?://|')
-        ()
-    });
+      for (; i < arguments.length; i++) {
+        target = arguments[i];
+        for (key in target) {
+          if (Object.prototype.hasOwnProperty.call(target, key)) {
+            obj[key] = target[key];
+          }
+        }
+      }
     
-    /**
-     * GFM + Line Breaks Inline Grammar
-     */
+      return obj;
+    }
     
-    inline.breaks = merge({}, inline.gfm, {
-      br: replace(inline.br)('{2,}', '*')(),
-      text: replace(inline.gfm.text)('{2,}', '*')()
-    });
     
     /**
-     * Inline Lexer & Compiler
+     * Block-Level Grammar
      */
     
-    var InlineLexer  = function (links, options) {
-      this.options = options || marked.defaults;
-      this.links = links;
-      this.rules = inline.normal;
-      this.renderer = this.options.renderer || new Renderer;
-      this.renderer.options = this.options;
     
-      if (!this.links) {
-        throw new
-          Error('Tokens array requires a `links` property.');
-      }
     
-      if (this.options.gfm) {
-        if (this.options.breaks) {
-          this.rules = inline.breaks;
-        } else {
-          this.rules = inline.gfm;
-        }
-      } else if (this.options.pedantic) {
-        this.rules = inline.pedantic;
-      }
-    }
+    
+    var block = {
+      newline: /^\n+/,
+      code: /^( {4}[^\n]+\n*)+/,
+      fences: noop,
+      hr: /^( *[-*_]){3,} *(?:\n+|$)/,
+      heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
+      nptable: noop,
+      lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
+      blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
+      list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
+      html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
+      def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
+      table: noop,
+      paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
+      text: /^[^\n]+/
+    };
+    
+    block.bullet = /(?:[*+-]|\d+\.)/;
+    block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
+    block.item = replace(block.item, 'gm')
+      (/bull/g, block.bullet)
+      ();
+    
+    block.list = replace(block.list)
+      (/bull/g, block.bullet)
+      ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
+      ('def', '\\n+(?=' + block.def.source + ')')
+      ();
+    
+    block.blockquote = replace(block.blockquote)
+      ('def', block.def)
+      ();
+    
+    block._tag = '(?!(?:'
+      + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+      + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+      + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
+    
+    block.html = replace(block.html)
+      ('comment', /<!--[\s\S]*?-->/)
+      ('closed', /<(tag)[\s\S]+?<\/\1>/)
+      ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
+      (/tag/g, block._tag)
+      ();
+    
+    block.paragraph = replace(block.paragraph)
+      ('hr', block.hr)
+      ('heading', block.heading)
+      ('lheading', block.lheading)
+      ('blockquote', block.blockquote)
+      ('tag', '<' + block._tag)
+      ('def', block.def)
+      ();
     
     /**
-     * Expose Inline Rules
+     * Normal Block Grammar
      */
     
-    InlineLexer.rules = inline;
+    block.normal = merge({}, block);
     
     /**
-     * Static Lexing/Compiling Method
+     * GFM Block Grammar
      */
     
-    InlineLexer.output = function(src, links, options) {
-      var inline = new InlineLexer(links, options);
-      return inline.output(src);
-    };
+    block.gfm = merge({}, block.normal, {
+      fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
+      paragraph: /^/,
+      heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
+    });
+    
+    block.gfm.paragraph = replace(block.paragraph)
+      ('(?!', '(?!'
+        + block.gfm.fences.source.replace('\\1', '\\2') + '|'
+        + block.list.source.replace('\\1', '\\3') + '|')
+      ();
     
     /**
-     * Lexing/Compiling
+     * GFM + Tables Block Grammar
      */
     
-    InlineLexer.prototype.output = function(src) {
-      var out = ''
-        , link
-        , text
-        , href
-        , cap;
+    block.tables = merge({}, block.gfm, {
+      nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
+      table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
+    });
     
-      while (src) {
-        // escape
-        if (cap = this.rules.escape.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += cap[1];
-          continue;
+    /**
+     * Block Lexer
+     */
+    
+    var Lexer = function (options) {
+      this.tokens = [];
+      this.tokens.links = {};
+      this.options = options || marked.defaults;
+      this.rules = block.normal;
+    
+      if (this.options.gfm) {
+        if (this.options.tables) {
+          this.rules = block.tables;
+        } else {
+          this.rules = block.gfm;
         }
+      }
+    }
     
-        // autolink
-        if (cap = this.rules.autolink.exec(src)) {
+    /**
+     * Expose Block Rules
+     */
+    
+    Lexer.rules = block;
+    
+    /**
+     * Static Lex Method
+     */
+    
+    Lexer.lex = function(src, options) {
+      var lexer = new Lexer(options);
+      return lexer.lex(src);
+    };
+    
+    /**
+     * Preprocessing
+     */
+    
+    Lexer.prototype.lex = function(src) {
+      src = src
+        .replace(/\r\n|\r/g, '\n')
+        .replace(/\t/g, '    ')
+        .replace(/\u00a0/g, ' ')
+        .replace(/\u2424/g, '\n');
+    
+      return this.token(src, true);
+    };
+    
+    /**
+     * Lexing
+     */
+    
+    Lexer.prototype.token = function(src, top, bq) {
+      var src = src.replace(/^ +$/gm, '')
+        , next
+        , loose
+        , cap
+        , bull
+        , b
+        , item
+        , space
+        , i
+        , l;
+    
+      while (src) {
+        // newline
+        if (cap = this.rules.newline.exec(src)) {
           src = src.substring(cap[0].length);
-          if (cap[2] === '@') {
-            text = cap[1].charAt(6) === ':'
-              ? this.mangle(cap[1].substring(7))
-              : this.mangle(cap[1]);
-            href = this.mangle('mailto:') + text;
-          } else {
-            text = escape(cap[1]);
-            href = text;
+          if (cap[0].length > 1) {
+            this.tokens.push({
+              type: 'space'
+            });
           }
-          out += this.renderer.link(href, null, text);
-          continue;
         }
     
-        // url (gfm)
-        if (!this.inLink && (cap = this.rules.url.exec(src))) {
+        // code
+        if (cap = this.rules.code.exec(src)) {
           src = src.substring(cap[0].length);
-          text = escape(cap[1]);
-          href = text;
-          out += this.renderer.link(href, null, text);
+          cap = cap[0].replace(/^ {4}/gm, '');
+          this.tokens.push({
+            type: 'code',
+            text: !this.options.pedantic
+              ? cap.replace(/\n+$/, '')
+              : cap
+          });
           continue;
         }
     
-        // tag
-        if (cap = this.rules.tag.exec(src)) {
-          if (!this.inLink && /^<a /i.test(cap[0])) {
-            this.inLink = true;
-          } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
-            this.inLink = false;
-          }
+        // fences (gfm)
+        if (cap = this.rules.fences.exec(src)) {
           src = src.substring(cap[0].length);
-          out += this.options.sanitize
-            ? this.options.sanitizer
-              ? this.options.sanitizer(cap[0])
-              : escape(cap[0])
-            : cap[0];
+          this.tokens.push({
+            type: 'code',
+            lang: cap[2],
+            text: cap[3] || ''
+          });
           continue;
         }
     
-        // link
-        if (cap = this.rules.link.exec(src)) {
+        // heading
+        if (cap = this.rules.heading.exec(src)) {
           src = src.substring(cap[0].length);
-          this.inLink = true;
-          out += this.outputLink(cap, {
-            href: cap[2],
-            title: cap[3]
+          this.tokens.push({
+            type: 'heading',
+            depth: cap[1].length,
+            text: cap[2]
           });
-          this.inLink = false;
           continue;
         }
     
-        // reflink, nolink
-        if ((cap = this.rules.reflink.exec(src))
-            || (cap = this.rules.nolink.exec(src))) {
+        // table no leading pipe (gfm)
+        if (top && (cap = this.rules.nptable.exec(src))) {
           src = src.substring(cap[0].length);
-          link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
-          link = this.links[link.toLowerCase()];
-          if (!link || !link.href) {
-            out += cap[0].charAt(0);
-            src = cap[0].substring(1) + src;
-            continue;
+    
+          item = {
+            type: 'table',
+            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
+            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
+            cells: cap[3].replace(/\n$/, '').split('\n')
+          };
+    
+          for (i = 0; i < item.align.length; i++) {
+            if (/^ *-+: *$/.test(item.align[i])) {
+              item.align[i] = 'right';
+            } else if (/^ *:-+: *$/.test(item.align[i])) {
+              item.align[i] = 'center';
+            } else if (/^ *:-+ *$/.test(item.align[i])) {
+              item.align[i] = 'left';
+            } else {
+              item.align[i] = null;
+            }
           }
-          this.inLink = true;
-          out += this.outputLink(cap, link);
-          this.inLink = false;
-          continue;
-        }
     
-        // strong
-        if (cap = this.rules.strong.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.strong(this.output(cap[2] || cap[1]));
-          continue;
-        }
+          for (i = 0; i < item.cells.length; i++) {
+            item.cells[i] = item.cells[i].split(/ *\| */);
+          }
     
-        // em
-        if (cap = this.rules.em.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.em(this.output(cap[2] || cap[1]));
-          continue;
-        }
+          this.tokens.push(item);
     
-        // code
-        if (cap = this.rules.code.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.codespan(escape(cap[2], true));
           continue;
         }
     
-        // br
-        if (cap = this.rules.br.exec(src)) {
+        // lheading
+        if (cap = this.rules.lheading.exec(src)) {
           src = src.substring(cap[0].length);
-          out += this.renderer.br();
+          this.tokens.push({
+            type: 'heading',
+            depth: cap[2] === '=' ? 1 : 2,
+            text: cap[1]
+          });
           continue;
         }
     
-        // del (gfm)
-        if (cap = this.rules.del.exec(src)) {
+        // hr
+        if (cap = this.rules.hr.exec(src)) {
           src = src.substring(cap[0].length);
-          out += this.renderer.del(this.output(cap[1]));
+          this.tokens.push({
+            type: 'hr'
+          });
           continue;
         }
     
-        // text
-        if (cap = this.rules.text.exec(src)) {
+        // blockquote
+        if (cap = this.rules.blockquote.exec(src)) {
           src = src.substring(cap[0].length);
-          out += this.renderer.text(escape(this.smartypants(cap[0])));
-          continue;
-        }
     
-        if (src) {
-          throw new
-            Error('Infinite loop on byte: ' + src.charCodeAt(0));
-        }
-      }
+          this.tokens.push({
+            type: 'blockquote_start'
+          });
     
-      return out;
-    };
+          cap = cap[0].replace(/^ *> ?/gm, '');
     
-    /**
-     * Compile Link
-     */
+          // Pass `top` to keep the current
+          // "toplevel" state. This is exactly
+          // how markdown.pl works.
+          this.token(cap, top, true);
     
-    InlineLexer.prototype.outputLink = function(cap, link) {
-      var href = escape(link.href)
-        , title = link.title ? escape(link.title) : null;
-    
-      return cap[0].charAt(0) !== '!'
-        ? this.renderer.link(href, title, this.output(cap[1]))
-        : this.renderer.image(href, title, escape(cap[1]));
-    };
-    
-    /**
-     * Smartypants Transformations
-     */
+          this.tokens.push({
+            type: 'blockquote_end'
+          });
     
-    InlineLexer.prototype.smartypants = function(text) {
-      if (!this.options.smartypants)  { return text; }
-      return text
-        // em-dashes
-        .replace(/---/g, '\u2014')
-        // en-dashes
-        .replace(/--/g, '\u2013')
-        // opening singles
-        .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
-        // closing singles & apostrophes
-        .replace(/'/g, '\u2019')
-        // opening doubles
-        .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
-        // closing doubles
-        .replace(/"/g, '\u201d')
-        // ellipses
-        .replace(/\.{3}/g, '\u2026');
-    };
+          continue;
+        }
     
-    /**
-     * Mangle Links
-     */
+        // list
+        if (cap = this.rules.list.exec(src)) {
+          src = src.substring(cap[0].length);
+          bull = cap[2];
     
-    InlineLexer.prototype.mangle = function(text) {
-      if (!this.options.mangle) { return text; }
-      var out = ''
-        , l = text.length
-        , i = 0
-        , ch;
+          this.tokens.push({
+            type: 'list_start',
+            ordered: bull.length > 1
+          });
     
-      for (; i < l; i++) {
-        ch = text.charCodeAt(i);
-        if (Math.random() > 0.5) {
-          ch = 'x' + ch.toString(16);
-        }
-        out += '&#' + ch + ';';
-      }
+          // Get each top-level item.
+          cap = cap[0].match(this.rules.item);
     
-      return out;
-    };
+          next = false;
+          l = cap.length;
+          i = 0;
     
-    /**
-     * Renderer
-     */
+          for (; i < l; i++) {
+            item = cap[i];
     
-     /**
-         * eval:var:Renderer
-    */
+            // Remove the list item's bullet
+            // so it is seen as the next token.
+            space = item.length;
+            item = item.replace(/^ *([*+-]|\d+\.) +/, '');
     
-    var Renderer   = function (options) {
-      this.options = options || {};
-    }
+            // Outdent whatever the
+            // list item contains. Hacky.
+            if (~item.indexOf('\n ')) {
+              space -= item.length;
+              item = !this.options.pedantic
+                ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
+                : item.replace(/^ {1,4}/gm, '');
+            }
     
-    Renderer.prototype.code = function(code, lang, escaped) {
-      if (this.options.highlight) {
-        var out = this.options.highlight(code, lang);
-        if (out != null && out !== code) {
-          escaped = true;
-          code = out;
-        }
-      } else {
-            // hack!!! - it's already escapeD?
-            escaped = true;
-      }
+            // Determine whether the next list item belongs here.
+            // Backpedal if it does not belong in this list.
+            if (this.options.smartLists && i !== l - 1) {
+              b = block.bullet.exec(cap[i + 1])[0];
+              if (bull !== b && !(bull.length > 1 && b.length > 1)) {
+                src = cap.slice(i + 1).join('\n') + src;
+                i = l - 1;
+              }
+            }
     
-      if (!lang) {
-        return '<pre><code>'
-          + (escaped ? code : escape(code, true))
-          + '\n</code></pre>';
-      }
+            // Determine whether item is loose or not.
+            // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
+            // for discount behavior.
+            loose = next || /\n\n(?!\s*$)/.test(item);
+            if (i !== l - 1) {
+              next = item.charAt(item.length - 1) === '\n';
+              if (!loose) { loose = next; }
+            }
     
-      return '<pre><code class="'
-        + this.options.langPrefix
-        + escape(lang, true)
-        + '">'
-        + (escaped ? code : escape(code, true))
-        + '\n</code></pre>\n';
-    };
+            this.tokens.push({
+              type: loose
+                ? 'loose_item_start'
+                : 'list_item_start'
+            });
     
-    Renderer.prototype.blockquote = function(quote) {
-      return '<blockquote>\n' + quote + '</blockquote>\n';
-    };
+            // Recurse.
+            this.token(item, false, bq);
     
-    Renderer.prototype.html = function(html) {
-      return html;
-    };
+            this.tokens.push({
+              type: 'list_item_end'
+            });
+          }
     
-    Renderer.prototype.heading = function(text, level, raw) {
-      return '<h'
-        + level
-        + ' id="'
-        + this.options.headerPrefix
-        + raw.toLowerCase().replace(/[^\w]+/g, '-')
-        + '">'
-        + text
-        + '</h'
-        + level
-        + '>\n';
-    };
+          this.tokens.push({
+            type: 'list_end'
+          });
     
-    Renderer.prototype.hr = function() {
-      return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
-    };
+          continue;
+        }
     
-    Renderer.prototype.list = function(body, ordered) {
-      var type = ordered ? 'ol' : 'ul';
-      return '<' + type + '>\n' + body + '</' + type + '>\n';
-    };
+        // html
+        if (cap = this.rules.html.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: this.options.sanitize
+              ? 'paragraph'
+              : 'html',
+            pre: !this.options.sanitizer
+              && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
+            text: cap[0]
+          });
+          continue;
+        }
     
-    Renderer.prototype.listitem = function(text) {
-      return '<li>' + text + '</li>\n';
-    };
+        // def
+        if ((!bq && top) && (cap = this.rules.def.exec(src))) {
+          src = src.substring(cap[0].length);
+          this.tokens.links[cap[1].toLowerCase()] = {
+            href: cap[2],
+            title: cap[3]
+          };
+          continue;
+        }
     
-    Renderer.prototype.paragraph = function(text) {
-      return '<p>' + text + '</p>\n';
-    };
+        // table (gfm)
+        if (top && (cap = this.rules.table.exec(src))) {
+          src = src.substring(cap[0].length);
     
-    Renderer.prototype.table = function(header, body) {
-      return '<table class="table table-striped">\n'
-        + '<thead>\n'
-        + header
-        + '</thead>\n'
-        + '<tbody>\n'
-        + body
-        + '</tbody>\n'
-        + '</table>\n';
-    };
+          item = {
+            type: 'table',
+            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
+            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
+            cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
+          };
     
-    Renderer.prototype.tablerow = function(content) {
-      return '<tr>\n' + content + '</tr>\n';
-    };
+          for (i = 0; i < item.align.length; i++) {
+            if (/^ *-+: *$/.test(item.align[i])) {
+              item.align[i] = 'right';
+            } else if (/^ *:-+: *$/.test(item.align[i])) {
+              item.align[i] = 'center';
+            } else if (/^ *:-+ *$/.test(item.align[i])) {
+              item.align[i] = 'left';
+            } else {
+              item.align[i] = null;
+            }
+          }
     
-    Renderer.prototype.tablecell = function(content, flags) {
-      var type = flags.header ? 'th' : 'td';
-      var tag = flags.align
-        ? '<' + type + ' style="text-align:' + flags.align + '">'
-        : '<' + type + '>';
-      return tag + content + '</' + type + '>\n';
-    };
+          for (i = 0; i < item.cells.length; i++) {
+            item.cells[i] = item.cells[i]
+              .replace(/^ *\| *| *\| *$/g, '')
+              .split(/ *\| */);
+          }
     
-    // span level renderer
-    Renderer.prototype.strong = function(text) {
-      return '<strong>' + text + '</strong>';
-    };
+          this.tokens.push(item);
     
-    Renderer.prototype.em = function(text) {
-      return '<em>' + text + '</em>';
-    };
+          continue;
+        }
     
-    Renderer.prototype.codespan = function(text) {
-      return '<code>' + text + '</code>';
-    };
-    
-    Renderer.prototype.br = function() {
-      return this.options.xhtml ? '<br/>' : '<br>';
-    };
-    
-    Renderer.prototype.del = function(text) {
-      return '<del>' + text + '</del>';
-    };
-    
-    Renderer.prototype.link = function(href, title, text) {
-      if (this.options.sanitize) {
-        try {
-          var prot = decodeURIComponent(unescape(href))
-            .replace(/[^\w:]/g, '')
-            .toLowerCase();
-        } catch (e) {
-          return '';
+        // top-level paragraph
+        if (top && (cap = this.rules.paragraph.exec(src))) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'paragraph',
+            text: cap[1].charAt(cap[1].length - 1) === '\n'
+              ? cap[1].slice(0, -1)
+              : cap[1]
+          });
+          continue;
         }
-        if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
-          return '';
+    
+        // text
+        if (cap = this.rules.text.exec(src)) {
+          // Top-level should never reach here.
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'text',
+            text: cap[0]
+          });
+          continue;
         }
-      }
-      var out = '<a href="' + href + '"';
-      if (title) {
-        out += ' title="' + title + '"';
-      }
-      out += '>' + text + '</a>';
-      return out;
-    };
     
-    Renderer.prototype.image = function(href, title, text) {
-      var out = '<img src="' + href + '" alt="' + text + '"';
-      if (title) {
-        out += ' title="' + title + '"';
+        if (src) {
+          throw new
+            Error('Infinite loop on byte: ' + src.charCodeAt(0));
+        }
       }
-      out += this.options.xhtml ? '/>' : '>';
-      return out;
-    };
     
-    Renderer.prototype.text = function(text) {
-      return text;
+      return this.tokens;
     };
     
     /**
-     * Parsing & Compiling
+     * Inline-Level Grammar
      */
-         /**
-         * eval:var:Parser
-    */
     
-    var Parser= function (options) {
-      this.tokens = [];
-      this.token = null;
-      this.options = options || marked.defaults;
-      this.options.renderer = this.options.renderer || new Renderer;
-      this.renderer = this.options.renderer;
-      this.renderer.options = this.options;
-    }
+    var inline = {
+      escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
+      autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
+      url: noop,
+      tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
+      link: /^!?\[(inside)\]\(href\)/,
+      reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
+      nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
+      strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
+      em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
+      code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
+      br: /^ {2,}\n(?!\s*$)/,
+      del: noop,
+      text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
+    };
     
-    /**
-     * Static Parse Method
-     */
+    inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
+    inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
     
-    Parser.parse = function(src, options, renderer) {
-      var parser = new Parser(options, renderer);
-      return parser.parse(src);
-    };
+    inline.link = replace(inline.link)
+      ('inside', inline._inside)
+      ('href', inline._href)
+      ();
+    
+    inline.reflink = replace(inline.reflink)
+      ('inside', inline._inside)
+      ();
     
     /**
-     * Parse Loop
+     * Normal Inline Grammar
      */
     
-    Parser.prototype.parse = function(src) {
-      this.inline = new InlineLexer(src.links, this.options, this.renderer);
-      this.tokens = src.reverse();
+    inline.normal = merge({}, inline);
     
-      var out = '';
-      while (this.next()) {
-        out += this.tok();
-      }
+    /**
+     * Pedantic Inline Grammar
+     */
     
-      return out;
-    };
+    inline.pedantic = merge({}, inline.normal, {
+      strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
+      em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
+    });
     
     /**
-     * Next Token
+     * GFM Inline Grammar
      */
     
-    Parser.prototype.next = function() {
-      return this.token = this.tokens.pop();
-    };
+    inline.gfm = merge({}, inline.normal, {
+      escape: replace(inline.escape)('])', '~|])')(),
+      url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
+      del: /^~~(?=\S)([\s\S]*?\S)~~/,
+      text: replace(inline.text)
+        (']|', '~]|')
+        ('|', '|https?://|')
+        ()
+    });
     
     /**
-     * Preview Next Token
+     * GFM + Line Breaks Inline Grammar
      */
     
-    Parser.prototype.peek = function() {
-      return this.tokens[this.tokens.length - 1] || 0;
-    };
+    inline.breaks = merge({}, inline.gfm, {
+      br: replace(inline.br)('{2,}', '*')(),
+      text: replace(inline.gfm.text)('{2,}', '*')()
+    });
     
     /**
-     * Parse Text Tokens
+     * Inline Lexer & Compiler
      */
     
-    Parser.prototype.parseText = function() {
-      var body = this.token.text;
+    var InlineLexer  = function (links, options) {
+      this.options = options || marked.defaults;
+      this.links = links;
+      this.rules = inline.normal;
+      this.renderer = this.options.renderer || new Renderer;
+      this.renderer.options = this.options;
     
-      while (this.peek().type === 'text') {
-        body += '\n' + this.next().text;
+      if (!this.links) {
+        throw new
+          Error('Tokens array requires a `links` property.');
       }
     
-      return this.inline.output(body);
-    };
+      if (this.options.gfm) {
+        if (this.options.breaks) {
+          this.rules = inline.breaks;
+        } else {
+          this.rules = inline.gfm;
+        }
+      } else if (this.options.pedantic) {
+        this.rules = inline.pedantic;
+      }
+    }
     
     /**
-     * Parse Current Token
+     * Expose Inline Rules
      */
     
-    Parser.prototype.tok = function() {
-      switch (this.token.type) {
-        case 'space': {
-          return '';
-        }
-        case 'hr': {
-          return this.renderer.hr();
-        }
-        case 'heading': {
-          return this.renderer.heading(
-            this.inline.output(this.token.text),
-            this.token.depth,
-            this.token.text);
-        }
-        case 'code': {
-          return this.renderer.code(this.token.text,
-            this.token.lang,
-            this.token.escaped);
-        }
-        case 'table': {
-          var header = ''
-            , body = ''
-            , i
-            , row
-            , cell
-            , flags
-            , j;
+    InlineLexer.rules = inline;
     
-          // header
-          cell = '';
-          for (i = 0; i < this.token.header.length; i++) {
-            flags = { header: true, align: this.token.align[i] };
-            cell += this.renderer.tablecell(
-              this.inline.output(this.token.header[i]),
-              { header: true, align: this.token.align[i] }
-            );
-          }
-          header += this.renderer.tablerow(cell);
+    /**
+     * Static Lexing/Compiling Method
+     */
     
-          for (i = 0; i < this.token.cells.length; i++) {
-            row = this.token.cells[i];
+    InlineLexer.output = function(src, links, options) {
+      var inline = new InlineLexer(links, options);
+      return inline.output(src);
+    };
     
-            cell = '';
-            for (j = 0; j < row.length; j++) {
-              cell += this.renderer.tablecell(
-                this.inline.output(row[j]),
-                { header: false, align: this.token.align[j] }
-              );
-            }
+    /**
+     * Lexing/Compiling
+     */
     
-            body += this.renderer.tablerow(cell);
-          }
-          return this.renderer.table(header, body);
-        }
-        case 'blockquote_start': {
-          var body = '';
+    InlineLexer.prototype.output = function(src) {
+      var out = ''
+        , link
+        , text
+        , href
+        , cap;
     
-          while (this.next().type !== 'blockquote_end') {
-            body += this.tok();
-          }
+      while (src) {
+        // escape
+        if (cap = this.rules.escape.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += cap[1];
+          continue;
+        }
     
-          return this.renderer.blockquote(body);
-        }
-        case 'list_start': {
-          var body = ''
-            , ordered = this.token.ordered;
-    
-          while (this.next().type !== 'list_end') {
-            body += this.tok();
+        // autolink
+        if (cap = this.rules.autolink.exec(src)) {
+          src = src.substring(cap[0].length);
+          if (cap[2] === '@') {
+            text = cap[1].charAt(6) === ':'
+              ? this.mangle(cap[1].substring(7))
+              : this.mangle(cap[1]);
+            href = this.mangle('mailto:') + text;
+          } else {
+            text = escape(cap[1]);
+            href = text;
           }
+          out += this.renderer.link(href, null, text);
+          continue;
+        }
     
-          return this.renderer.list(body, ordered);
+        // url (gfm)
+        if (!this.inLink && (cap = this.rules.url.exec(src))) {
+          src = src.substring(cap[0].length);
+          text = escape(cap[1]);
+          href = text;
+          out += this.renderer.link(href, null, text);
+          continue;
         }
-        case 'list_item_start': {
-          var body = '';
     
-          while (this.next().type !== 'list_item_end') {
-            body += this.token.type === 'text'
-              ? this.parseText()
-              : this.tok();
+        // tag
+        if (cap = this.rules.tag.exec(src)) {
+          if (!this.inLink && /^<a /i.test(cap[0])) {
+            this.inLink = true;
+          } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
+            this.inLink = false;
           }
+          src = src.substring(cap[0].length);
+          out += this.options.sanitize
+            ? this.options.sanitizer
+              ? this.options.sanitizer(cap[0])
+              : escape(cap[0])
+            : cap[0];
+          continue;
+        }
     
-          return this.renderer.listitem(body);
+        // link
+        if (cap = this.rules.link.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.inLink = true;
+          out += this.outputLink(cap, {
+            href: cap[2],
+            title: cap[3]
+          });
+          this.inLink = false;
+          continue;
         }
-        case 'loose_item_start': {
-          var body = '';
     
-          while (this.next().type !== 'list_item_end') {
-            body += this.tok();
+        // reflink, nolink
+        if ((cap = this.rules.reflink.exec(src))
+            || (cap = this.rules.nolink.exec(src))) {
+          src = src.substring(cap[0].length);
+          link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
+          link = this.links[link.toLowerCase()];
+          if (!link || !link.href) {
+            out += cap[0].charAt(0);
+            src = cap[0].substring(1) + src;
+            continue;
           }
-    
-          return this.renderer.listitem(body);
-        }
-        case 'html': {
-          var html = !this.token.pre && !this.options.pedantic
-            ? this.inline.output(this.token.text)
-            : this.token.text;
-          return this.renderer.html(html);
-        }
-        case 'paragraph': {
-          return this.renderer.paragraph(this.inline.output(this.token.text));
-        }
-        case 'text': {
-          return this.renderer.paragraph(this.parseText());
+          this.inLink = true;
+          out += this.outputLink(cap, link);
+          this.inLink = false;
+          continue;
         }
-      }
-    };
-  
     
-    /**
-     * Marked
-     */
-         /**
-         * eval:var:marked
-    */
-    var marked = function (src, opt, callback) {
-      if (callback || typeof opt === 'function') {
-        if (!callback) {
-          callback = opt;
-          opt = null;
+        // strong
+        if (cap = this.rules.strong.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.strong(this.output(cap[2] || cap[1]));
+          continue;
         }
     
-        opt = merge({}, marked.defaults, opt || {});
-    
-        var highlight = opt.highlight
-          , tokens
-          , pending
-          , i = 0;
-    
-        try {
-          tokens = Lexer.lex(src, opt)
-        } catch (e) {
-          return callback(e);
+        // em
+        if (cap = this.rules.em.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.em(this.output(cap[2] || cap[1]));
+          continue;
         }
     
-        pending = tokens.length;
-         /**
-         * eval:var:done
-    */
-        var done = function(err) {
-          if (err) {
-            opt.highlight = highlight;
-            return callback(err);
-          }
-    
-          var out;
-    
-          try {
-            out = Parser.parse(tokens, opt);
-          } catch (e) {
-            err = e;
-          }
-    
-          opt.highlight = highlight;
-    
-          return err
-            ? callback(err)
-            : callback(null, out);
-        };
-    
-        if (!highlight || highlight.length < 3) {
-          return done();
+        // code
+        if (cap = this.rules.code.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.codespan(escape(cap[2], true));
+          continue;
         }
     
-        delete opt.highlight;
+        // br
+        if (cap = this.rules.br.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.br();
+          continue;
+        }
     
-        if (!pending) { return done(); }
+        // del (gfm)
+        if (cap = this.rules.del.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.del(this.output(cap[1]));
+          continue;
+        }
     
-        for (; i < tokens.length; i++) {
-          (function(token) {
-            if (token.type !== 'code') {
-              return --pending || done();
-            }
-            return highlight(token.text, token.lang, function(err, code) {
-              if (err) { return done(err); }
-              if (code == null || code === token.text) {
-                return --pending || done();
-              }
-              token.text = code;
-              token.escaped = true;
-              --pending || done();
-            });
-          })(tokens[i]);
+        // text
+        if (cap = this.rules.text.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.text(escape(this.smartypants(cap[0])));
+          continue;
         }
     
-        return;
-      }
-      try {
-        if (opt) { opt = merge({}, marked.defaults, opt); }
-        return Parser.parse(Lexer.lex(src, opt), opt);
-      } catch (e) {
-        e.message += '\nPlease report this to https://github.com/chjj/marked.';
-        if ((opt || marked.defaults).silent) {
-          return '<p>An error occured:</p><pre>'
-            + escape(e.message + '', true)
-            + '</pre>';
+        if (src) {
+          throw new
+            Error('Infinite loop on byte: ' + src.charCodeAt(0));
         }
-        throw e;
       }
-    }
+    
+      return out;
+    };
     
     /**
-     * Options
+     * Compile Link
      */
     
-    marked.options =
-    marked.setOptions = function(opt) {
-      merge(marked.defaults, opt);
-      return marked;
-    };
+    InlineLexer.prototype.outputLink = function(cap, link) {
+      var href = escape(link.href)
+        , title = link.title ? escape(link.title) : null;
     
-    marked.defaults = {
-      gfm: true,
-      tables: true,
-      breaks: false,
-      pedantic: false,
-      sanitize: false,
-      sanitizer: null,
-      mangle: true,
-      smartLists: false,
-      silent: false,
-      highlight: null,
-      langPrefix: 'lang-',
-      smartypants: false,
-      headerPrefix: '',
-      renderer: new Renderer,
-      xhtml: false
+      return cap[0].charAt(0) !== '!'
+        ? this.renderer.link(href, title, this.output(cap[1]))
+        : this.renderer.image(href, title, escape(cap[1]));
     };
     
     /**
-     * Expose
+     * Smartypants Transformations
      */
     
-    marked.Parser = Parser;
-    marked.parser = Parser.parse;
-    
-    marked.Renderer = Renderer;
-    
-    marked.Lexer = Lexer;
-    marked.lexer = Lexer.lex;
-    
-    marked.InlineLexer = InlineLexer;
-    marked.inlineLexer = InlineLexer.output;
-    
-    marked.parse = marked;
-    
-    Roo.Markdown.marked = marked;
-
-})();/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-
-
-/*
- * These classes are derivatives of the similarly named classes in the YUI Library.
- * The original license:
- * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
- * Code licensed under the BSD License:
- * http://developer.yahoo.net/yui/license.txt
- */
-
-(function() {
-
-var Event=Roo.EventManager;
-var Dom=Roo.lib.Dom;
-
-/**
- * @class Roo.dd.DragDrop
- * @extends Roo.util.Observable
- * Defines the interface and base operation of items that that can be
- * dragged or can be drop targets.  It was designed to be extended, overriding
- * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
- * Up to three html elements can be associated with a DragDrop instance:
- * <ul>
- * <li>linked element: the element that is passed into the constructor.
- * This is the element which defines the boundaries for interaction with
- * other DragDrop objects.</li>
- * <li>handle element(s): The drag operation only occurs if the element that
- * was clicked matches a handle element.  By default this is the linked
- * element, but there are times that you will want only a portion of the
- * linked element to initiate the drag operation, and the setHandleElId()
- * method provides a way to define this.</li>
- * <li>drag element: this represents the element that would be moved along
- * with the cursor during a drag operation.  By default, this is the linked
- * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
- * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
- * </li>
- * </ul>
- * This class should not be instantiated until the onload event to ensure that
- * the associated elements are available.
- * The following would define a DragDrop obj that would interact with any
- * other DragDrop obj in the "group1" group:
- * <pre>
- *  dd = new Roo.dd.DragDrop("div1", "group1");
- * </pre>
- * Since none of the event handlers have been implemented, nothing would
- * actually happen if you were to run the code above.  Normally you would
- * override this class or one of the default implementations, but you can
- * also override the methods you want on an instance of the class...
- * <pre>
- *  dd.onDragDrop = function(e, id) {
- *  &nbsp;&nbsp;alert("dd was dropped on " + id);
- *  }
- * </pre>
- * @constructor
- * @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
- *                Valid properties for DragDrop:
- *                    padding, isTarget, maintainOffset, primaryButtonOnly
- */
-Roo.dd.DragDrop = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
-    }
+    InlineLexer.prototype.smartypants = function(text) {
+      if (!this.options.smartypants)  { return text; }
+      return text
+        // em-dashes
+        .replace(/---/g, '\u2014')
+        // en-dashes
+        .replace(/--/g, '\u2013')
+        // opening singles
+        .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
+        // closing singles & apostrophes
+        .replace(/'/g, '\u2019')
+        // opening doubles
+        .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
+        // closing doubles
+        .replace(/"/g, '\u201d')
+        // ellipses
+        .replace(/\.{3}/g, '\u2026');
+    };
     
-};
-
-Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
-
-    /**
-     * The id of the element associated with this object.  This is what we
-     * refer to as the "linked element" because the size and position of
-     * this element is used to determine when the drag and drop objects have
-     * interacted.
-     * @property id
-     * @type String
-     */
-    id: null,
-
-    /**
-     * Configuration attributes passed into the constructor
-     * @property config
-     * @type object
-     */
-    config: null,
-
-    /**
-     * The id of the element that will be dragged.  By default this is same
-     * as the linked element , but could be changed to another element. Ex:
-     * Roo.dd.DDProxy
-     * @property dragElId
-     * @type String
-     * @private
-     */
-    dragElId: null,
-
-    /**
-     * the id of the element that initiates the drag operation.  By default
-     * this is the linked element, but could be changed to be a child of this
-     * element.  This lets us do things like only starting the drag when the
-     * header element within the linked html element is clicked.
-     * @property handleElId
-     * @type String
-     * @private
-     */
-    handleElId: null,
-
-    /**
-     * An associative array of HTML tags that will be ignored if clicked.
-     * @property invalidHandleTypes
-     * @type {string: string}
-     */
-    invalidHandleTypes: null,
-
-    /**
-     * An associative array of ids for elements that will be ignored if clicked
-     * @property invalidHandleIds
-     * @type {string: string}
-     */
-    invalidHandleIds: null,
-
-    /**
-     * An indexted array of css class names for elements that will be ignored
-     * if clicked.
-     * @property invalidHandleClasses
-     * @type string[]
-     */
-    invalidHandleClasses: null,
-
-    /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageX
-     * @type int
-     * @private
-     */
-    startPageX: 0,
-
-    /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageY
-     * @type int
-     * @private
-     */
-    startPageY: 0,
-
-    /**
-     * The group defines a logical collection of DragDrop objects that are
-     * related.  Instances only get events when interacting with other
-     * DragDrop object in the same group.  This lets us define multiple
-     * groups using a single DragDrop subclass if we want.
-     * @property groups
-     * @type {string: string}
-     */
-    groups: null,
-
-    /**
-     * Individual drag/drop instances can be locked.  This will prevent
-     * onmousedown start drag.
-     * @property locked
-     * @type boolean
-     * @private
-     */
-    locked: false,
-
-    /**
-     * Lock this instance
-     * @method lock
-     */
-    lock: function() { this.locked = true; },
-
-    /**
-     * Unlock this instace
-     * @method unlock
-     */
-    unlock: function() { this.locked = false; },
-
-    /**
-     * By default, all insances can be a drop target.  This can be disabled by
-     * setting isTarget to false.
-     * @method isTarget
-     * @type boolean
-     */
-    isTarget: true,
-
-    /**
-     * The padding configured for this drag and drop object for calculating
-     * the drop zone intersection with this object.
-     * @method padding
-     * @type int[]
-     */
-    padding: null,
-
     /**
-     * Cached reference to the linked element
-     * @property _domRef
-     * @private
+     * Mangle Links
      */
-    _domRef: null,
-
+    
+    InlineLexer.prototype.mangle = function(text) {
+      if (!this.options.mangle) { return text; }
+      var out = ''
+        , l = text.length
+        , i = 0
+        , ch;
+    
+      for (; i < l; i++) {
+        ch = text.charCodeAt(i);
+        if (Math.random() > 0.5) {
+          ch = 'x' + ch.toString(16);
+        }
+        out += '&#' + ch + ';';
+      }
+    
+      return out;
+    };
+    
     /**
-     * Internal typeof flag
-     * @property __ygDragDrop
-     * @private
+     * Renderer
      */
-    __ygDragDrop: true,
-
+    
+     /**
+         * eval:var:Renderer
+    */
+    
+    var Renderer   = function (options) {
+      this.options = options || {};
+    }
+    
+    Renderer.prototype.code = function(code, lang, escaped) {
+      if (this.options.highlight) {
+        var out = this.options.highlight(code, lang);
+        if (out != null && out !== code) {
+          escaped = true;
+          code = out;
+        }
+      } else {
+            // hack!!! - it's already escapeD?
+            escaped = true;
+      }
+    
+      if (!lang) {
+        return '<pre><code>'
+          + (escaped ? code : escape(code, true))
+          + '\n</code></pre>';
+      }
+    
+      return '<pre><code class="'
+        + this.options.langPrefix
+        + escape(lang, true)
+        + '">'
+        + (escaped ? code : escape(code, true))
+        + '\n</code></pre>\n';
+    };
+    
+    Renderer.prototype.blockquote = function(quote) {
+      return '<blockquote>\n' + quote + '</blockquote>\n';
+    };
+    
+    Renderer.prototype.html = function(html) {
+      return html;
+    };
+    
+    Renderer.prototype.heading = function(text, level, raw) {
+      return '<h'
+        + level
+        + ' id="'
+        + this.options.headerPrefix
+        + raw.toLowerCase().replace(/[^\w]+/g, '-')
+        + '">'
+        + text
+        + '</h'
+        + level
+        + '>\n';
+    };
+    
+    Renderer.prototype.hr = function() {
+      return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
+    };
+    
+    Renderer.prototype.list = function(body, ordered) {
+      var type = ordered ? 'ol' : 'ul';
+      return '<' + type + '>\n' + body + '</' + type + '>\n';
+    };
+    
+    Renderer.prototype.listitem = function(text) {
+      return '<li>' + text + '</li>\n';
+    };
+    
+    Renderer.prototype.paragraph = function(text) {
+      return '<p>' + text + '</p>\n';
+    };
+    
+    Renderer.prototype.table = function(header, body) {
+      return '<table class="table table-striped">\n'
+        + '<thead>\n'
+        + header
+        + '</thead>\n'
+        + '<tbody>\n'
+        + body
+        + '</tbody>\n'
+        + '</table>\n';
+    };
+    
+    Renderer.prototype.tablerow = function(content) {
+      return '<tr>\n' + content + '</tr>\n';
+    };
+    
+    Renderer.prototype.tablecell = function(content, flags) {
+      var type = flags.header ? 'th' : 'td';
+      var tag = flags.align
+        ? '<' + type + ' style="text-align:' + flags.align + '">'
+        : '<' + type + '>';
+      return tag + content + '</' + type + '>\n';
+    };
+    
+    // span level renderer
+    Renderer.prototype.strong = function(text) {
+      return '<strong>' + text + '</strong>';
+    };
+    
+    Renderer.prototype.em = function(text) {
+      return '<em>' + text + '</em>';
+    };
+    
+    Renderer.prototype.codespan = function(text) {
+      return '<code>' + text + '</code>';
+    };
+    
+    Renderer.prototype.br = function() {
+      return this.options.xhtml ? '<br/>' : '<br>';
+    };
+    
+    Renderer.prototype.del = function(text) {
+      return '<del>' + text + '</del>';
+    };
+    
+    Renderer.prototype.link = function(href, title, text) {
+      if (this.options.sanitize) {
+        try {
+          var prot = decodeURIComponent(unescape(href))
+            .replace(/[^\w:]/g, '')
+            .toLowerCase();
+        } catch (e) {
+          return '';
+        }
+        if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
+          return '';
+        }
+      }
+      var out = '<a href="' + href + '"';
+      if (title) {
+        out += ' title="' + title + '"';
+      }
+      out += '>' + text + '</a>';
+      return out;
+    };
+    
+    Renderer.prototype.image = function(href, title, text) {
+      var out = '<img src="' + href + '" alt="' + text + '"';
+      if (title) {
+        out += ' title="' + title + '"';
+      }
+      out += this.options.xhtml ? '/>' : '>';
+      return out;
+    };
+    
+    Renderer.prototype.text = function(text) {
+      return text;
+    };
+    
     /**
-     * Set to true when horizontal contraints are applied
-     * @property constrainX
-     * @type boolean
-     * @private
+     * Parsing & Compiling
      */
-    constrainX: false,
-
+         /**
+         * eval:var:Parser
+    */
+    
+    var Parser= function (options) {
+      this.tokens = [];
+      this.token = null;
+      this.options = options || marked.defaults;
+      this.options.renderer = this.options.renderer || new Renderer;
+      this.renderer = this.options.renderer;
+      this.renderer.options = this.options;
+    }
+    
     /**
-     * Set to true when vertical contraints are applied
-     * @property constrainY
-     * @type boolean
-     * @private
+     * Static Parse Method
      */
-    constrainY: false,
-
+    
+    Parser.parse = function(src, options, renderer) {
+      var parser = new Parser(options, renderer);
+      return parser.parse(src);
+    };
+    
     /**
-     * The left constraint
-     * @property minX
-     * @type int
-     * @private
+     * Parse Loop
      */
-    minX: 0,
-
+    
+    Parser.prototype.parse = function(src) {
+      this.inline = new InlineLexer(src.links, this.options, this.renderer);
+      this.tokens = src.reverse();
+    
+      var out = '';
+      while (this.next()) {
+        out += this.tok();
+      }
+    
+      return out;
+    };
+    
     /**
-     * The right constraint
-     * @property maxX
-     * @type int
-     * @private
+     * Next Token
      */
-    maxX: 0,
-
+    
+    Parser.prototype.next = function() {
+      return this.token = this.tokens.pop();
+    };
+    
     /**
-     * The up constraint
-     * @property minY
-     * @type int
-     * @type int
-     * @private
+     * Preview Next Token
      */
-    minY: 0,
-
+    
+    Parser.prototype.peek = function() {
+      return this.tokens[this.tokens.length - 1] || 0;
+    };
+    
     /**
-     * The down constraint
-     * @property maxY
-     * @type int
-     * @private
+     * Parse Text Tokens
      */
-    maxY: 0,
-
+    
+    Parser.prototype.parseText = function() {
+      var body = this.token.text;
+    
+      while (this.peek().type === 'text') {
+        body += '\n' + this.next().text;
+      }
+    
+      return this.inline.output(body);
+    };
+    
     /**
-     * Maintain offsets when we resetconstraints.  Set to true when you want
-     * the position of the element relative to its parent to stay the same
-     * when the page changes
-     *
-     * @property maintainOffset
-     * @type boolean
+     * Parse Current Token
      */
-    maintainOffset: false,
-
-    /**
-     * 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 xTicks
-     * @type int[]
-     */
-    xTicks: null,
-
+    
+    Parser.prototype.tok = function() {
+      switch (this.token.type) {
+        case 'space': {
+          return '';
+        }
+        case 'hr': {
+          return this.renderer.hr();
+        }
+        case 'heading': {
+          return this.renderer.heading(
+            this.inline.output(this.token.text),
+            this.token.depth,
+            this.token.text);
+        }
+        case 'code': {
+          return this.renderer.code(this.token.text,
+            this.token.lang,
+            this.token.escaped);
+        }
+        case 'table': {
+          var header = ''
+            , body = ''
+            , i
+            , row
+            , cell
+            , flags
+            , j;
+    
+          // header
+          cell = '';
+          for (i = 0; i < this.token.header.length; i++) {
+            flags = { header: true, align: this.token.align[i] };
+            cell += this.renderer.tablecell(
+              this.inline.output(this.token.header[i]),
+              { header: true, align: this.token.align[i] }
+            );
+          }
+          header += this.renderer.tablerow(cell);
+    
+          for (i = 0; i < this.token.cells.length; i++) {
+            row = this.token.cells[i];
+    
+            cell = '';
+            for (j = 0; j < row.length; j++) {
+              cell += this.renderer.tablecell(
+                this.inline.output(row[j]),
+                { header: false, align: this.token.align[j] }
+              );
+            }
+    
+            body += this.renderer.tablerow(cell);
+          }
+          return this.renderer.table(header, body);
+        }
+        case 'blockquote_start': {
+          var body = '';
+    
+          while (this.next().type !== 'blockquote_end') {
+            body += this.tok();
+          }
+    
+          return this.renderer.blockquote(body);
+        }
+        case 'list_start': {
+          var body = ''
+            , ordered = this.token.ordered;
+    
+          while (this.next().type !== 'list_end') {
+            body += this.tok();
+          }
+    
+          return this.renderer.list(body, ordered);
+        }
+        case 'list_item_start': {
+          var body = '';
+    
+          while (this.next().type !== 'list_item_end') {
+            body += this.token.type === 'text'
+              ? this.parseText()
+              : this.tok();
+          }
+    
+          return this.renderer.listitem(body);
+        }
+        case 'loose_item_start': {
+          var body = '';
+    
+          while (this.next().type !== 'list_item_end') {
+            body += this.tok();
+          }
+    
+          return this.renderer.listitem(body);
+        }
+        case 'html': {
+          var html = !this.token.pre && !this.options.pedantic
+            ? this.inline.output(this.token.text)
+            : this.token.text;
+          return this.renderer.html(html);
+        }
+        case 'paragraph': {
+          return this.renderer.paragraph(this.inline.output(this.token.text));
+        }
+        case 'text': {
+          return this.renderer.paragraph(this.parseText());
+        }
+      }
+    };
+  
+    
     /**
-     * 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 yTicks
-     * @type int[]
+     * Marked
      */
-    yTicks: null,
-
+         /**
+         * eval:var:marked
+    */
+    var marked = function (src, opt, callback) {
+      if (callback || typeof opt === 'function') {
+        if (!callback) {
+          callback = opt;
+          opt = null;
+        }
+    
+        opt = merge({}, marked.defaults, opt || {});
+    
+        var highlight = opt.highlight
+          , tokens
+          , pending
+          , i = 0;
+    
+        try {
+          tokens = Lexer.lex(src, opt)
+        } catch (e) {
+          return callback(e);
+        }
+    
+        pending = tokens.length;
+         /**
+         * eval:var:done
+    */
+        var done = function(err) {
+          if (err) {
+            opt.highlight = highlight;
+            return callback(err);
+          }
+    
+          var out;
+    
+          try {
+            out = Parser.parse(tokens, opt);
+          } catch (e) {
+            err = e;
+          }
+    
+          opt.highlight = highlight;
+    
+          return err
+            ? callback(err)
+            : callback(null, out);
+        };
+    
+        if (!highlight || highlight.length < 3) {
+          return done();
+        }
+    
+        delete opt.highlight;
+    
+        if (!pending) { return done(); }
+    
+        for (; i < tokens.length; i++) {
+          (function(token) {
+            if (token.type !== 'code') {
+              return --pending || done();
+            }
+            return highlight(token.text, token.lang, function(err, code) {
+              if (err) { return done(err); }
+              if (code == null || code === token.text) {
+                return --pending || done();
+              }
+              token.text = code;
+              token.escaped = true;
+              --pending || done();
+            });
+          })(tokens[i]);
+        }
+    
+        return;
+      }
+      try {
+        if (opt) { opt = merge({}, marked.defaults, opt); }
+        return Parser.parse(Lexer.lex(src, opt), opt);
+      } catch (e) {
+        e.message += '\nPlease report this to https://github.com/chjj/marked.';
+        if ((opt || marked.defaults).silent) {
+          return '<p>An error occured:</p><pre>'
+            + escape(e.message + '', true)
+            + '</pre>';
+        }
+        throw e;
+      }
+    }
+    
     /**
-     * By default the drag and drop instance will only respond to the primary
-     * button click (left button for a right-handed mouse).  Set to true to
-     * allow drag and drop to start with any mouse click that is propogated
-     * by the browser
-     * @property primaryButtonOnly
-     * @type boolean
+     * Options
      */
-    primaryButtonOnly: true,
-
+    
+    marked.options =
+    marked.setOptions = function(opt) {
+      merge(marked.defaults, opt);
+      return marked;
+    };
+    
+    marked.defaults = {
+      gfm: true,
+      tables: true,
+      breaks: false,
+      pedantic: false,
+      sanitize: false,
+      sanitizer: null,
+      mangle: true,
+      smartLists: false,
+      silent: false,
+      highlight: null,
+      langPrefix: 'lang-',
+      smartypants: false,
+      headerPrefix: '',
+      renderer: new Renderer,
+      xhtml: false
+    };
+    
     /**
-     * The availabe property is false until the linked dom element is accessible.
-     * @property available
-     * @type boolean
+     * Expose
      */
-    available: false,
-
+    
+    marked.Parser = Parser;
+    marked.parser = Parser.parse;
+    
+    marked.Renderer = Renderer;
+    
+    marked.Lexer = Lexer;
+    marked.lexer = Lexer.lex;
+    
+    marked.InlineLexer = InlineLexer;
+    marked.inlineLexer = InlineLexer.output;
+    
+    marked.parse = marked;
+    
+    Roo.Markdown.marked = marked;
+
+})();/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+
+
+/*
+ * These classes are derivatives of the similarly named classes in the YUI Library.
+ * The original license:
+ * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+ * Code licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ */
+
+(function() {
+
+var Event=Roo.EventManager;
+var Dom=Roo.lib.Dom;
+
+/**
+ * @class Roo.dd.DragDrop
+ * @extends Roo.util.Observable
+ * Defines the interface and base operation of items that that can be
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that
+ * was clicked matches a handle element.  By default this is the linked
+ * element, but there are times that you will want only a portion of the
+ * linked element to initiate the drag operation, and the setHandleElId()
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any
+ * other DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new Roo.dd.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would
+ * actually happen if you were to run the code above.  Normally you would
+ * override this class or one of the default implementations, but you can
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *  &nbsp;&nbsp;alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @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
+ *                Valid properties for DragDrop:
+ *                    padding, isTarget, maintainOffset, primaryButtonOnly
+ */
+Roo.dd.DragDrop = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+    }
+    
+};
+
+Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
+
     /**
-     * By default, drags can only be initiated if the mousedown occurs in the
-     * region the linked element is.  This is done in part to work around a
-     * bug in some browsers that mis-report the mousedown if the previous
-     * mouseup happened outside of the window.  This property is set to true
-     * if outer handles are defined.
-     *
-     * @property hasOuterHandles
-     * @type boolean
-     * @default false
+     * The id of the element associated with this object.  This is what we
+     * refer to as the "linked element" because the size and position of
+     * this element is used to determine when the drag and drop objects have
+     * interacted.
+     * @property id
+     * @type String
      */
-    hasOuterHandles: false,
+    id: null,
 
     /**
-     * Code that executes immediately before the startDrag event
-     * @method b4StartDrag
-     * @private
+     * Configuration attributes passed into the constructor
+     * @property config
+     * @type object
      */
-    b4StartDrag: function(x, y) { },
+    config: null,
 
     /**
-     * Abstract method called after a drag/drop object is clicked
-     * and the drag or mousedown time thresholds have beeen met.
-     * @method startDrag
-     * @param {int} X click location
-     * @param {int} Y click location
+     * The id of the element that will be dragged.  By default this is same
+     * as the linked element , but could be changed to another element. Ex:
+     * Roo.dd.DDProxy
+     * @property dragElId
+     * @type String
+     * @private
      */
-    startDrag: function(x, y) { /* override this */ },
+    dragElId: null,
 
     /**
-     * Code that executes immediately before the onDrag event
-     * @method b4Drag
+     * the id of the element that initiates the drag operation.  By default
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the
+     * header element within the linked html element is clicked.
+     * @property handleElId
+     * @type String
      * @private
      */
-    b4Drag: function(e) { },
+    handleElId: null,
 
     /**
-     * Abstract method called during the onMouseMove event while dragging an
-     * object.
-     * @method onDrag
-     * @param {Event} e the mousemove event
+     * An associative array of HTML tags that will be ignored if clicked.
+     * @property invalidHandleTypes
+     * @type {string: string}
      */
-    onDrag: function(e) { /* override this */ },
+    invalidHandleTypes: null,
 
     /**
-     * Abstract method called when this element fist begins hovering over
-     * another DragDrop obj
-     * @method onDragEnter
-     * @param {Event} e the mousemove event
-     * @param {String|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.
+     * An associative array of ids for elements that will be ignored if clicked
+     * @property invalidHandleIds
+     * @type {string: string}
      */
-    onDragEnter: function(e, id) { /* override this */ },
+    invalidHandleIds: null,
 
     /**
-     * Code that executes immediately before the onDragOver event
-     * @method b4DragOver
-     * @private
+     * An indexted array of css class names for elements that will be ignored
+     * if clicked.
+     * @property invalidHandleClasses
+     * @type string[]
      */
-    b4DragOver: function(e) { },
+    invalidHandleClasses: null,
 
     /**
-     * Abstract method called when this element is hovering over another
-     * DragDrop obj
-     * @method onDragOver
-     * @param {Event} e the mousemove event
-     * @param {String|DragDrop[]} id In POINT mode, the element
-     * id this is hovering over.  In INTERSECT mode, an array of dd items
-     * being hovered over.
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageX
+     * @type int
+     * @private
      */
-    onDragOver: function(e, id) { /* override this */ },
+    startPageX: 0,
 
     /**
-     * Code that executes immediately before the onDragOut event
-     * @method b4DragOut
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageY
+     * @type int
      * @private
      */
-    b4DragOut: function(e) { },
+    startPageY: 0,
 
     /**
-     * Abstract method called when we are no longer hovering over an element
-     * @method onDragOut
-     * @param {Event} e the mousemove event
-     * @param {String|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.
+     * The group defines a logical collection of DragDrop objects that are
+     * related.  Instances only get events when interacting with other
+     * DragDrop object in the same group.  This lets us define multiple
+     * groups using a single DragDrop subclass if we want.
+     * @property groups
+     * @type {string: string}
      */
-    onDragOut: function(e, id) { /* override this */ },
+    groups: null,
 
     /**
-     * Code that executes immediately before the onDragDrop event
-     * @method b4DragDrop
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     * @property locked
+     * @type boolean
      * @private
      */
-    b4DragDrop: function(e) { },
+    locked: false,
 
     /**
-     * Abstract method called when this item is dropped on another DragDrop
-     * obj
-     * @method onDragDrop
-     * @param {Event} e the mouseup event
-     * @param {String|DragDrop[]} id In POINT mode, the element
-     * id this was dropped on.  In INTERSECT mode, an array of dd items this
-     * was dropped on.
+     * Lock this instance
+     * @method lock
      */
-    onDragDrop: function(e, id) { /* override this */ },
+    lock: function() { this.locked = true; },
 
     /**
-     * Abstract method called when this item is dropped on an area with no
-     * drop target
-     * @method onInvalidDrop
-     * @param {Event} e the mouseup event
+     * Unlock this instace
+     * @method unlock
      */
-    onInvalidDrop: function(e) { /* override this */ },
+    unlock: function() { this.locked = false; },
 
     /**
-     * Code that executes immediately before the endDrag event
-     * @method b4EndDrag
-     * @private
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     * @method isTarget
+     * @type boolean
      */
-    b4EndDrag: function(e) { },
+    isTarget: true,
 
     /**
-     * Fired when we are done dragging the object
-     * @method endDrag
-     * @param {Event} e the mouseup event
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     * @method padding
+     * @type int[]
      */
-    endDrag: function(e) { /* override this */ },
+    padding: null,
 
     /**
-     * Code executed immediately before the onMouseDown event
+     * Cached reference to the linked element
+     * @property _domRef
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @property __ygDragDrop
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     * @property constrainX
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     * @property constrainY
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     * @property minX
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     * @property maxX
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint
+     * @property minY
+     * @type int
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint
+     * @property maxY
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Set to true when you want
+     * the position of the element relative to its parent to stay the same
+     * when the page changes
+     *
+     * @property maintainOffset
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * 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 xTicks
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * 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 yTicks
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @property primaryButtonOnly
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * The availabe property is false until the linked dom element is accessible.
+     * @property available
+     * @type boolean
+     */
+    available: false,
+
+    /**
+     * By default, drags can only be initiated if the mousedown occurs in the
+     * region the linked element is.  This is done in part to work around a
+     * bug in some browsers that mis-report the mousedown if the previous
+     * mouseup happened outside of the window.  This property is set to true
+     * if outer handles are defined.
+     *
+     * @property hasOuterHandles
+     * @type boolean
+     * @default false
+     */
+    hasOuterHandles: false,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @method b4StartDrag
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     * @method startDrag
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @method b4Drag
+     * @private
+     */
+    b4Drag: function(e) { },
+
+    /**
+     * Abstract method called during the onMouseMove event while dragging an
+     * object.
+     * @method onDrag
+     * @param {Event} e the mousemove event
+     */
+    onDrag: function(e) { /* override this */ },
+
+    /**
+     * Abstract method called when this element fist begins hovering over
+     * another DragDrop obj
+     * @method onDragEnter
+     * @param {Event} e the mousemove event
+     * @param {String|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.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @method b4DragOver
+     * @private
+     */
+    b4DragOver: function(e) { },
+
+    /**
+     * Abstract method called when this element is hovering over another
+     * DragDrop obj
+     * @method onDragOver
+     * @param {Event} e the mousemove event
+     * @param {String|DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @method b4DragOut
+     * @private
+     */
+    b4DragOut: function(e) { },
+
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     * @method onDragOut
+     * @param {Event} e the mousemove event
+     * @param {String|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.
+     */
+    onDragOut: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @method b4DragDrop
+     * @private
+     */
+    b4DragDrop: function(e) { },
+
+    /**
+     * Abstract method called when this item is dropped on another DragDrop
+     * obj
+     * @method onDragDrop
+     * @param {Event} e the mouseup event
+     * @param {String|DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
+
+    /**
+     * Abstract method called when this item is dropped on an area with no
+     * drop target
+     * @method onInvalidDrop
+     * @param {Event} e the mouseup event
+     */
+    onInvalidDrop: function(e) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the endDrag event
+     * @method b4EndDrag
+     * @private
+     */
+    b4EndDrag: function(e) { },
+
+    /**
+     * Fired when we are done dragging the object
+     * @method endDrag
+     * @param {Event} e the mouseup event
+     */
+    endDrag: function(e) { /* override this */ },
+
+    /**
+     * Code executed immediately before the onMouseDown event
      * @method b4MouseDown
      * @param {Event} e the mousedown event
      * @private
@@ -21323,1167 +21780,13 @@ Roo.dd.ScrollManager = function(){
          */
         refreshCache : function(){
             for(var id in els){
-                if(typeof els[id] == 'object'){ // for people extending the object prototype
-                    els[id]._region = els[id].getRegion();
-                }
-            }
-        }
-    };
-}();/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.dd.Registry
- * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
- * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
- * @singleton
- */
-Roo.dd.Registry = function(){
-    var elements = {}; 
-    var handles = {}; 
-    var autoIdSeed = 0;
-
-    var getId = function(el, autogen){
-        if(typeof el == "string"){
-            return el;
-        }
-        var id = el.id;
-        if(!id && autogen !== false){
-            id = "roodd-" + (++autoIdSeed);
-            el.id = id;
-        }
-        return id;
-    };
-    
-    return {
-    /**
-     * Register a drag drop element
-     * @param {String|HTMLElement} element The id or DOM node to register
-     * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
-     * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
-     * knows how to interpret, plus there are some specific properties known to the Registry that should be
-     * populated in the data object (if applicable):
-     * <pre>
-Value      Description<br />
----------  ------------------------------------------<br />
-handles    Array of DOM nodes that trigger dragging<br />
-           for the element being registered<br />
-isHandle   True if the element passed in triggers<br />
-           dragging itself, else false
-</pre>
-     */
-        register : function(el, data){
-            data = data || {};
-            if(typeof el == "string"){
-                el = document.getElementById(el);
-            }
-            data.ddel = el;
-            elements[getId(el)] = data;
-            if(data.isHandle !== false){
-                handles[data.ddel.id] = data;
-            }
-            if(data.handles){
-                var hs = data.handles;
-                for(var i = 0, len = hs.length; i < len; i++){
-                       handles[getId(hs[i])] = data;
-                }
-            }
-        },
-
-    /**
-     * Unregister a drag drop element
-     * @param {String|HTMLElement}  element The id or DOM node to unregister
-     */
-        unregister : function(el){
-            var id = getId(el, false);
-            var data = elements[id];
-            if(data){
-                delete elements[id];
-                if(data.handles){
-                    var hs = data.handles;
-                    for(var i = 0, len = hs.length; i < len; i++){
-                       delete handles[getId(hs[i], false)];
-                    }
-                }
-            }
-        },
-
-    /**
-     * Returns the handle registered for a DOM Node by id
-     * @param {String|HTMLElement} id The DOM node or id to look up
-     * @return {Object} handle The custom handle data
-     */
-        getHandle : function(id){
-            if(typeof id != "string"){ // must be element?
-                id = id.id;
-            }
-            return handles[id];
-        },
-
-    /**
-     * Returns the handle that is registered for the DOM node that is the target of the event
-     * @param {Event} e The event
-     * @return {Object} handle The custom handle data
-     */
-        getHandleFromEvent : function(e){
-            var t = Roo.lib.Event.getTarget(e);
-            return t ? handles[t.id] : null;
-        },
-
-    /**
-     * Returns a custom data object that is registered for a DOM node by id
-     * @param {String|HTMLElement} id The DOM node or id to look up
-     * @return {Object} data The custom data
-     */
-        getTarget : function(id){
-            if(typeof id != "string"){ // must be element?
-                id = id.id;
-            }
-            return elements[id];
-        },
-
-    /**
-     * Returns a custom data object that is registered for the DOM node that is the target of the event
-     * @param {Event} e The event
-     * @return {Object} data The custom data
-     */
-        getTargetFromEvent : function(e){
-            var t = Roo.lib.Event.getTarget(e);
-            return t ? elements[t.id] || handles[t.id] : null;
-        }
-    };
-}();/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.dd.StatusProxy
- * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
- * default drag proxy used by all Roo.dd components.
- * @constructor
- * @param {Object} config
- */
-Roo.dd.StatusProxy = function(config){
-    Roo.apply(this, config);
-    this.id = this.id || Roo.id();
-    this.el = new Roo.Layer({
-        dh: {
-            id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
-                {tag: "div", cls: "x-dd-drop-icon"},
-                {tag: "div", cls: "x-dd-drag-ghost"}
-            ]
-        }, 
-        shadow: !config || config.shadow !== false
-    });
-    this.ghost = Roo.get(this.el.dom.childNodes[1]);
-    this.dropStatus = this.dropNotAllowed;
-};
-
-Roo.dd.StatusProxy.prototype = {
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : "x-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 : "x-dd-drop-nodrop",
-
-    /**
-     * 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.replaceClass(this.dropStatus, cssClass);
-            this.dropStatus = cssClass;
-        }
-    },
-
-    /**
-     * 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 = "x-dd-drag-proxy " + this.dropNotAllowed;
-        this.dropStatus = this.dropNotAllowed;
-        if(clearGhost){
-            this.ghost.update("");
-        }
-    },
-
-    /**
-     * Updates the contents of the ghost element
-     * @param {String} html The html that will replace the current innerHTML of the ghost element
-     */
-    update : function(html){
-        if(typeof html == "string"){
-            this.ghost.update(html);
-        }else{
-            this.ghost.update("");
-            html.style.margin = "0";
-            this.ghost.dom.appendChild(html);
-        }
-        // ensure float = none set?? cant remember why though.
-        var el = this.ghost.dom.firstChild;
-               if(el){
-                       Roo.fly(el).setStyle('float', 'none');
-               }
-    },
-    
-    /**
-     * Returns the underlying proxy {@link Roo.Layer}
-     * @return {Roo.Layer} el
-    */
-    getEl : function(){
-        return this.el;
-    },
-
-    /**
-     * Returns the ghost element
-     * @return {Roo.Element} el
-     */
-    getGhost : function(){
-        return this.ghost;
-    },
-
-    /**
-     * Hides the proxy
-     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
-     */
-    hide : function(clear){
-        this.el.hide();
-        if(clear){
-            this.reset(true);
-        }
-    },
-
-    /**
-     * Stops the repair animation if it's currently running
-     */
-    stop : function(){
-        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
-            this.anim.stop();
-        }
-    },
-
-    /**
-     * Displays this proxy
-     */
-    show : function(){
-        this.el.show();
-    },
-
-    /**
-     * Force the Layer to sync its shadow and shim positions to the element
-     */
-    sync : function(){
-        this.el.sync();
-    },
-
-    /**
-     * 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 in which to execute the callback
-     */
-    repair : function(xy, callback, scope){
-        this.callback = callback;
-        this.scope = scope;
-        if(xy && this.animRepair !== false){
-            this.el.addClass("x-dd-drag-repair");
-            this.el.hideUnders(true);
-            this.anim = this.el.shift({
-                duration: this.repairDuration || .5,
-                easing: 'easeOut',
-                xy: xy,
-                stopFx: true,
-                callback: this.afterRepair,
-                scope: this
-            });
-        }else{
-            this.afterRepair();
-        }
-    },
-
-    // private
-    afterRepair : function(){
-        this.hide(true);
-        if(typeof this.callback == "function"){
-            this.callback.call(this.scope || this);
-        }
-        this.callback = null;
-        this.scope = null;
-    }
-};/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.dd.DragSource
- * @extends Roo.dd.DDProxy
- * A simple class that provides the basic implementation needed to make any element draggable.
- * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
- */
-Roo.dd.DragSource = function(el, config){
-    this.el = Roo.get(el);
-    this.dragData = {};
-    
-    Roo.apply(this, config);
-    
-    if(!this.proxy){
-        this.proxy = new Roo.dd.StatusProxy();
-    }
-
-    Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
-          {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
-    
-    this.dragging = false;
-};
-
-Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : "x-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").
-     */
-    dropNotAllowed : "x-dd-drop-nodrop",
-
-    /**
-     * Returns the data object associated with this drag source
-     * @return {Object} data An object containing arbitrary data
-     */
-    getDragData : function(e){
-        return this.dragData;
-    },
-
-    // private
-    onDragEnter : function(e, id){
-        var target = Roo.dd.DragDropMgr.getDDById(id);
-        this.cachedTarget = target;
-        if(this.beforeDragEnter(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                var status = target.notifyEnter(this, e, this.dragData);
-                this.proxy.setStatus(status);
-            }else{
-                this.proxy.setStatus(this.dropAllowed);
-            }
-            
-            if(this.afterDragEnter){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * when the dragged item enters the drop target by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragEnter
-                 */
-                this.afterDragEnter(target, e, id);
-            }
-        }
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action
-     * before the dragged item enters the drop target and optionally cancel the onDragEnter.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
-     */
-    beforeDragEnter : function(target, e, id){
-        return true;
-    },
-
-    // private
-    alignElWithMouse: function() {
-        Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
-        this.proxy.sync();
-    },
-
-    // private
-    onDragOver : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragOver(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                var status = target.notifyOver(this, e, this.dragData);
-                this.proxy.setStatus(status);
-            }
-
-            if(this.afterDragOver){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * while the dragged item is over the drop target by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragOver
-                 */
-                this.afterDragOver(target, e, id);
-            }
-        }
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action
-     * while the dragged item is over the drop target and optionally cancel the onDragOver.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
-     */
-    beforeDragOver : function(target, e, id){
-        return true;
-    },
-
-    // private
-    onDragOut : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragOut(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                target.notifyOut(this, e, this.dragData);
-            }
-            this.proxy.reset();
-            if(this.afterDragOut){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * after the dragged item is dragged out of the target without dropping.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragOut
-                 */
-                this.afterDragOut(target, e, id);
-            }
-        }
-        this.cachedTarget = null;
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action before the dragged
-     * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
-     */
-    beforeDragOut : function(target, e, id){
-        return true;
-    },
-    
-    // private
-    onDragDrop : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragDrop(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
-                    this.onValidDrop(target, e, id);
-                }else{
-                    this.onInvalidDrop(target, e, id);
-                }
-            }else{
-                this.onValidDrop(target, e, id);
-            }
-            
-            if(this.afterDragDrop){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * after a valid drag drop has occurred by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dropped element
-                 * @method afterDragDrop
-                 */
-                this.afterDragDrop(target, e, id);
-            }
-        }
-        delete this.cachedTarget;
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action before the dragged
-     * item is dropped onto the target and optionally cancel the onDragDrop.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
-     */
-    beforeDragDrop : function(target, e, id){
-        return true;
-    },
-
-    // private
-    onValidDrop : function(target, e, id){
-        this.hideProxy();
-        if(this.afterValidDrop){
-            /**
-             * An empty function by default, but provided so that you can perform a custom action
-             * after a valid drop has occurred by providing an implementation.
-             * @param {Object} target The target DD 
-             * @param {Event} e The event object
-             * @param {String} id The id of the dropped element
-             * @method afterInvalidDrop
-             */
-            this.afterValidDrop(target, e, id);
-        }
-    },
-
-    // private
-    getRepairXY : function(e, data){
-        return this.el.getXY();  
-    },
-
-    // private
-    onInvalidDrop : function(target, e, id){
-        this.beforeInvalidDrop(target, e, id);
-        if(this.cachedTarget){
-            if(this.cachedTarget.isNotifyTarget){
-                this.cachedTarget.notifyOut(this, e, this.dragData);
-            }
-            this.cacheTarget = null;
-        }
-        this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
-
-        if(this.afterInvalidDrop){
-            /**
-             * An empty function by default, but provided so that you can perform a custom action
-             * after an invalid drop has occurred by providing an implementation.
-             * @param {Event} e The event object
-             * @param {String} id The id of the dropped element
-             * @method afterInvalidDrop
-             */
-            this.afterInvalidDrop(e, id);
-        }
-    },
-
-    // private
-    afterRepair : function(){
-        if(Roo.enableFx){
-            this.el.highlight(this.hlColor || "c3daf9");
-        }
-        this.dragging = false;
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action after an invalid
-     * drop has occurred.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
-     */
-    beforeInvalidDrop : function(target, e, id){
-        return true;
-    },
-
-    // private
-    handleMouseDown : function(e){
-        if(this.dragging) {
-            return;
-        }
-        var data = this.getDragData(e);
-        if(data && this.onBeforeDrag(data, e) !== false){
-            this.dragData = data;
-            this.proxy.stop();
-            Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
-        } 
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action before the initial
-     * drag event begins and optionally cancel it.
-     * @param {Object} data An object containing arbitrary data to be shared with drop targets
-     * @param {Event} e The event object
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
-     */
-    onBeforeDrag : function(data, e){
-        return true;
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action once the initial
-     * drag event has begun.  The drag cannot be canceled from this function.
-     * @param {Number} x The x position of the click on the dragged object
-     * @param {Number} y The y position of the click on the dragged object
-     */
-    onStartDrag : Roo.emptyFn,
-
-    // private - YUI override
-    startDrag : function(x, y){
-        this.proxy.reset();
-        this.dragging = true;
-        this.proxy.update("");
-        this.onInitDrag(x, y);
-        this.proxy.show();
-    },
-
-    // private
-    onInitDrag : function(x, y){
-        var clone = this.el.dom.cloneNode(true);
-        clone.id = Roo.id(); // prevent duplicate ids
-        this.proxy.update(clone);
-        this.onStartDrag(x, y);
-        return true;
-    },
-
-    /**
-     * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
-     * @return {Roo.dd.StatusProxy} proxy The StatusProxy
-     */
-    getProxy : function(){
-        return this.proxy;  
-    },
-
-    /**
-     * Hides the drag source's {@link Roo.dd.StatusProxy}
-     */
-    hideProxy : function(){
-        this.proxy.hide();  
-        this.proxy.reset(true);
-        this.dragging = false;
-    },
-
-    // private
-    triggerCacheRefresh : function(){
-        Roo.dd.DDM.refreshCache(this.groups);
-    },
-
-    // private - override to prevent hiding
-    b4EndDrag: function(e) {
-    },
-
-    // private - override to prevent moving
-    endDrag : function(e){
-        this.onEndDrag(this.dragData, e);
-    },
-
-    // private
-    onEndDrag : function(data, e){
-    },
-    
-    // private - pin to cursor
-    autoOffset : function(x, y) {
-        this.setDelta(-12, -20);
-    }    
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-
-/**
- * @class Roo.dd.DropTarget
- * @extends Roo.dd.DDTarget
- * A simple class that provides the basic implementation needed to make any element a drop target that can have
- * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
- * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
- */
-Roo.dd.DropTarget = function(el, config){
-    this.el = Roo.get(el);
-    
-    var listeners = false; ;
-    if (config && config.listeners) {
-        listeners= config.listeners;
-        delete config.listeners;
-    }
-    Roo.apply(this, config);
-    
-    if(this.containerScroll){
-        Roo.dd.ScrollManager.register(this.el);
-    }
-    this.addEvents( {
-         /**
-         * @scope Roo.dd.DropTarget
-         */
-         
-         /**
-         * @event enter
-         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
-         * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
-         * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
-         * 
-         * IMPORTANT : it should set this.overClass and this.dropAllowed
-         * 
-         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
-         * @param {Event} e The event
-         * @param {Object} data An object containing arbitrary data supplied by the drag source
-         */
-        "enter" : true,
-        
-         /**
-         * @event over
-         * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
-         * This method will be called on every mouse movement while the drag source is over the drop target.
-         * This default implementation simply returns the dropAllowed config value.
-         * 
-         * IMPORTANT : it should set this.dropAllowed
-         * 
-         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
-         * @param {Event} e The event
-         * @param {Object} data An object containing arbitrary data supplied by the drag source
-         
-         */
-        "over" : true,
-        /**
-         * @event out
-         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
-         * out of the target without dropping.  This default implementation simply removes the CSS class specified by
-         * overClass (if any) from the drop element.
-         * 
-         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
-         * @param {Event} e The event
-         * @param {Object} data An object containing arbitrary data supplied by the drag source
-         */
-         "out" : true,
-         
-        /**
-         * @event drop
-         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
-         * been dropped on it.  This method has no default implementation and returns false, so you must provide an
-         * implementation that does something to process the drop event and returns true so that the drag source's
-         * repair action does not run.
-         * 
-         * IMPORTANT : it should set this.success
-         * 
-         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
-         * @param {Event} e The event
-         * @param {Object} data An object containing arbitrary data supplied by the drag source
-        */
-         "drop" : true
-    });
-            
-     
-    Roo.dd.DropTarget.superclass.constructor.call(  this, 
-        this.el.dom, 
-        this.ddGroup || this.group,
-        {
-            isTarget: true,
-            listeners : listeners || {} 
-           
-        
-        }
-    );
-
-};
-
-Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
-    /**
-     * @cfg {String} overClass
-     * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
-     */
-     /**
-     * @cfg {String} ddGroup
-     * The drag drop group to handle drop events for
-     */
-     
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : "x-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").
-     */
-    dropNotAllowed : "x-dd-drop-nodrop",
-    /**
-     * @cfg {boolean} success
-     * set this after drop listener.. 
-     */
-    success : false,
-    /**
-     * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
-     * if the drop point is valid for over/enter..
-     */
-    valid : false,
-    // private
-    isTarget : true,
-
-    // private
-    isNotifyTarget : true,
-    
-    /**
-     * @hide
-     */
-    notifyEnter : function(dd, e, data)
-    {
-        this.valid = true;
-        this.fireEvent('enter', dd, e, data);
-        if(this.overClass){
-            this.el.addClass(this.overClass);
-        }
-        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
-            this.valid ? this.dropAllowed : this.dropNotAllowed
-        );
-    },
-
-    /**
-     * @hide
-     */
-    notifyOver : function(dd, e, data)
-    {
-        this.valid = true;
-        this.fireEvent('over', dd, e, data);
-        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
-            this.valid ? this.dropAllowed : this.dropNotAllowed
-        );
-    },
-
-    /**
-     * @hide
-     */
-    notifyOut : function(dd, e, data)
-    {
-        this.fireEvent('out', dd, e, data);
-        if(this.overClass){
-            this.el.removeClass(this.overClass);
-        }
-    },
-
-    /**
-     * @hide
-     */
-    notifyDrop : function(dd, e, data)
-    {
-        this.success = false;
-        this.fireEvent('drop', dd, e, data);
-        return this.success;
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-
-/**
- * @class Roo.dd.DragZone
- * @extends Roo.dd.DragSource
- * This class provides a container DD instance that proxies for multiple child node sources.<br />
- * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
- * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
- */
-Roo.dd.DragZone = function(el, config){
-    Roo.dd.DragZone.superclass.constructor.call(this, el, config);
-    if(this.containerScroll){
-        Roo.dd.ScrollManager.register(this.el);
-    }
-};
-
-Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
-    /**
-     * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
-     * for auto scrolling during drag operations.
-     */
-    /**
-     * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
-     * method after a failed drop (defaults to "c3daf9" - light blue)
-     */
-
-    /**
-     * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
-     * 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
-     * @return {Object} The dragData
-     */
-    getDragData : function(e){
-        return Roo.dd.Registry.getHandleFromEvent(e);
-    },
-    
-    /**
-     * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
-     * this.dragData.ddel
-     * @param {Number} x The x position of the click on the dragged object
-     * @param {Number} y The y position of the click on the dragged object
-     * @return {Boolean} true to continue the drag, false to cancel
-     */
-    onInitDrag : function(x, y){
-        this.proxy.update(this.dragData.ddel.cloneNode(true));
-        this.onStartDrag(x, y);
-        return true;
-    },
-    
-    /**
-     * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
-     */
-    afterRepair : function(){
-        if(Roo.enableFx){
-            Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
-        }
-        this.dragging = false;
-    },
-
-    /**
-     * 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])
-     */
-    getRepairXY : function(e){
-        return Roo.Element.fly(this.dragData.ddel).getXY();  
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-/**
- * @class Roo.dd.DropZone
- * @extends Roo.dd.DropTarget
- * This class provides a container DD instance that proxies for multiple child node targets.<br />
- * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
- * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
- */
-Roo.dd.DropZone = function(el, config){
-    Roo.dd.DropZone.superclass.constructor.call(this, el, config);
-};
-
-Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
-    /**
-     * Returns a custom data object associated with the DOM node that is the target of the event.  By default
-     * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
-     * provide your own custom lookup.
-     * @param {Event} e The event
-     * @return {Object} data The custom data
-     */
-    getTargetFromEvent : function(e){
-        return Roo.dd.Registry.getTargetFromEvent(e);
-    },
-
-    /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
-     * that it has registered.  This method has no default implementation and should be overridden to provide
-     * node-specific processing if necessary.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     */
-    onNodeEnter : function(n, dd, e, data){
-        
-    },
-
-    /**
-     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
-     * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
-     * overridden to provide the proper feedback.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
-     */
-    onNodeOver : function(n, dd, e, data){
-        return this.dropAllowed;
-    },
-
-    /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
-     * the drop node without dropping.  This method has no default implementation and should be overridden to provide
-     * node-specific processing if necessary.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     */
-    onNodeOut : function(n, dd, e, data){
-        
-    },
-
-    /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
-     * the drop node.  The default implementation returns false, so it should be overridden to provide the
-     * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {Boolean} True if the drop was valid, else false
-     */
-    onNodeDrop : function(n, dd, e, data){
-        return false;
-    },
-
-    /**
-     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
-     * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
-     * it should be overridden to provide the proper feedback if necessary.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
-     */
-    onContainerOver : function(dd, e, data){
-        return this.dropNotAllowed;
-    },
-
-    /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
-     * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
-     * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
-     * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {Boolean} True if the drop was valid, else false
-     */
-    onContainerDrop : function(dd, e, data){
-        return false;
-    },
-
-    /**
-     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
-     * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
-     * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
-     * you should override this method and provide a custom implementation.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
-     */
-    notifyEnter : function(dd, e, data){
-        return this.dropNotAllowed;
-    },
-
-    /**
-     * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
-     * This method will be called on every mouse movement while the drag source is over the drop zone.
-     * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
-     * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
-     * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
-     * registered node, it will call {@link #onContainerOver}.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
-     */
-    notifyOver : function(dd, e, data){
-        var n = this.getTargetFromEvent(e);
-        if(!n){ // not over valid drop target
-            if(this.lastOverNode){
-                this.onNodeOut(this.lastOverNode, dd, e, data);
-                this.lastOverNode = null;
-            }
-            return this.onContainerOver(dd, e, data);
-        }
-        if(this.lastOverNode != n){
-            if(this.lastOverNode){
-                this.onNodeOut(this.lastOverNode, dd, e, data);
+                if(typeof els[id] == 'object'){ // for people extending the object prototype
+                    els[id]._region = els[id].getRegion();
+                }
             }
-            this.onNodeEnter(n, dd, e, data);
-            this.lastOverNode = n;
-        }
-        return this.onNodeOver(n, dd, e, data);
-    },
-
-    /**
-     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
-     * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
-     * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag zone
-     */
-    notifyOut : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
-        }
-    },
-
-    /**
-     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
-     * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
-     * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
-     * otherwise it will call {@link #onContainerDrop}.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {Boolean} True if the drop was valid, else false
-     */
-    notifyDrop : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
         }
-        var n = this.getTargetFromEvent(e);
-        return n ?
-            this.onNodeDrop(n, dd, e, data) :
-            this.onContainerDrop(dd, e, data);
-    },
-
-    // private
-    triggerCacheRefresh : function(){
-        Roo.dd.DDM.refreshCache(this.groups);
-    }  
-});/*
+    };
+}();/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -22493,329 +21796,303 @@ Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
 
 /**
- * @class Roo.data.SortTypes
+ * @class Roo.dd.Registry
+ * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
+ * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
  * @singleton
- * Defines the default sorting (casting?) comparison functions used when sorting data.
  */
-Roo.data.SortTypes = {
-    /**
-     * Default sort that does nothing
-     * @param {Mixed} s The value being converted
-     * @return {Mixed} The comparison value
-     */
-    none : function(s){
-        return s;
-    },
-    
-    /**
-     * The regular expression used to strip tags
-     * @type {RegExp}
-     * @property
-     */
-    stripTagsRE : /<\/?[^>]+>/gi,
+Roo.dd.Registry = function(){
+    var elements = {}; 
+    var handles = {}; 
+    var autoIdSeed = 0;
+
+    var getId = function(el, autogen){
+        if(typeof el == "string"){
+            return el;
+        }
+        var id = el.id;
+        if(!id && autogen !== false){
+            id = "roodd-" + (++autoIdSeed);
+            el.id = id;
+        }
+        return id;
+    };
     
+    return {
     /**
-     * Strips all HTML tags to sort on text only
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * Register a drag drop element
+     * @param {String|HTMLElement} element The id or DOM node to register
+     * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
+     * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
+     * knows how to interpret, plus there are some specific properties known to the Registry that should be
+     * populated in the data object (if applicable):
+     * <pre>
+Value      Description<br />
+---------  ------------------------------------------<br />
+handles    Array of DOM nodes that trigger dragging<br />
+           for the element being registered<br />
+isHandle   True if the element passed in triggers<br />
+           dragging itself, else false
+</pre>
      */
-    asText : function(s){
-        return String(s).replace(this.stripTagsRE, "");
-    },
-    
+        register : function(el, data){
+            data = data || {};
+            if(typeof el == "string"){
+                el = document.getElementById(el);
+            }
+            data.ddel = el;
+            elements[getId(el)] = data;
+            if(data.isHandle !== false){
+                handles[data.ddel.id] = data;
+            }
+            if(data.handles){
+                var hs = data.handles;
+                for(var i = 0, len = hs.length; i < len; i++){
+                       handles[getId(hs[i])] = data;
+                }
+            }
+        },
+
     /**
-     * Strips all HTML tags to sort on text only - Case insensitive
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * Unregister a drag drop element
+     * @param {String|HTMLElement}  element The id or DOM node to unregister
      */
-    asUCText : function(s){
-        return String(s).toUpperCase().replace(this.stripTagsRE, "");
-    },
-    
+        unregister : function(el){
+            var id = getId(el, false);
+            var data = elements[id];
+            if(data){
+                delete elements[id];
+                if(data.handles){
+                    var hs = data.handles;
+                    for(var i = 0, len = hs.length; i < len; i++){
+                       delete handles[getId(hs[i], false)];
+                    }
+                }
+            }
+        },
+
     /**
-     * Case insensitive string
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * Returns the handle registered for a DOM Node by id
+     * @param {String|HTMLElement} id The DOM node or id to look up
+     * @return {Object} handle The custom handle data
      */
-    asUCString : function(s) {
-       return String(s).toUpperCase();
-    },
-    
+        getHandle : function(id){
+            if(typeof id != "string"){ // must be element?
+                id = id.id;
+            }
+            return handles[id];
+        },
+
     /**
-     * Date sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
+     * Returns the handle that is registered for the DOM node that is the target of the event
+     * @param {Event} e The event
+     * @return {Object} handle The custom handle data
      */
-    asDate : function(s) {
-        if(!s){
-            return 0;
-        }
-        if(s instanceof Date){
-            return s.getTime();
-        }
-       return Date.parse(String(s));
-    },
-    
+        getHandleFromEvent : function(e){
+            var t = Roo.lib.Event.getTarget(e);
+            return t ? handles[t.id] : null;
+        },
+
     /**
-     * Float sorting
-     * @param {Mixed} s The value being converted
-     * @return {Float} The comparison value
+     * Returns a custom data object that is registered for a DOM node by id
+     * @param {String|HTMLElement} id The DOM node or id to look up
+     * @return {Object} data The custom data
      */
-    asFloat : function(s) {
-       var val = parseFloat(String(s).replace(/,/g, ""));
-        if(isNaN(val)) {
-            val = 0;
-        }
-       return val;
-    },
-    
+        getTarget : function(id){
+            if(typeof id != "string"){ // must be element?
+                id = id.id;
+            }
+            return elements[id];
+        },
+
     /**
-     * Integer sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
+     * Returns a custom data object that is registered for the DOM node that is the target of the event
+     * @param {Event} e The event
+     * @return {Object} data The custom data
      */
-    asInt : function(s) {
-        var val = parseInt(String(s).replace(/,/g, ""));
-        if(isNaN(val)) {
-            val = 0;
+        getTargetFromEvent : function(e){
+            var t = Roo.lib.Event.getTarget(e);
+            return t ? elements[t.id] || handles[t.id] : null;
         }
-       return val;
-    }
-};/*
+    };
+}();/*
  * Based on:
  * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
-* @class Roo.data.Record
- * Instances of this class encapsulate both record <em>definition</em> information, and record
- * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
- * to access Records cached in an {@link Roo.data.Store} object.<br>
- * <p>
- * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
- * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
- * objects.<br>
- * <p>
- * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
- * @constructor
- * This constructor should not be used to create Record objects. Instead, use the constructor generated by
- * {@link #create}. The parameters are the same.
- * @param {Array} data An associative Array of data values keyed by the field name.
- * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
- * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
- * not specified an integer id is generated.
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
  */
-Roo.data.Record = function(data, id){
-    this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
-    this.data = data;
-};
 
 /**
- * Generate a constructor for a specific record layout.
- * @param {Array} o An Array of field definition objects which specify field names, and optionally,
- * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
- * Each field definition object may contain the following properties: <ul>
- * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
- * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
- * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
- * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
- * is being used, then this is a string containing the javascript expression to reference the data relative to 
- * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
- * to the data item relative to the record element. If the mapping expression is the same as the field name,
- * this may be omitted.</p></li>
- * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
- * <ul><li>auto (Default, implies no conversion)</li>
- * <li>string</li>
- * <li>int</li>
- * <li>float</li>
- * <li>boolean</li>
- * <li>date</li></ul></p></li>
- * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
- * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
- * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
- * by the Reader into an object that will be stored in the Record. It is passed the
- * following parameters:<ul>
- * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
- * </ul></p></li>
- * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
- * </ul>
- * <br>usage:<br><pre><code>
-var TopicRecord = Roo.data.Record.create(
-    {name: 'title', mapping: 'topic_title'},
-    {name: 'author', mapping: 'username'},
-    {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
-    {name: 'lastPost', mapping: 'post_time', type: 'date'},
-    {name: 'lastPoster', mapping: 'user2'},
-    {name: 'excerpt', mapping: 'post_text'}
-);
-
-var myNewRecord = new TopicRecord({
-    title: 'Do my job please',
-    author: 'noobie',
-    totalPosts: 1,
-    lastPost: new Date(),
-    lastPoster: 'Animal',
-    excerpt: 'No way dude!'
-});
-myStore.add(myNewRecord);
-</code></pre>
- * @method create
- * @static
+ * @class Roo.dd.StatusProxy
+ * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
+ * default drag proxy used by all Roo.dd components.
+ * @constructor
+ * @param {Object} config
  */
-Roo.data.Record.create = function(o){
-    var f = function(){
-        f.superclass.constructor.apply(this, arguments);
-    };
-    Roo.extend(f, Roo.data.Record);
-    var p = f.prototype;
-    p.fields = new Roo.util.MixedCollection(false, function(field){
-        return field.name;
+Roo.dd.StatusProxy = function(config){
+    Roo.apply(this, config);
+    this.id = this.id || Roo.id();
+    this.el = new Roo.Layer({
+        dh: {
+            id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
+                {tag: "div", cls: "x-dd-drop-icon"},
+                {tag: "div", cls: "x-dd-drag-ghost"}
+            ]
+        }, 
+        shadow: !config || config.shadow !== false
     });
-    for(var i = 0, len = o.length; i < len; i++){
-        p.fields.add(new Roo.data.Field(o[i]));
-    }
-    f.getField = function(name){
-        return p.fields.get(name);  
-    };
-    return f;
+    this.ghost = Roo.get(this.el.dom.childNodes[1]);
+    this.dropStatus = this.dropNotAllowed;
 };
 
-Roo.data.Record.AUTO_ID = 1000;
-Roo.data.Record.EDIT = 'edit';
-Roo.data.Record.REJECT = 'reject';
-Roo.data.Record.COMMIT = 'commit';
-
-Roo.data.Record.prototype = {
+Roo.dd.StatusProxy.prototype = {
     /**
-     * Readonly flag - true if this record has been modified.
-     * @type Boolean
+     * @cfg {String} dropAllowed
+     * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
      */
-    dirty : false,
-    editing : false,
-    error: null,
-    modified: null,
-
-    // private
-    join : function(store){
-        this.store = store;
-    },
+    dropAllowed : "x-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 : "x-dd-drop-nodrop",
 
     /**
-     * Set the named field to the specified value.
-     * @param {String} name The name of the field to set.
-     * @param {Object} value The value to set the field to.
+     * 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
      */
-    set : function(name, value){
-        if(this.data[name] == value){
-            return;
-        }
-        this.dirty = true;
-        if(!this.modified){
-            this.modified = {};
-        }
-        if(typeof this.modified[name] == 'undefined'){
-            this.modified[name] = this.data[name];
+    setStatus : function(cssClass){
+        cssClass = cssClass || this.dropNotAllowed;
+        if(this.dropStatus != cssClass){
+            this.el.replaceClass(this.dropStatus, cssClass);
+            this.dropStatus = cssClass;
         }
-        this.data[name] = value;
-        if(!this.editing && this.store){
-            this.store.afterEdit(this);
-        }       
     },
 
     /**
-     * Get the value of the named field.
-     * @param {String} name The name of the field to get the value of.
-     * @return {Object} The value of the field.
+     * 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
      */
-    get : function(name){
-        return this.data[name]; 
+    reset : function(clearGhost){
+        this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
+        this.dropStatus = this.dropNotAllowed;
+        if(clearGhost){
+            this.ghost.update("");
+        }
     },
 
-    // private
-    beginEdit : function(){
-        this.editing = true;
-        this.modified = {}; 
+    /**
+     * Updates the contents of the ghost element
+     * @param {String} html The html that will replace the current innerHTML of the ghost element
+     */
+    update : function(html){
+        if(typeof html == "string"){
+            this.ghost.update(html);
+        }else{
+            this.ghost.update("");
+            html.style.margin = "0";
+            this.ghost.dom.appendChild(html);
+        }
+        // ensure float = none set?? cant remember why though.
+        var el = this.ghost.dom.firstChild;
+               if(el){
+                       Roo.fly(el).setStyle('float', 'none');
+               }
     },
-
-    // private
-    cancelEdit : function(){
-        this.editing = false;
-        delete this.modified;
+    
+    /**
+     * Returns the underlying proxy {@link Roo.Layer}
+     * @return {Roo.Layer} el
+    */
+    getEl : function(){
+        return this.el;
     },
 
-    // private
-    endEdit : function(){
-        this.editing = false;
-        if(this.dirty && this.store){
-            this.store.afterEdit(this);
-        }
+    /**
+     * Returns the ghost element
+     * @return {Roo.Element} el
+     */
+    getGhost : function(){
+        return this.ghost;
     },
 
     /**
-     * Usually called by the {@link Roo.data.Store} which owns the Record.
-     * Rejects all changes made to the Record since either creation, or the last commit operation.
-     * Modified fields are reverted to their original values.
-     * <p>
-     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
-     * of reject operations.
+     * Hides the proxy
+     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
      */
-    reject : function(){
-        var m = this.modified;
-        for(var n in m){
-            if(typeof m[n] != "function"){
-                this.data[n] = m[n];
-            }
-        }
-        this.dirty = false;
-        delete this.modified;
-        this.editing = false;
-        if(this.store){
-            this.store.afterReject(this);
+    hide : function(clear){
+        this.el.hide();
+        if(clear){
+            this.reset(true);
         }
     },
 
     /**
-     * Usually called by the {@link Roo.data.Store} which owns the Record.
-     * Commits all changes made to the Record since either creation, or the last commit operation.
-     * <p>
-     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
-     * of commit operations.
+     * Stops the repair animation if it's currently running
      */
-    commit : function(){
-        this.dirty = false;
-        delete this.modified;
-        this.editing = false;
-        if(this.store){
-            this.store.afterCommit(this);
+    stop : function(){
+        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
+            this.anim.stop();
         }
     },
 
-    // private
-    hasError : function(){
-        return this.error != null;
+    /**
+     * Displays this proxy
+     */
+    show : function(){
+        this.el.show();
     },
 
-    // private
-    clearError : function(){
-        this.error = null;
+    /**
+     * Force the Layer to sync its shadow and shim positions to the element
+     */
+    sync : function(){
+        this.el.sync();
     },
 
     /**
-     * Creates a copy of this record.
-     * @param {String} id (optional) A new record id if you don't want to use this record's id
-     * @return {Record}
+     * 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 in which to execute the callback
      */
-    copy : function(newId) {
-        return new this.constructor(Roo.apply({}, this.data), newId || this.id);
+    repair : function(xy, callback, scope){
+        this.callback = callback;
+        this.scope = scope;
+        if(xy && this.animRepair !== false){
+            this.el.addClass("x-dd-drag-repair");
+            this.el.hideUnders(true);
+            this.anim = this.el.shift({
+                duration: this.repairDuration || .5,
+                easing: 'easeOut',
+                xy: xy,
+                stopFx: true,
+                callback: this.afterRepair,
+                scope: this
+            });
+        }else{
+            this.afterRepair();
+        }
+    },
+
+    // private
+    afterRepair : function(){
+        this.hide(true);
+        if(typeof this.callback == "function"){
+            this.callback.call(this.scope || this);
+        }
+        this.callback = null;
+        this.scope = null;
     }
 };/*
  * Based on:
@@ -22828,744 +22105,841 @@ Roo.data.Record.prototype = {
  * <script type="text/javascript">
  */
 
-
-
 /**
- * @class Roo.data.Store
- * @extends Roo.util.Observable
- * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
- * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
- * <p>
- * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
- * has no knowledge of the format of the data returned by the Proxy.<br>
- * <p>
- * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
- * instances from the data object. These records are cached and made available through accessor functions.
+ * @class Roo.dd.DragSource
+ * @extends Roo.dd.DDProxy
+ * A simple class that provides the basic implementation needed to make any element draggable.
  * @constructor
- * Creates a new Store.
- * @param {Object} config A config object containing the objects needed for the Store to access data,
- * and read the data into Records.
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
  */
-Roo.data.Store = function(config){
-    this.data = new Roo.util.MixedCollection(false);
-    this.data.getKey = function(o){
-        return o.id;
-    };
-    this.baseParams = {};
-    // private
-    this.paramNames = {
-        "start" : "start",
-        "limit" : "limit",
-        "sort" : "sort",
-        "dir" : "dir",
-        "multisort" : "_multisort"
-    };
-
-    if(config && config.data){
-        this.inlineData = config.data;
-        delete config.data;
-    }
-
+Roo.dd.DragSource = function(el, config){
+    this.el = Roo.get(el);
+    this.dragData = {};
+    
     Roo.apply(this, config);
     
-    if(this.reader){ // reader passed
-        this.reader = Roo.factory(this.reader, Roo.data);
-        this.reader.xmodule = this.xmodule || false;
-        if(!this.recordType){
-            this.recordType = this.reader.recordType;
-        }
-        if(this.reader.onMetaChange){
-            this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
-        }
-    }
-
-    if(this.recordType){
-        this.fields = this.recordType.prototype.fields;
+    if(!this.proxy){
+        this.proxy = new Roo.dd.StatusProxy();
     }
-    this.modified = [];
 
-    this.addEvents({
-        /**
-         * @event datachanged
-         * Fires when the data cache has changed, and a widget which is using this Store
-         * as a Record cache should refresh its view.
-         * @param {Store} this
-         */
-        datachanged : true,
-        /**
-         * @event metachange
-         * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
-         * @param {Store} this
-         * @param {Object} meta The JSON metadata
-         */
-        metachange : true,
-        /**
-         * @event add
-         * Fires when Records have been added to the Store
-         * @param {Store} this
-         * @param {Roo.data.Record[]} records The array of Records added
-         * @param {Number} index The index at which the record(s) were added
-         */
-        add : true,
-        /**
-         * @event remove
-         * Fires when a Record has been removed from the Store
-         * @param {Store} this
-         * @param {Roo.data.Record} record The Record that was removed
-         * @param {Number} index The index at which the record was removed
-         */
-        remove : true,
-        /**
-         * @event update
-         * Fires when a Record has been updated
-         * @param {Store} this
-         * @param {Roo.data.Record} record The Record that was updated
-         * @param {String} operation The update operation being performed.  Value may be one of:
-         * <pre><code>
- Roo.data.Record.EDIT
- Roo.data.Record.REJECT
- Roo.data.Record.COMMIT
-         * </code></pre>
-         */
-        update : true,
-        /**
-         * @event clear
-         * Fires when the data cache has been cleared.
-         * @param {Store} this
-         */
-        clear : true,
-        /**
-         * @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 {Store} this
-         * @param {Object} options The loading options that were specified (see {@link #load} for details)
-         */
-        beforeload : true,
-        /**
-         * @event beforeloadadd
-         * Fires after a new set of Records has been loaded.
-         * @param {Store} this
-         * @param {Roo.data.Record[]} records The Records that were loaded
-         * @param {Object} options The loading options that were specified (see {@link #load} for details)
-         */
-        beforeloadadd : true,
-        /**
-         * @event load
-         * Fires after a new set of Records has been loaded, before they are added to the store.
-         * @param {Store} this
-         * @param {Roo.data.Record[]} records The Records that were loaded
-         * @param {Object} options The loading options that were specified (see {@link #load} for details)
-         * @params {Object} return from reader
-         */
-        load : true,
-        /**
-         * @event loadexception
-         * Fires if an exception occurs in the Proxy during loading.
-         * Called with the signature of the Proxy's "loadexception" event.
-         * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
-         * 
-         * @param {Proxy} 
-         * @param {Object} return from JsonData.reader() - success, totalRecords, records
-         * @param {Object} load options 
-         * @param {Object} jsonData from your request (normally this contains the Exception)
-         */
-        loadexception : true
-    });
+    Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
+          {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
     
-    if(this.proxy){
-        this.proxy = Roo.factory(this.proxy, Roo.data);
-        this.proxy.xmodule = this.xmodule || false;
-        this.relayEvents(this.proxy,  ["loadexception"]);
-    }
-    this.sortToggle = {};
-    this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
+    this.dragging = false;
+};
+
+Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
+    /**
+     * @cfg {String} dropAllowed
+     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+     */
+    dropAllowed : "x-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").
+     */
+    dropNotAllowed : "x-dd-drop-nodrop",
+
+    /**
+     * Returns the data object associated with this drag source
+     * @return {Object} data An object containing arbitrary data
+     */
+    getDragData : function(e){
+        return this.dragData;
+    },
+
+    // private
+    onDragEnter : function(e, id){
+        var target = Roo.dd.DragDropMgr.getDDById(id);
+        this.cachedTarget = target;
+        if(this.beforeDragEnter(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                var status = target.notifyEnter(this, e, this.dragData);
+                this.proxy.setStatus(status);
+            }else{
+                this.proxy.setStatus(this.dropAllowed);
+            }
+            
+            if(this.afterDragEnter){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * when the dragged item enters the drop target by providing an implementation.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dragged element
+                 * @method afterDragEnter
+                 */
+                this.afterDragEnter(target, e, id);
+            }
+        }
+    },
+
+    /**
+     * An empty function by default, but provided so that you can perform a custom action
+     * before the dragged item enters the drop target and optionally cancel the onDragEnter.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+     */
+    beforeDragEnter : function(target, e, id){
+        return true;
+    },
 
-    Roo.data.Store.superclass.constructor.call(this);
+    // private
+    alignElWithMouse: function() {
+        Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
+        this.proxy.sync();
+    },
 
-    if(this.inlineData){
-        this.loadData(this.inlineData);
-        delete this.inlineData;
-    }
-};
+    // private
+    onDragOver : function(e, id){
+        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
+        if(this.beforeDragOver(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                var status = target.notifyOver(this, e, this.dragData);
+                this.proxy.setStatus(status);
+            }
 
-Roo.extend(Roo.data.Store, Roo.util.Observable, {
-     /**
-    * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
-    * without a remote query - used by combo/forms at present.
-    */
-    
-    /**
-    * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
-    */
-    /**
-    * @cfg {Array} data Inline data to be loaded when the store is initialized.
-    */
-    /**
-    * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
-    * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
-    */
-    /**
-    * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
-    * on any HTTP request
-    */
-    /**
-    * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
-    */
-    /**
-    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
-    */
-    multiSort: false,
-    /**
-    * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
-    * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
-    */
-    remoteSort : false,
+            if(this.afterDragOver){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * while the dragged item is over the drop target by providing an implementation.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dragged element
+                 * @method afterDragOver
+                 */
+                this.afterDragOver(target, e, id);
+            }
+        }
+    },
 
     /**
-    * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
-     * loaded or when a record is removed. (defaults to false).
-    */
-    pruneModifiedRecords : false,
+     * An empty function by default, but provided so that you can perform a custom action
+     * while the dragged item is over the drop target and optionally cancel the onDragOver.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+     */
+    beforeDragOver : function(target, e, id){
+        return true;
+    },
 
     // private
-    lastOptions : null,
+    onDragOut : function(e, id){
+        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
+        if(this.beforeDragOut(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                target.notifyOut(this, e, this.dragData);
+            }
+            this.proxy.reset();
+            if(this.afterDragOut){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * after the dragged item is dragged out of the target without dropping.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dragged element
+                 * @method afterDragOut
+                 */
+                this.afterDragOut(target, e, id);
+            }
+        }
+        this.cachedTarget = null;
+    },
 
     /**
-     * Add Records to the Store and fires the add event.
-     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
+     * An empty function by default, but provided so that you can perform a custom action before the dragged
+     * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
      */
-    add : function(records){
-        records = [].concat(records);
-        for(var i = 0, len = records.length; i < len; i++){
-            records[i].join(this);
+    beforeDragOut : function(target, e, id){
+        return true;
+    },
+    
+    // private
+    onDragDrop : function(e, id){
+        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
+        if(this.beforeDragDrop(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
+                    this.onValidDrop(target, e, id);
+                }else{
+                    this.onInvalidDrop(target, e, id);
+                }
+            }else{
+                this.onValidDrop(target, e, id);
+            }
+            
+            if(this.afterDragDrop){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * after a valid drag drop has occurred by providing an implementation.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dropped element
+                 * @method afterDragDrop
+                 */
+                this.afterDragDrop(target, e, id);
+            }
         }
-        var index = this.data.length;
-        this.data.addAll(records);
-        this.fireEvent("add", this, records, index);
+        delete this.cachedTarget;
     },
 
     /**
-     * Remove a Record from the Store and fires the remove event.
-     * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
+     * An empty function by default, but provided so that you can perform a custom action before the dragged
+     * item is dropped onto the target and optionally cancel the onDragDrop.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
      */
-    remove : function(record){
-        var index = this.data.indexOf(record);
-        this.data.removeAt(index);
-        if(this.pruneModifiedRecords){
-            this.modified.remove(record);
+    beforeDragDrop : function(target, e, id){
+        return true;
+    },
+
+    // private
+    onValidDrop : function(target, e, id){
+        this.hideProxy();
+        if(this.afterValidDrop){
+            /**
+             * An empty function by default, but provided so that you can perform a custom action
+             * after a valid drop has occurred by providing an implementation.
+             * @param {Object} target The target DD 
+             * @param {Event} e The event object
+             * @param {String} id The id of the dropped element
+             * @method afterInvalidDrop
+             */
+            this.afterValidDrop(target, e, id);
         }
-        this.fireEvent("remove", this, record, index);
+    },
+
+    // private
+    getRepairXY : function(e, data){
+        return this.el.getXY();  
+    },
+
+    // private
+    onInvalidDrop : function(target, e, id){
+        this.beforeInvalidDrop(target, e, id);
+        if(this.cachedTarget){
+            if(this.cachedTarget.isNotifyTarget){
+                this.cachedTarget.notifyOut(this, e, this.dragData);
+            }
+            this.cacheTarget = null;
+        }
+        this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
+
+        if(this.afterInvalidDrop){
+            /**
+             * An empty function by default, but provided so that you can perform a custom action
+             * after an invalid drop has occurred by providing an implementation.
+             * @param {Event} e The event object
+             * @param {String} id The id of the dropped element
+             * @method afterInvalidDrop
+             */
+            this.afterInvalidDrop(e, id);
+        }
+    },
+
+    // private
+    afterRepair : function(){
+        if(Roo.enableFx){
+            this.el.highlight(this.hlColor || "c3daf9");
+        }
+        this.dragging = false;
     },
 
     /**
-     * Remove all Records from the Store and fires the clear event.
+     * An empty function by default, but provided so that you can perform a custom action after an invalid
+     * drop has occurred.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
      */
-    removeAll : function(){
-        this.data.clear();
-        if(this.pruneModifiedRecords){
-            this.modified = [];
+    beforeInvalidDrop : function(target, e, id){
+        return true;
+    },
+
+    // private
+    handleMouseDown : function(e){
+        if(this.dragging) {
+            return;
         }
-        this.fireEvent("clear", this);
+        var data = this.getDragData(e);
+        if(data && this.onBeforeDrag(data, e) !== false){
+            this.dragData = data;
+            this.proxy.stop();
+            Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
+        } 
     },
 
     /**
-     * Inserts Records to the Store at the given index and fires the add event.
-     * @param {Number} index The start index at which to insert the passed Records.
-     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
+     * An empty function by default, but provided so that you can perform a custom action before the initial
+     * drag event begins and optionally cancel it.
+     * @param {Object} data An object containing arbitrary data to be shared with drop targets
+     * @param {Event} e The event object
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
      */
-    insert : function(index, records){
-        records = [].concat(records);
-        for(var i = 0, len = records.length; i < len; i++){
-            this.data.insert(index, records[i]);
-            records[i].join(this);
-        }
-        this.fireEvent("add", this, records, index);
+    onBeforeDrag : function(data, e){
+        return true;
     },
 
     /**
-     * Get the index within the cache of the passed Record.
-     * @param {Roo.data.Record} record The Roo.data.Record object to to find.
-     * @return {Number} The index of the passed Record. Returns -1 if not found.
+     * An empty function by default, but provided so that you can perform a custom action once the initial
+     * drag event has begun.  The drag cannot be canceled from this function.
+     * @param {Number} x The x position of the click on the dragged object
+     * @param {Number} y The y position of the click on the dragged object
      */
-    indexOf : function(record){
-        return this.data.indexOf(record);
+    onStartDrag : Roo.emptyFn,
+
+    // private - YUI override
+    startDrag : function(x, y){
+        this.proxy.reset();
+        this.dragging = true;
+        this.proxy.update("");
+        this.onInitDrag(x, y);
+        this.proxy.show();
     },
 
-    /**
-     * 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);
+    // private
+    onInitDrag : function(x, y){
+        var clone = this.el.dom.cloneNode(true);
+        clone.id = Roo.id(); // prevent duplicate ids
+        this.proxy.update(clone);
+        this.onStartDrag(x, y);
+        return true;
     },
 
     /**
-     * Get the Record with the specified id.
-     * @param {String} id The id of the Record to find.
-     * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
+     * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
+     * @return {Roo.dd.StatusProxy} proxy The StatusProxy
      */
-    getById : function(id){
-        return this.data.key(id);
+    getProxy : function(){
+        return this.proxy;  
     },
 
     /**
-     * Get the Record at the specified index.
-     * @param {Number} index The index of the Record to find.
-     * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
+     * Hides the drag source's {@link Roo.dd.StatusProxy}
      */
-    getAt : function(index){
-        return this.data.itemAt(index);
+    hideProxy : function(){
+        this.proxy.hide();  
+        this.proxy.reset(true);
+        this.dragging = false;
     },
 
-    /**
-     * 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 {Roo.data.Record[]} An array of Records
-     */
-    getRange : function(start, end){
-        return this.data.getRange(start, end);
+    // private
+    triggerCacheRefresh : function(){
+        Roo.dd.DDM.refreshCache(this.groups);
+    },
+
+    // private - override to prevent hiding
+    b4EndDrag: function(e) {
+    },
+
+    // private - override to prevent moving
+    endDrag : function(e){
+        this.onEndDrag(this.dragData, e);
     },
 
     // private
-    storeOptions : function(o){
-        o = Roo.apply({}, o);
-        delete o.callback;
-        delete o.scope;
-        this.lastOptions = o;
+    onEndDrag : function(data, e){
     },
+    
+    // private - pin to cursor
+    autoOffset : function(x, y) {
+        this.setDelta(-12, -20);
+    }    
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+
+/**
+ * @class Roo.dd.DropTarget
+ * @extends Roo.dd.DDTarget
+ * A simple class that provides the basic implementation needed to make any element a drop target that can have
+ * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
+ * @constructor
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
+ */
+Roo.dd.DropTarget = function(el, config){
+    this.el = Roo.get(el);
+    
+    var listeners = false; ;
+    if (config && config.listeners) {
+        listeners= config.listeners;
+        delete config.listeners;
+    }
+    Roo.apply(this, config);
+    
+    if(this.containerScroll){
+        Roo.dd.ScrollManager.register(this.el);
+    }
+    this.addEvents( {
+         /**
+         * @scope Roo.dd.DropTarget
+         */
+         
+         /**
+         * @event enter
+         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
+         * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
+         * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
+         * 
+         * IMPORTANT : it should set this.overClass and this.dropAllowed
+         * 
+         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
+         * @param {Event} e The event
+         * @param {Object} data An object containing arbitrary data supplied by the drag source
+         */
+        "enter" : true,
+        
+         /**
+         * @event over
+         * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
+         * This method will be called on every mouse movement while the drag source is over the drop target.
+         * This default implementation simply returns the dropAllowed config value.
+         * 
+         * IMPORTANT : it should set this.dropAllowed
+         * 
+         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
+         * @param {Event} e The event
+         * @param {Object} data An object containing arbitrary data supplied by the drag source
+         
+         */
+        "over" : true,
+        /**
+         * @event out
+         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
+         * out of the target without dropping.  This default implementation simply removes the CSS class specified by
+         * overClass (if any) from the drop element.
+         * 
+         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
+         * @param {Event} e The event
+         * @param {Object} data An object containing arbitrary data supplied by the drag source
+         */
+         "out" : true,
+         
+        /**
+         * @event drop
+         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
+         * been dropped on it.  This method has no default implementation and returns false, so you must provide an
+         * implementation that does something to process the drop event and returns true so that the drag source's
+         * repair action does not run.
+         * 
+         * IMPORTANT : it should set this.success
+         * 
+         * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
+         * @param {Event} e The event
+         * @param {Object} data An object containing arbitrary data supplied by the drag source
+        */
+         "drop" : true
+    });
+            
+     
+    Roo.dd.DropTarget.superclass.constructor.call(  this, 
+        this.el.dom, 
+        this.ddGroup || this.group,
+        {
+            isTarget: true,
+            listeners : listeners || {} 
+           
+        
+        }
+    );
 
+};
+
+Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
     /**
-     * Loads the Record cache from the configured Proxy using the configured Reader.
-     * <p>
-     * If using remote paging, then the first load call must specify the <em>start</em>
-     * and <em>limit</em> properties in the options.params property to establish the initial
-     * position within the dataset, and the number of Records to cache on each read from the Proxy.
-     * <p>
-     * <strong>It is important to note that for remote data sources, loading is asynchronous,
-     * and this call will return before the new data has been loaded. Perform any post-processing
-     * in a callback function, or in a "load" event handler.</strong>
-     * <p>
-     * @param {Object} options An object containing properties which control loading options:<ul>
-     * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
-     * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
-     * passed the following arguments:<ul>
-     * <li>r : Roo.data.Record[]</li>
-     * <li>options: Options object from the load call</li>
-     * <li>success: Boolean success indicator</li></ul></li>
-     * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
-     * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
-     * </ul>
+     * @cfg {String} overClass
+     * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
      */
-    load : function(options){
-        options = options || {};
-        if(this.fireEvent("beforeload", this, options) !== false){
-            this.storeOptions(options);
-            var p = Roo.apply(options.params || {}, this.baseParams);
-            // if meta was not loaded from remote source.. try requesting it.
-            if (!this.reader.metaFromRemote) {
-                p._requestMeta = 1;
-            }
-            if(this.sortInfo && this.remoteSort){
-                var pn = this.paramNames;
-                p[pn["sort"]] = this.sortInfo.field;
-                p[pn["dir"]] = this.sortInfo.direction;
-            }
-            if (this.multiSort) {
-                var pn = this.paramNames;
-                p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
-            }
-            
-            this.proxy.load(p, this.reader, this.loadRecords, this, options);
+     /**
+     * @cfg {String} ddGroup
+     * The drag drop group to handle drop events for
+     */
+     
+    /**
+     * @cfg {String} dropAllowed
+     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+     */
+    dropAllowed : "x-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").
+     */
+    dropNotAllowed : "x-dd-drop-nodrop",
+    /**
+     * @cfg {boolean} success
+     * set this after drop listener.. 
+     */
+    success : false,
+    /**
+     * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
+     * if the drop point is valid for over/enter..
+     */
+    valid : false,
+    // private
+    isTarget : true,
+
+    // private
+    isNotifyTarget : true,
+    
+    /**
+     * @hide
+     */
+    notifyEnter : function(dd, e, data)
+    {
+        this.valid = true;
+        this.fireEvent('enter', dd, e, data);
+        if(this.overClass){
+            this.el.addClass(this.overClass);
         }
+        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
+            this.valid ? this.dropAllowed : this.dropNotAllowed
+        );
     },
 
     /**
-     * Reloads the Record cache from the configured Proxy using the configured Reader and
-     * the options from the last load operation performed.
-     * @param {Object} options (optional) An object containing properties which may override the options
-     * used in the last load operation. See {@link #load} for details (defaults to null, in which case
-     * the most recently used options are reused).
+     * @hide
      */
-    reload : function(options){
-        this.load(Roo.applyIf(options||{}, this.lastOptions));
+    notifyOver : function(dd, e, data)
+    {
+        this.valid = true;
+        this.fireEvent('over', dd, e, data);
+        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
+            this.valid ? this.dropAllowed : this.dropNotAllowed
+        );
     },
 
-    // private
-    // Called as a callback by the Reader during a load operation.
-    loadRecords : function(o, options, success){
-        if(!o || success === false){
-            if(success !== false){
-                this.fireEvent("load", this, [], options, o);
-            }
-            if(options.callback){
-                options.callback.call(options.scope || this, [], options, false);
-            }
-            return;
-        }
-        // if data returned failure - throw an exception.
-        if (o.success === false) {
-            // show a message if no listener is registered.
-            if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
-                    Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
-            }
-            // loadmask wil be hooked into this..
-            this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
-            return;
-        }
-        var r = o.records, t = o.totalRecords || r.length;
-        
-        this.fireEvent("beforeloadadd", this, r, options, o);
-        
-        if(!options || options.add !== true){
-            if(this.pruneModifiedRecords){
-                this.modified = [];
-            }
-            for(var i = 0, len = r.length; i < len; i++){
-                r[i].join(this);
-            }
-            if(this.snapshot){
-                this.data = this.snapshot;
-                delete this.snapshot;
-            }
-            this.data.clear();
-            this.data.addAll(r);
-            this.totalLength = t;
-            this.applySort();
-            this.fireEvent("datachanged", this);
-        }else{
-            this.totalLength = Math.max(t, this.data.length+r.length);
-            this.add(r);
+    /**
+     * @hide
+     */
+    notifyOut : function(dd, e, data)
+    {
+        this.fireEvent('out', dd, e, data);
+        if(this.overClass){
+            this.el.removeClass(this.overClass);
         }
-        
-        if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
-                
-            var e = new Roo.data.Record({});
+    },
 
-            e.set(this.parent.displayField, this.parent.emptyTitle);
-            e.set(this.parent.valueField, '');
+    /**
+     * @hide
+     */
+    notifyDrop : function(dd, e, data)
+    {
+        this.success = false;
+        this.fireEvent('drop', dd, e, data);
+        return this.success;
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
-            this.insert(0, e);
-        }
-            
-        this.fireEvent("load", this, r, options, o);
-        if(options.callback){
-            options.callback.call(options.scope || this, r, options, true);
-        }
-    },
 
+/**
+ * @class Roo.dd.DragZone
+ * @extends Roo.dd.DragSource
+ * This class provides a container DD instance that proxies for multiple child node sources.<br />
+ * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
+ * @constructor
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
+ */
+Roo.dd.DragZone = function(el, config){
+    Roo.dd.DragZone.superclass.constructor.call(this, el, config);
+    if(this.containerScroll){
+        Roo.dd.ScrollManager.register(this.el);
+    }
+};
 
+Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
     /**
-     * Loads data from a passed data block. A Reader which understands the format of the data
-     * must have been configured in the constructor.
-     * @param {Object} data The data block from which to read the Records.  The format of the data expected
-     * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
-     * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
+     * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
+     * for auto scrolling during drag operations.
      */
-    loadData : function(o, append){
-        var r = this.reader.readRecords(o);
-        this.loadRecords(r, {add: append}, true);
-    },
-    
-     /**
-     * using 'cn' the nested child reader read the child array into it's child stores.
-     * @param {Object} rec The record with a 'children array
+    /**
+     * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
+     * method after a failed drop (defaults to "c3daf9" - light blue)
      */
-    loadDataFromChildren : function(rec)
-    {
-        this.loadData(this.reader.toLoadData(rec));
-    },
-    
 
     /**
-     * Gets the number of cached records.
-     * <p>
-     * <em>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 getTotalCount() function returns
-     * the data set size</em>
+     * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
+     * 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
+     * @return {Object} The dragData
      */
-    getCount : function(){
-        return this.data.length || 0;
+    getDragData : function(e){
+        return Roo.dd.Registry.getHandleFromEvent(e);
     },
-
+    
     /**
-     * Gets the total number of records in the dataset as returned by the server.
-     * <p>
-     * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
-     * the dataset size</em>
+     * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
+     * this.dragData.ddel
+     * @param {Number} x The x position of the click on the dragged object
+     * @param {Number} y The y position of the click on the dragged object
+     * @return {Boolean} true to continue the drag, false to cancel
      */
-    getTotalCount : function(){
-        return this.totalLength || 0;
+    onInitDrag : function(x, y){
+        this.proxy.update(this.dragData.ddel.cloneNode(true));
+        this.onStartDrag(x, y);
+        return true;
     },
-
+    
     /**
-     * Returns the sort state of the Store as an object with two properties:
-     * <pre><code>
- field {String} The name of the field by which the Records are sorted
- direction {String} The sort order, "ASC" or "DESC"
-     * </code></pre>
+     * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
      */
-    getSortState : function(){
-        return this.sortInfo;
-    },
-
-    // private
-    applySort : function(){
-        if(this.sortInfo && !this.remoteSort){
-            var s = this.sortInfo, f = s.field;
-            var st = this.fields.get(f).sortType;
-            var fn = function(r1, r2){
-                var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
-                return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
-            };
-            this.data.sort(s.direction, fn);
-            if(this.snapshot && this.snapshot != this.data){
-                this.snapshot.sort(s.direction, fn);
-            }
+    afterRepair : function(){
+        if(Roo.enableFx){
+            Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
         }
+        this.dragging = false;
     },
 
     /**
-     * Sets the default sort column and order to be used by the next load operation.
-     * @param {String} fieldName The name of the field to sort by.
-     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
+     * 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])
      */
-    setDefaultSort : function(field, dir){
-        this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
-    },
+    getRepairXY : function(e){
+        return Roo.Element.fly(this.dragData.ddel).getXY();  
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.dd.DropZone
+ * @extends Roo.dd.DropTarget
+ * This class provides a container DD instance that proxies for multiple child node targets.<br />
+ * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
+ * @constructor
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
+ */
+Roo.dd.DropZone = function(el, config){
+    Roo.dd.DropZone.superclass.constructor.call(this, el, config);
+};
 
+Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
     /**
-     * Sort the Records.
-     * If remote sorting is used, the sort is performed on the server, and the cache is
-     * reloaded. If local sorting is used, the cache is sorted internally.
-     * @param {String} fieldName The name of the field to sort by.
-     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
+     * Returns a custom data object associated with the DOM node that is the target of the event.  By default
+     * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
+     * provide your own custom lookup.
+     * @param {Event} e The event
+     * @return {Object} data The custom data
      */
-    sort : function(fieldName, dir){
-        var f = this.fields.get(fieldName);
-        if(!dir){
-            this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
-            
-            if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
-                dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
-            }else{
-                dir = f.sortDir;
-            }
-        }
-        this.sortToggle[f.name] = dir;
-        this.sortInfo = {field: f.name, direction: dir};
-        if(!this.remoteSort){
-            this.applySort();
-            this.fireEvent("datachanged", this);
-        }else{
-            this.load(this.lastOptions);
-        }
+    getTargetFromEvent : function(e){
+        return Roo.dd.Registry.getTargetFromEvent(e);
     },
 
     /**
-     * Calls the specified function for each of the Records in the cache.
-     * @param {Function} fn The function to call. The Record is passed as the first parameter.
-     * Returning <em>false</em> aborts and exits the iteration.
-     * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
+     * that it has registered.  This method has no default implementation and should be overridden to provide
+     * node-specific processing if necessary.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
      */
-    each : function(fn, scope){
-        this.data.each(fn, scope);
+    onNodeEnter : function(n, dd, e, data){
+        
     },
 
     /**
-     * Gets all records modified since the last commit.  Modified records are persisted across load operations
-     * (e.g., during paging).
-     * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
+     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
+     * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
+     * overridden to provide the proper feedback.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
      */
-    getModifiedRecords : function(){
-        return this.modified;
-    },
-
-    // private
-    createFilterFn : function(property, value, anyMatch){
-        if(!value.exec){ // not a regex
-            value = String(value);
-            if(value.length == 0){
-                return false;
-            }
-            value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
-        }
-        return function(r){
-            return value.test(r.data[property]);
-        };
+    onNodeOver : function(n, dd, e, data){
+        return this.dropAllowed;
     },
 
     /**
-     * Sums the value of <i>property</i> for each record between start and end and returns the result.
-     * @param {String} property A field on your records
-     * @param {Number} start The record index to start at (defaults to 0)
-     * @param {Number} end The last record index to include (defaults to length - 1)
-     * @return {Number} The sum
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
+     * the drop node without dropping.  This method has no default implementation and should be overridden to provide
+     * node-specific processing if necessary.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
      */
-    sum : function(property, start, end){
-        var rs = this.data.items, v = 0;
-        start = start || 0;
-        end = (end || end === 0) ? end : rs.length-1;
-
-        for(var i = start; i <= end; i++){
-            v += (rs[i].data[property] || 0);
-        }
-        return v;
+    onNodeOut : function(n, dd, e, data){
+        
     },
 
     /**
-     * Filter the records by a specified property.
-     * @param {String} field A field on your records
-     * @param {String/RegExp} value Either a string that the field
-     * should start with or a RegExp to test against the field
-     * @param {Boolean} anyMatch True to match any part not just the beginning
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
+     * the drop node.  The default implementation returns false, so it should be overridden to provide the
+     * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {Boolean} True if the drop was valid, else false
      */
-    filter : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.filterBy(fn) : this.clearFilter();
+    onNodeDrop : function(n, dd, e, data){
+        return false;
     },
 
     /**
-     * Filter by a function. The specified function will be called with each
-     * record in this data source. If the function returns true the record is included,
-     * otherwise it is filtered.
-     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
-     * @param {Object} scope (optional) The scope of the function (defaults to this)
+     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
+     * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
+     * it should be overridden to provide the proper feedback if necessary.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
      */
-    filterBy : function(fn, scope){
-        this.snapshot = this.snapshot || this.data;
-        this.data = this.queryBy(fn, scope||this);
-        this.fireEvent("datachanged", this);
+    onContainerOver : function(dd, e, data){
+        return this.dropNotAllowed;
     },
 
     /**
-     * Query the records by a specified property.
-     * @param {String} field A field on your records
-     * @param {String/RegExp} value Either a string that the field
-     * should start with or a RegExp to test against the field
-     * @param {Boolean} anyMatch True to match any part not just the beginning
-     * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
+     * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
+     * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
+     * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {Boolean} True if the drop was valid, else false
      */
-    query : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.queryBy(fn) : this.data.clone();
-    },
-
-    /**
-     * Query by a function. The specified function will be called with each
-     * record in this data source. If the function returns true the record is included
-     * in the results.
-     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
-     * @param {Object} scope (optional) The scope of the function (defaults to this)
-      @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
-     **/
-    queryBy : function(fn, scope){
-        var data = this.snapshot || this.data;
-        return data.filterBy(fn, scope||this);
+    onContainerDrop : function(dd, e, data){
+        return false;
     },
 
     /**
-     * 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 d = (bypassFilter === true && this.snapshot) ?
-                this.snapshot.items : this.data.items;
-        var v, sv, r = [], l = {};
-        for(var i = 0, len = d.length; i < len; i++){
-            v = d[i].data[dataIndex];
-            sv = String(v);
-            if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
-                l[sv] = true;
-                r[r.length] = v;
-            }
-        }
-        return r;
+     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
+     * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
+     * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
+     * you should override this method and provide a custom implementation.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
+     */
+    notifyEnter : function(dd, e, data){
+        return this.dropNotAllowed;
     },
 
     /**
-     * Revert to a view of the Record cache with no filtering applied.
-     * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
+     * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
+     * This method will be called on every mouse movement while the drag source is over the drop zone.
+     * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
+     * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
+     * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
+     * registered node, it will call {@link #onContainerOver}.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
      */
-    clearFilter : function(suppressEvent){
-        if(this.snapshot && this.snapshot != this.data){
-            this.data = this.snapshot;
-            delete this.snapshot;
-            if(suppressEvent !== true){
-                this.fireEvent("datachanged", this);
+    notifyOver : function(dd, e, data){
+        var n = this.getTargetFromEvent(e);
+        if(!n){ // not over valid drop target
+            if(this.lastOverNode){
+                this.onNodeOut(this.lastOverNode, dd, e, data);
+                this.lastOverNode = null;
             }
+            return this.onContainerOver(dd, e, data);
         }
-    },
-
-    // private
-    afterEdit : function(record){
-        if(this.modified.indexOf(record) == -1){
-            this.modified.push(record);
+        if(this.lastOverNode != n){
+            if(this.lastOverNode){
+                this.onNodeOut(this.lastOverNode, dd, e, data);
+            }
+            this.onNodeEnter(n, dd, e, data);
+            this.lastOverNode = n;
         }
-        this.fireEvent("update", this, record, Roo.data.Record.EDIT);
-    },
-    
-    // private
-    afterReject : function(record){
-        this.modified.remove(record);
-        this.fireEvent("update", this, record, Roo.data.Record.REJECT);
-    },
-
-    // private
-    afterCommit : function(record){
-        this.modified.remove(record);
-        this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
+        return this.onNodeOver(n, dd, e, data);
     },
 
     /**
-     * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
-     * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
+     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
+     * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
+     * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag zone
      */
-    commitChanges : function(){
-        var m = this.modified.slice(0);
-        this.modified = [];
-        for(var i = 0, len = m.length; i < len; i++){
-            m[i].commit();
+    notifyOut : function(dd, e, data){
+        if(this.lastOverNode){
+            this.onNodeOut(this.lastOverNode, dd, e, data);
+            this.lastOverNode = null;
         }
     },
 
     /**
-     * Cancel outstanding changes on all changed records.
+     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
+     * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
+     * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
+     * otherwise it will call {@link #onContainerDrop}.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {Boolean} True if the drop was valid, else false
      */
-    rejectChanges : function(){
-        var m = this.modified.slice(0);
-        this.modified = [];
-        for(var i = 0, len = m.length; i < len; i++){
-            m[i].reject();
+    notifyDrop : function(dd, e, data){
+        if(this.lastOverNode){
+            this.onNodeOut(this.lastOverNode, dd, e, data);
+            this.lastOverNode = null;
         }
+        var n = this.getTargetFromEvent(e);
+        return n ?
+            this.onNodeDrop(n, dd, e, data) :
+            this.onContainerDrop(dd, e, data);
     },
 
-    onMetaChange : function(meta, rtype, o){
-        this.recordType = rtype;
-        this.fields = rtype.prototype.fields;
-        delete this.snapshot;
-        this.sortInfo = meta.sortInfo || this.sortInfo;
-        this.modified = [];
-        this.fireEvent('metachange', this, this.reader.meta);
-    },
-    
-    moveIndex : function(data, type)
-    {
-        var index = this.indexOf(data);
-        
-        var newIndex = index + type;
-        
-        this.remove(data);
-        
-        this.insert(newIndex, data);
-        
-    }
+    // private
+    triggerCacheRefresh : function(){
+        Roo.dd.DDM.refreshCache(this.groups);
+    }  
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -23577,169 +22951,96 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
  * <script type="text/javascript">
  */
 
-/**
- * @class Roo.data.SimpleStore
- * @extends Roo.data.Store
- * Small helper class to make creating Stores from Array data easier.
- * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
- * @cfg {Array} fields An array of field definition objects, or field name strings.
- * @cfg {Object} an existing reader (eg. copied from another store)
- * @cfg {Array} data The multi-dimensional array of data
- * @constructor
- * @param {Object} config
- */
-Roo.data.SimpleStore = function(config)
-{
-    Roo.data.SimpleStore.superclass.constructor.call(this, {
-        isLocal : true,
-        reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
-                id: config.id
-            },
-            Roo.data.Record.create(config.fields)
-        ),
-        proxy : new Roo.data.MemoryProxy(config.data)
-    });
-    this.load();
-};
-Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
 
 /**
-/**
- * @extends Roo.data.Store
- * @class Roo.data.JsonStore
- * Small helper class to make creating Stores for JSON data easier. <br/>
-<pre><code>
-var store = new Roo.data.JsonStore({
-    url: 'get-images.php',
-    root: 'images',
-    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
-});
-</code></pre>
- * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
- * JsonReader and HttpProxy (unless inline data is provided).</b>
- * @cfg {Array} fields An array of field definition objects, or field name strings.
- * @constructor
- * @param {Object} config
- */
-Roo.data.JsonStore = function(c){
-    Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
-        proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
-        reader: new Roo.data.JsonReader(c, c.fields)
-    }));
-};
-Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
+ * @class Roo.data.SortTypes
+ * @singleton
+ * Defines the default sorting (casting?) comparison functions used when sorting data.
  */
-
-Roo.data.Field = function(config){
-    if(typeof config == "string"){
-        config = {name: config};
-    }
-    Roo.apply(this, config);
+Roo.data.SortTypes = {
+    /**
+     * Default sort that does nothing
+     * @param {Mixed} s The value being converted
+     * @return {Mixed} The comparison value
+     */
+    none : function(s){
+        return s;
+    },
     
-    if(!this.type){
-        this.type = "auto";
-    }
+    /**
+     * The regular expression used to strip tags
+     * @type {RegExp}
+     * @property
+     */
+    stripTagsRE : /<\/?[^>]+>/gi,
     
-    var st = Roo.data.SortTypes;
-    // named sortTypes are supported, here we look them up
-    if(typeof this.sortType == "string"){
-        this.sortType = st[this.sortType];
-    }
+    /**
+     * 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, "");
+    },
     
-    // set default sortType for strings and dates
-    if(!this.sortType){
-        switch(this.type){
-            case "string":
-                this.sortType = st.asUCString;
-                break;
-            case "date":
-                this.sortType = st.asDate;
-                break;
-            default:
-                this.sortType = st.none;
-        }
-    }
-
-    // define once
-    var stripRe = /[\$,%]/g;
-
-    // prebuilt conversion function for this field, instead of
-    // switching every time we're reading a value
-    if(!this.convert){
-        var cv, dateFormat = this.dateFormat;
-        switch(this.type){
-            case "":
-            case "auto":
-            case undefined:
-                cv = function(v){ return v; };
-                break;
-            case "string":
-                cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
-                break;
-            case "int":
-                cv = function(v){
-                    return v !== undefined && v !== null && v !== '' ?
-                           parseInt(String(v).replace(stripRe, ""), 10) : '';
-                    };
-                break;
-            case "float":
-                cv = function(v){
-                    return v !== undefined && v !== null && v !== '' ?
-                           parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
-                    };
-                break;
-            case "bool":
-            case "boolean":
-                cv = function(v){ return v === true || v === "true" || v == 1; };
-                break;
-            case "date":
-                cv = function(v){
-                    if(!v){
-                        return '';
-                    }
-                    if(v instanceof Date){
-                        return v;
-                    }
-                    if(dateFormat){
-                        if(dateFormat == "timestamp"){
-                            return new Date(v*1000);
-                        }
-                        return Date.parseDate(v, dateFormat);
-                    }
-                    var parsed = Date.parse(v);
-                    return parsed ? new Date(parsed) : null;
-                };
-             break;
-            
+    /**
+     * Strips all HTML tags to sort on text only - Case insensitive
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
+     */
+    asUCText : function(s){
+        return String(s).toUpperCase().replace(this.stripTagsRE, "");
+    },
+    
+    /**
+     * Case insensitive string
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
+     */
+    asUCString : function(s) {
+       return String(s).toUpperCase();
+    },
+    
+    /**
+     * Date sorting
+     * @param {Mixed} s The value being converted
+     * @return {Number} The comparison value
+     */
+    asDate : function(s) {
+        if(!s){
+            return 0;
         }
-        this.convert = cv;
+        if(s instanceof Date){
+            return s.getTime();
+        }
+       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, ""));
+        if(isNaN(val)) {
+            val = 0;
+        }
+       return val;
+    },
+    
+    /**
+     * Integer sorting
+     * @param {Mixed} s The value being converted
+     * @return {Number} The comparison value
+     */
+    asInt : function(s) {
+        var val = parseInt(String(s).replace(/,/g, ""));
+        if(isNaN(val)) {
+            val = 0;
+        }
+       return val;
     }
-};
-
-Roo.data.Field.prototype = {
-    dateFormat: null,
-    defaultValue: "",
-    mapping: null,
-    sortType : null,
-    sortDir : "ASC"
 };/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -23750,49 +23051,229 @@ Roo.data.Field.prototype = {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-// Base class for reading structured data from a data source.  This class is intended to be
-// extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
 
 /**
- * @class Roo.data.DataReader
- * Base class for reading structured data from a data source.  This class is intended to be
- * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
+* @class Roo.data.Record
+ * Instances of this class encapsulate both record <em>definition</em> information, and record
+ * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
+ * to access Records cached in an {@link Roo.data.Store} object.<br>
+ * <p>
+ * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
+ * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
+ * objects.<br>
+ * <p>
+ * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
+ * @constructor
+ * This constructor should not be used to create Record objects. Instead, use the constructor generated by
+ * {@link #create}. The parameters are the same.
+ * @param {Array} data An associative Array of data values keyed by the field name.
+ * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
+ * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
+ * not specified an integer id is generated.
+ */
+Roo.data.Record = function(data, id){
+    this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
+    this.data = data;
+};
+
+/**
+ * Generate a constructor for a specific record layout.
+ * @param {Array} o An Array of field definition objects which specify field names, and optionally,
+ * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
+ * Each field definition object may contain the following properties: <ul>
+ * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
+ * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
+ * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
+ * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
+ * is being used, then this is a string containing the javascript expression to reference the data relative to 
+ * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
+ * to the data item relative to the record element. If the mapping expression is the same as the field name,
+ * this may be omitted.</p></li>
+ * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
+ * <ul><li>auto (Default, implies no conversion)</li>
+ * <li>string</li>
+ * <li>int</li>
+ * <li>float</li>
+ * <li>boolean</li>
+ * <li>date</li></ul></p></li>
+ * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
+ * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
+ * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
+ * by the Reader into an object that will be stored in the Record. It is passed the
+ * following parameters:<ul>
+ * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
+ * </ul></p></li>
+ * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
+ * </ul>
+ * <br>usage:<br><pre><code>
+var TopicRecord = Roo.data.Record.create(
+    {name: 'title', mapping: 'topic_title'},
+    {name: 'author', mapping: 'username'},
+    {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
+    {name: 'lastPost', mapping: 'post_time', type: 'date'},
+    {name: 'lastPoster', mapping: 'user2'},
+    {name: 'excerpt', mapping: 'post_text'}
+);
+
+var myNewRecord = new TopicRecord({
+    title: 'Do my job please',
+    author: 'noobie',
+    totalPosts: 1,
+    lastPost: new Date(),
+    lastPoster: 'Animal',
+    excerpt: 'No way dude!'
+});
+myStore.add(myNewRecord);
+</code></pre>
+ * @method create
+ * @static
  */
+Roo.data.Record.create = function(o){
+    var f = function(){
+        f.superclass.constructor.apply(this, arguments);
+    };
+    Roo.extend(f, Roo.data.Record);
+    var p = f.prototype;
+    p.fields = new Roo.util.MixedCollection(false, function(field){
+        return field.name;
+    });
+    for(var i = 0, len = o.length; i < len; i++){
+        p.fields.add(new Roo.data.Field(o[i]));
+    }
+    f.getField = function(name){
+        return p.fields.get(name);  
+    };
+    return f;
+};
+
+Roo.data.Record.AUTO_ID = 1000;
+Roo.data.Record.EDIT = 'edit';
+Roo.data.Record.REJECT = 'reject';
+Roo.data.Record.COMMIT = 'commit';
+
+Roo.data.Record.prototype = {
+    /**
+     * Readonly flag - true if this record has been modified.
+     * @type Boolean
+     */
+    dirty : false,
+    editing : false,
+    error: null,
+    modified: null,
+
+    // private
+    join : function(store){
+        this.store = store;
+    },
+
+    /**
+     * Set the named field to the specified value.
+     * @param {String} name The name of the field to set.
+     * @param {Object} value The value to set the field to.
+     */
+    set : function(name, value){
+        if(this.data[name] == value){
+            return;
+        }
+        this.dirty = true;
+        if(!this.modified){
+            this.modified = {};
+        }
+        if(typeof this.modified[name] == 'undefined'){
+            this.modified[name] = this.data[name];
+        }
+        this.data[name] = value;
+        if(!this.editing && this.store){
+            this.store.afterEdit(this);
+        }       
+    },
+
+    /**
+     * Get the value of the named field.
+     * @param {String} name The name of the field to get the value of.
+     * @return {Object} The value of the field.
+     */
+    get : function(name){
+        return this.data[name]; 
+    },
+
+    // private
+    beginEdit : function(){
+        this.editing = true;
+        this.modified = {}; 
+    },
+
+    // private
+    cancelEdit : function(){
+        this.editing = false;
+        delete this.modified;
+    },
+
+    // private
+    endEdit : function(){
+        this.editing = false;
+        if(this.dirty && this.store){
+            this.store.afterEdit(this);
+        }
+    },
+
+    /**
+     * Usually called by the {@link Roo.data.Store} which owns the Record.
+     * Rejects all changes made to the Record since either creation, or the last commit operation.
+     * Modified fields are reverted to their original values.
+     * <p>
+     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
+     * of reject operations.
+     */
+    reject : function(){
+        var m = this.modified;
+        for(var n in m){
+            if(typeof m[n] != "function"){
+                this.data[n] = m[n];
+            }
+        }
+        this.dirty = false;
+        delete this.modified;
+        this.editing = false;
+        if(this.store){
+            this.store.afterReject(this);
+        }
+    },
+
+    /**
+     * Usually called by the {@link Roo.data.Store} which owns the Record.
+     * Commits all changes made to the Record since either creation, or the last commit operation.
+     * <p>
+     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
+     * of commit operations.
+     */
+    commit : function(){
+        this.dirty = false;
+        delete this.modified;
+        this.editing = false;
+        if(this.store){
+            this.store.afterCommit(this);
+        }
+    },
+
+    // private
+    hasError : function(){
+        return this.error != null;
+    },
 
-Roo.data.DataReader = function(meta, recordType){
-    
-    this.meta = meta;
-    
-    this.recordType = recordType instanceof Array ? 
-        Roo.data.Record.create(recordType) : recordType;
-};
+    // private
+    clearError : function(){
+        this.error = null;
+    },
 
-Roo.data.DataReader.prototype = {
-    
-    
-    readerType : 'Data',
-     /**
-     * Create an empty record
-     * @param {Object} data (optional) - overlay some values
-     * @return {Roo.data.Record} record created.
+    /**
+     * Creates a copy of this record.
+     * @param {String} id (optional) A new record id if you don't want to use this record's id
+     * @return {Record}
      */
-    newRow :  function(d) {
-        var da =  {};
-        this.recordType.prototype.fields.each(function(c) {
-            switch( c.type) {
-                case 'int' : da[c.name] = 0; break;
-                case 'date' : da[c.name] = new Date(); break;
-                case 'float' : da[c.name] = 0.0; break;
-                case 'boolean' : da[c.name] = false; break;
-                default : da[c.name] = ""; break;
-            }
-            
-        });
-        return new this.recordType(Roo.apply(da, d));
+    copy : function(newId) {
+        return new this.constructor(Roo.apply({}, this.data), newId || this.id);
     }
-    
-    
 };/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -23804,819 +23285,743 @@ Roo.data.DataReader.prototype = {
  * <script type="text/javascript">
  */
 
+
+
 /**
- * @class Roo.data.DataProxy
- * @extends Roo.data.Observable
- * This class is an abstract base class for implementations which provide retrieval of
- * unformatted data objects.<br>
+ * @class Roo.data.Store
+ * @extends Roo.util.Observable
+ * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
+ * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
  * <p>
- * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
- * (of the appropriate type which knows how to parse the data object) to provide a block of
- * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
+ * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
+ * has no knowledge of the format of the data returned by the Proxy.<br>
  * <p>
- * Custom implementations must implement the load method as described in
- * {@link Roo.data.HttpProxy#load}.
+ * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
+ * instances from the data object. These records are cached and made available through accessor functions.
+ * @constructor
+ * Creates a new Store.
+ * @param {Object} config A config object containing the objects needed for the Store to access data,
+ * and read the data into Records.
  */
-Roo.data.DataProxy = function(){
+Roo.data.Store = function(config){
+    this.data = new Roo.util.MixedCollection(false);
+    this.data.getKey = function(o){
+        return o.id;
+    };
+    this.baseParams = {};
+    // private
+    this.paramNames = {
+        "start" : "start",
+        "limit" : "limit",
+        "sort" : "sort",
+        "dir" : "dir",
+        "multisort" : "_multisort"
+    };
+
+    if(config && config.data){
+        this.inlineData = config.data;
+        delete config.data;
+    }
+
+    Roo.apply(this, config);
+    
+    if(this.reader){ // reader passed
+        this.reader = Roo.factory(this.reader, Roo.data);
+        this.reader.xmodule = this.xmodule || false;
+        if(!this.recordType){
+            this.recordType = this.reader.recordType;
+        }
+        if(this.reader.onMetaChange){
+            this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
+        }
+    }
+
+    if(this.recordType){
+        this.fields = this.recordType.prototype.fields;
+    }
+    this.modified = [];
+
     this.addEvents({
+        /**
+         * @event datachanged
+         * Fires when the data cache has changed, and a widget which is using this Store
+         * as a Record cache should refresh its view.
+         * @param {Store} this
+         */
+        datachanged : true,
+        /**
+         * @event metachange
+         * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
+         * @param {Store} this
+         * @param {Object} meta The JSON metadata
+         */
+        metachange : true,
+        /**
+         * @event add
+         * Fires when Records have been added to the Store
+         * @param {Store} this
+         * @param {Roo.data.Record[]} records The array of Records added
+         * @param {Number} index The index at which the record(s) were added
+         */
+        add : true,
+        /**
+         * @event remove
+         * Fires when a Record has been removed from the Store
+         * @param {Store} this
+         * @param {Roo.data.Record} record The Record that was removed
+         * @param {Number} index The index at which the record was removed
+         */
+        remove : true,
+        /**
+         * @event update
+         * Fires when a Record has been updated
+         * @param {Store} this
+         * @param {Roo.data.Record} record The Record that was updated
+         * @param {String} operation The update operation being performed.  Value may be one of:
+         * <pre><code>
+ Roo.data.Record.EDIT
+ Roo.data.Record.REJECT
+ Roo.data.Record.COMMIT
+         * </code></pre>
+         */
+        update : true,
+        /**
+         * @event clear
+         * Fires when the data cache has been cleared.
+         * @param {Store} this
+         */
+        clear : true,
         /**
          * @event beforeload
-         * Fires before a network request is made to retrieve a data object.
-         * @param {Object} This DataProxy object.
-         * @param {Object} params The params parameter to the load function.
+         * Fires before a request is made for a new data object.  If the beforeload handler returns false
+         * the load action will be canceled.
+         * @param {Store} this
+         * @param {Object} options The loading options that were specified (see {@link #load} for details)
          */
         beforeload : true,
+        /**
+         * @event beforeloadadd
+         * Fires after a new set of Records has been loaded.
+         * @param {Store} this
+         * @param {Roo.data.Record[]} records The Records that were loaded
+         * @param {Object} options The loading options that were specified (see {@link #load} for details)
+         */
+        beforeloadadd : true,
         /**
          * @event load
-         * Fires before the load method's callback is called.
-         * @param {Object} This DataProxy object.
-         * @param {Object} o The data object.
-         * @param {Object} arg The callback argument object passed to the load function.
+         * Fires after a new set of Records has been loaded, before they are added to the store.
+         * @param {Store} this
+         * @param {Roo.data.Record[]} records The Records that were loaded
+         * @param {Object} options The loading options that were specified (see {@link #load} for details)
+         * @params {Object} return from reader
          */
         load : true,
         /**
          * @event loadexception
-         * Fires if an Exception occurs during data retrieval.
-         * @param {Object} This DataProxy object.
-         * @param {Object} o The data object.
-         * @param {Object} arg The callback argument object passed to the load function.
-         * @param {Object} e The Exception.
+         * Fires if an exception occurs in the Proxy during loading.
+         * Called with the signature of the Proxy's "loadexception" event.
+         * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
+         * 
+         * @param {Proxy} 
+         * @param {Object} return from JsonData.reader() - success, totalRecords, records
+         * @param {Object} load options 
+         * @param {Object} jsonData from your request (normally this contains the Exception)
          */
         loadexception : true
     });
-    Roo.data.DataProxy.superclass.constructor.call(this);
-};
+    
+    if(this.proxy){
+        this.proxy = Roo.factory(this.proxy, Roo.data);
+        this.proxy.xmodule = this.xmodule || false;
+        this.relayEvents(this.proxy,  ["loadexception"]);
+    }
+    this.sortToggle = {};
+    this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
 
-Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
+    Roo.data.Store.superclass.constructor.call(this);
 
-    /**
-     * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
-     */
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-/**
- * @class Roo.data.MemoryProxy
- * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
- * to the Reader when its load method is called.
- * @constructor
- * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
- */
-Roo.data.MemoryProxy = function(data){
-    if (data.data) {
-        data = data.data;
+    if(this.inlineData){
+        this.loadData(this.inlineData);
+        delete this.inlineData;
     }
-    Roo.data.MemoryProxy.superclass.constructor.call(this);
-    this.data = data;
 };
 
-Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
-    
+Roo.extend(Roo.data.Store, Roo.util.Observable, {
+     /**
+    * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
+    * without a remote query - used by combo/forms at present.
+    */
+    
+    /**
+    * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
+    */
+    /**
+    * @cfg {Array} data Inline data to be loaded when the store is initialized.
+    */
+    /**
+    * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
+    * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
+    */
+    /**
+    * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
+    * on any HTTP request
+    */
+    /**
+    * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
+    */
+    /**
+    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
+    */
+    multiSort: false,
+    /**
+    * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
+    * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
+    */
+    remoteSort : false,
+
     /**
-     * Load data from the requested source (in this case an in-memory
-     * data object passed to the constructor), read the data object into
-     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
-     * process that block using the passed callback.
-     * @param {Object} params This parameter is not used by the MemoryProxy class.
-     * @param {Roo.data.DataReader} reader The Reader object which converts the data
-     * object into a block of Roo.data.Records.
-     * @param {Function} callback The function into which to pass the block of Roo.data.records.
-     * The function must be passed <ul>
-     * <li>The Record block object</li>
-     * <li>The "arg" argument from the load function</li>
-     * <li>A boolean success indicator</li>
-     * </ul>
-     * @param {Object} scope The scope in which to call the callback
-     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+    * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
+     * loaded or when a record is removed. (defaults to false).
+    */
+    pruneModifiedRecords : false,
+
+    // private
+    lastOptions : null,
+
+    /**
+     * Add Records to the Store and fires the add event.
+     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
      */
-    load : function(params, reader, callback, scope, arg){
-        params = params || {};
-        var result;
-        try {
-            result = reader.readRecords(params.data ? params.data :this.data);
-        }catch(e){
-            this.fireEvent("loadexception", this, arg, null, e);
-            callback.call(scope, null, arg, false);
-            return;
+    add : function(records){
+        records = [].concat(records);
+        for(var i = 0, len = records.length; i < len; i++){
+            records[i].join(this);
         }
-        callback.call(scope, result, arg, true);
+        var index = this.data.length;
+        this.data.addAll(records);
+        this.fireEvent("add", this, records, index);
     },
-    
-    // private
-    update : function(params, records){
-        
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-/**
- * @class Roo.data.HttpProxy
- * @extends Roo.data.DataProxy
- * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
- * configured to reference a certain URL.<br><br>
- * <p>
- * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
- * from which the running page was served.<br><br>
- * <p>
- * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
- * <p>
- * Be aware that to enable the browser to parse an XML document, the server must set
- * the Content-Type header in the HTTP response to "text/xml".
- * @constructor
- * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
- * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
- * will be used to make the request.
- */
-Roo.data.HttpProxy = function(conn){
-    Roo.data.HttpProxy.superclass.constructor.call(this);
-    // is conn a conn config or a real conn?
-    this.conn = conn;
-    this.useAjax = !conn || !conn.events;
-  
-};
 
-Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
-    // thse are take from connection...
-    
     /**
-     * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
+     * Remove a Record from the Store and fires the remove event.
+     * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
      */
+    remove : function(record){
+        var index = this.data.indexOf(record);
+        this.data.removeAt(index);
+        if(this.pruneModifiedRecords){
+            this.modified.remove(record);
+        }
+        this.fireEvent("remove", this, record, index);
+    },
+
     /**
-     * @cfg {Object} extraParams (Optional) An object containing properties which are used as
-     * extra parameters to each request made by this object. (defaults to undefined)
+     * Remove all Records from the Store and fires the clear event.
      */
+    removeAll : function(){
+        this.data.clear();
+        if(this.pruneModifiedRecords){
+            this.modified = [];
+        }
+        this.fireEvent("clear", this);
+    },
+
     /**
-     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
-     *  to each request made by this object. (defaults to undefined)
+     * Inserts Records to the Store at the given index and fires the add event.
+     * @param {Number} index The start index at which to insert the passed Records.
+     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
      */
+    insert : function(index, records){
+        records = [].concat(records);
+        for(var i = 0, len = records.length; i < len; i++){
+            this.data.insert(index, records[i]);
+            records[i].join(this);
+        }
+        this.fireEvent("add", this, records, index);
+    },
+
     /**
-     * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
+     * Get the index within the cache of the passed Record.
+     * @param {Roo.data.Record} record The Roo.data.Record object to to find.
+     * @return {Number} The index of the passed Record. Returns -1 if not found.
      */
+    indexOf : function(record){
+        return this.data.indexOf(record);
+    },
+
     /**
-     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
+     * 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.
      */
-     /**
-     * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
-     * @type Boolean
+    indexOfId : function(id){
+        return this.data.indexOfKey(id);
+    },
+
+    /**
+     * Get the Record with the specified id.
+     * @param {String} id The id of the Record to find.
+     * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
      */
-  
+    getById : function(id){
+        return this.data.key(id);
+    },
 
     /**
-     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
-     * @type Boolean
+     * Get the Record at the specified index.
+     * @param {Number} index The index of the Record to find.
+     * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
      */
+    getAt : function(index){
+        return this.data.itemAt(index);
+    },
+
     /**
-     * Return the {@link Roo.data.Connection} object being used by this Proxy.
-     * @return {Connection} The Connection object. This object may be used to subscribe to events on
-     * a finer-grained basis than the DataProxy events.
+     * 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 {Roo.data.Record[]} An array of Records
      */
-    getConnection : function(){
-        return this.useAjax ? Roo.Ajax : this.conn;
+    getRange : function(start, end){
+        return this.data.getRange(start, end);
+    },
+
+    // private
+    storeOptions : function(o){
+        o = Roo.apply({}, o);
+        delete o.callback;
+        delete o.scope;
+        this.lastOptions = o;
     },
 
     /**
-     * Load data from the configured {@link Roo.data.Connection}, read the data object into
-     * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
-     * process that block using the passed callback.
-     * @param {Object} params An object containing properties which are to be used as HTTP parameters
-     * for the request to the remote server.
-     * @param {Roo.data.DataReader} reader The Reader object which converts the data
-     * object into a block of Roo.data.Records.
-     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
-     * The function must be passed <ul>
-     * <li>The Record block object</li>
-     * <li>The "arg" argument from the load function</li>
-     * <li>A boolean success indicator</li>
+     * Loads the Record cache from the configured Proxy using the configured Reader.
+     * <p>
+     * If using remote paging, then the first load call must specify the <em>start</em>
+     * and <em>limit</em> properties in the options.params property to establish the initial
+     * position within the dataset, and the number of Records to cache on each read from the Proxy.
+     * <p>
+     * <strong>It is important to note that for remote data sources, loading is asynchronous,
+     * and this call will return before the new data has been loaded. Perform any post-processing
+     * in a callback function, or in a "load" event handler.</strong>
+     * <p>
+     * @param {Object} options An object containing properties which control loading options:<ul>
+     * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
+     * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
+     * passed the following arguments:<ul>
+     * <li>r : Roo.data.Record[]</li>
+     * <li>options: Options object from the load call</li>
+     * <li>success: Boolean success indicator</li></ul></li>
+     * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
+     * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
      * </ul>
-     * @param {Object} scope The scope in which to call the callback
-     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
      */
-    load : function(params, reader, callback, scope, arg){
-        if(this.fireEvent("beforeload", this, params) !== false){
-            var  o = {
-                params : params || {},
-                request: {
-                    callback : callback,
-                    scope : scope,
-                    arg : arg
-                },
-                reader: reader,
-                callback : this.loadResponse,
-                scope: this
-            };
-            if(this.useAjax){
-                Roo.applyIf(o, this.conn);
-                if(this.activeRequest){
-                    Roo.Ajax.abort(this.activeRequest);
-                }
-                this.activeRequest = Roo.Ajax.request(o);
-            }else{
-                this.conn.request(o);
+    load : function(options){
+        options = options || {};
+        if(this.fireEvent("beforeload", this, options) !== false){
+            this.storeOptions(options);
+            var p = Roo.apply(options.params || {}, this.baseParams);
+            // if meta was not loaded from remote source.. try requesting it.
+            if (!this.reader.metaFromRemote) {
+                p._requestMeta = 1;
+            }
+            if(this.sortInfo && this.remoteSort){
+                var pn = this.paramNames;
+                p[pn["sort"]] = this.sortInfo.field;
+                p[pn["dir"]] = this.sortInfo.direction;
+            }
+            if (this.multiSort) {
+                var pn = this.paramNames;
+                p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
             }
-        }else{
-            callback.call(scope||this, null, arg, false);
+            
+            this.proxy.load(p, this.reader, this.loadRecords, this, options);
         }
     },
 
+    /**
+     * Reloads the Record cache from the configured Proxy using the configured Reader and
+     * the options from the last load operation performed.
+     * @param {Object} options (optional) An object containing properties which may override the options
+     * used in the last load operation. See {@link #load} for details (defaults to null, in which case
+     * the most recently used options are reused).
+     */
+    reload : function(options){
+        this.load(Roo.applyIf(options||{}, this.lastOptions));
+    },
+
     // private
-    loadResponse : function(o, success, response){
-        delete this.activeRequest;
-        if(!success){
-            this.fireEvent("loadexception", this, o, response);
-            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+    // Called as a callback by the Reader during a load operation.
+    loadRecords : function(o, options, success){
+        if(!o || success === false){
+            if(success !== false){
+                this.fireEvent("load", this, [], options, o);
+            }
+            if(options.callback){
+                options.callback.call(options.scope || this, [], options, false);
+            }
             return;
         }
-        var result;
-        try {
-            result = o.reader.read(response);
-        }catch(e){
-            this.fireEvent("loadexception", this, o, response, e);
-            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+        // if data returned failure - throw an exception.
+        if (o.success === false) {
+            // show a message if no listener is registered.
+            if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
+                    Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
+            }
+            // loadmask wil be hooked into this..
+            this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
             return;
         }
+        var r = o.records, t = o.totalRecords || r.length;
         
-        this.fireEvent("load", this, o, o.request.arg);
-        o.request.callback.call(o.request.scope, result, o.request.arg, true);
-    },
+        this.fireEvent("beforeloadadd", this, r, options, o);
+        
+        if(!options || options.add !== true){
+            if(this.pruneModifiedRecords){
+                this.modified = [];
+            }
+            for(var i = 0, len = r.length; i < len; i++){
+                r[i].join(this);
+            }
+            if(this.snapshot){
+                this.data = this.snapshot;
+                delete this.snapshot;
+            }
+            this.data.clear();
+            this.data.addAll(r);
+            this.totalLength = t;
+            this.applySort();
+            this.fireEvent("datachanged", this);
+        }else{
+            this.totalLength = Math.max(t, this.data.length+r.length);
+            this.add(r);
+        }
+        
+        if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
+                
+            var e = new Roo.data.Record({});
 
-    // private
-    update : function(dataSet){
+            e.set(this.parent.displayField, this.parent.emptyTitle);
+            e.set(this.parent.valueField, '');
 
+            this.insert(0, e);
+        }
+            
+        this.fireEvent("load", this, r, options, o);
+        if(options.callback){
+            options.callback.call(options.scope || this, r, options, true);
+        }
     },
 
-    // private
-    updateResponse : function(dataSet){
-
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.data.ScriptTagProxy
- * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
- * other than the originating domain of the running page.<br><br>
- * <p>
- * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
- * of the running page, you must use this class, rather than DataProxy.</em><br><br>
- * <p>
- * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
- * source code that is used as the source inside a &lt;script> tag.<br><br>
- * <p>
- * In order for the browser to process the returned data, the server must wrap the data object
- * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
- * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
- * depending on whether the callback name was passed:
- * <p>
- * <pre><code>
-boolean scriptTag = false;
-String cb = request.getParameter("callback");
-if (cb != null) {
-    scriptTag = true;
-    response.setContentType("text/javascript");
-} else {
-    response.setContentType("application/x-json");
-}
-Writer out = response.getWriter();
-if (scriptTag) {
-    out.write(cb + "(");
-}
-out.print(dataBlock.toJsonString());
-if (scriptTag) {
-    out.write(");");
-}
-</pre></code>
- *
- * @constructor
- * @param {Object} config A configuration object.
- */
-Roo.data.ScriptTagProxy = function(config){
-    Roo.data.ScriptTagProxy.superclass.constructor.call(this);
-    Roo.apply(this, config);
-    this.head = document.getElementsByTagName("head")[0];
-};
-
-Roo.data.ScriptTagProxy.TRANS_ID = 1000;
 
-Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
     /**
-     * @cfg {String} url The URL from which to request the data object.
+     * Loads data from a passed data block. A Reader which understands the format of the data
+     * must have been configured in the constructor.
+     * @param {Object} data The data block from which to read the Records.  The format of the data expected
+     * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
+     * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
      */
-    /**
-     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
+    loadData : function(o, append){
+        var r = this.reader.readRecords(o);
+        this.loadRecords(r, {add: append}, true);
+    },
+    
+     /**
+     * using 'cn' the nested child reader read the child array into it's child stores.
+     * @param {Object} rec The record with a 'children array
      */
-    timeout : 30000,
+    loadDataFromChildren : function(rec)
+    {
+        this.loadData(this.reader.toLoadData(rec));
+    },
+    
+
     /**
-     * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
-     * the server the name of the callback function set up by the load call to process the returned data object.
-     * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
-     * javascript output which calls this named function passing the data object as its only parameter.
+     * Gets the number of cached records.
+     * <p>
+     * <em>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 getTotalCount() function returns
+     * the data set size</em>
      */
-    callbackParam : "callback",
+    getCount : function(){
+        return this.data.length || 0;
+    },
+
     /**
-     *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
-     * name to the request.
+     * Gets the total number of records in the dataset as returned by the server.
+     * <p>
+     * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
+     * the dataset size</em>
      */
-    nocache : true,
+    getTotalCount : function(){
+        return this.totalLength || 0;
+    },
 
     /**
-     * Load data from the configured URL, read the data object into
-     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
-     * process that block using the passed callback.
-     * @param {Object} params An object containing properties which are to be used as HTTP parameters
-     * for the request to the remote server.
-     * @param {Roo.data.DataReader} reader The Reader object which converts the data
-     * object into a block of Roo.data.Records.
-     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
-     * The function must be passed <ul>
-     * <li>The Record block object</li>
-     * <li>The "arg" argument from the load function</li>
-     * <li>A boolean success indicator</li>
-     * </ul>
-     * @param {Object} scope The scope in which to call the callback
-     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+     * Returns the sort state of the Store as an object with two properties:
+     * <pre><code>
+ field {String} The name of the field by which the Records are sorted
+ direction {String} The sort order, "ASC" or "DESC"
+     * </code></pre>
      */
-    load : function(params, reader, callback, scope, arg){
-        if(this.fireEvent("beforeload", this, params) !== false){
-
-            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
-
-            var url = this.url;
-            url += (url.indexOf("?") != -1 ? "&" : "?") + p;
-            if(this.nocache){
-                url += "&_dc=" + (new Date().getTime());
-            }
-            var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
-            var trans = {
-                id : transId,
-                cb : "stcCallback"+transId,
-                scriptId : "stcScript"+transId,
-                params : params,
-                arg : arg,
-                url : url,
-                callback : callback,
-                scope : scope,
-                reader : reader
-            };
-            var conn = this;
-
-            window[trans.cb] = function(o){
-                conn.handleResponse(o, trans);
-            };
-
-            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
+    getSortState : function(){
+        return this.sortInfo;
+    },
 
-            if(this.autoAbort !== false){
-                this.abort();
+    // private
+    applySort : function(){
+        if(this.sortInfo && !this.remoteSort){
+            var s = this.sortInfo, f = s.field;
+            var st = this.fields.get(f).sortType;
+            var fn = function(r1, r2){
+                var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
+                return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
+            };
+            this.data.sort(s.direction, fn);
+            if(this.snapshot && this.snapshot != this.data){
+                this.snapshot.sort(s.direction, fn);
             }
+        }
+    },
 
-            trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
-
-            var script = document.createElement("script");
-            script.setAttribute("src", url);
-            script.setAttribute("type", "text/javascript");
-            script.setAttribute("id", trans.scriptId);
-            this.head.appendChild(script);
+    /**
+     * Sets the default sort column and order to be used by the next load operation.
+     * @param {String} fieldName The name of the field to sort by.
+     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
+     */
+    setDefaultSort : function(field, dir){
+        this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
+    },
 
-            this.trans = trans;
+    /**
+     * Sort the Records.
+     * If remote sorting is used, the sort is performed on the server, and the cache is
+     * reloaded. If local sorting is used, the cache is sorted internally.
+     * @param {String} fieldName The name of the field to sort by.
+     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
+     */
+    sort : function(fieldName, dir){
+        var f = this.fields.get(fieldName);
+        if(!dir){
+            this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
+            
+            if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
+                dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
+            }else{
+                dir = f.sortDir;
+            }
+        }
+        this.sortToggle[f.name] = dir;
+        this.sortInfo = {field: f.name, direction: dir};
+        if(!this.remoteSort){
+            this.applySort();
+            this.fireEvent("datachanged", this);
         }else{
-            callback.call(scope||this, null, arg, false);
+            this.load(this.lastOptions);
         }
     },
 
-    // private
-    isLoading : function(){
-        return this.trans ? true : false;
+    /**
+     * Calls the specified function for each of the Records in the cache.
+     * @param {Function} fn The function to call. The Record is passed as the first parameter.
+     * Returning <em>false</em> aborts and exits the iteration.
+     * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
+     */
+    each : function(fn, scope){
+        this.data.each(fn, scope);
     },
 
     /**
-     * Abort the current server request.
+     * Gets all records modified since the last commit.  Modified records are persisted across load operations
+     * (e.g., during paging).
+     * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
      */
-    abort : function(){
-        if(this.isLoading()){
-            this.destroyTrans(this.trans);
-        }
+    getModifiedRecords : function(){
+        return this.modified;
     },
 
     // private
-    destroyTrans : function(trans, isLoaded){
-        this.head.removeChild(document.getElementById(trans.scriptId));
-        clearTimeout(trans.timeoutId);
-        if(isLoaded){
-            window[trans.cb] = undefined;
-            try{
-                delete window[trans.cb];
-            }catch(e){}
-        }else{
-            // if hasn't been loaded, wait for load to remove it to prevent script error
-            window[trans.cb] = function(){
-                window[trans.cb] = undefined;
-                try{
-                    delete window[trans.cb];
-                }catch(e){}
-            };
+    createFilterFn : function(property, value, anyMatch){
+        if(!value.exec){ // not a regex
+            value = String(value);
+            if(value.length == 0){
+                return false;
+            }
+            value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
         }
+        return function(r){
+            return value.test(r.data[property]);
+        };
     },
 
-    // private
-    handleResponse : function(o, trans){
-        this.trans = false;
-        this.destroyTrans(trans, true);
-        var result;
-        try {
-            result = trans.reader.readRecords(o);
-        }catch(e){
-            this.fireEvent("loadexception", this, o, trans.arg, e);
-            trans.callback.call(trans.scope||window, null, trans.arg, false);
-            return;
+    /**
+     * Sums the value of <i>property</i> for each record between start and end and returns the result.
+     * @param {String} property A field on your records
+     * @param {Number} start The record index to start at (defaults to 0)
+     * @param {Number} end The last record index to include (defaults to length - 1)
+     * @return {Number} The sum
+     */
+    sum : function(property, start, end){
+        var rs = this.data.items, v = 0;
+        start = start || 0;
+        end = (end || end === 0) ? end : rs.length-1;
+
+        for(var i = start; i <= end; i++){
+            v += (rs[i].data[property] || 0);
         }
-        this.fireEvent("load", this, o, trans.arg);
-        trans.callback.call(trans.scope||window, result, trans.arg, true);
+        return v;
     },
 
-    // private
-    handleFailure : function(trans){
-        this.trans = false;
-        this.destroyTrans(trans, false);
-        this.fireEvent("loadexception", this, null, trans.arg);
-        trans.callback.call(trans.scope||window, null, trans.arg, false);
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.data.JsonReader
- * @extends Roo.data.DataReader
- * Data reader class to create an Array of Roo.data.Record objects from a JSON response
- * based on mappings in a provided Roo.data.Record constructor.
- * 
- * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
- * in the reply previously. 
- * 
- * <p>
- * Example code:
- * <pre><code>
-var RecordDef = Roo.data.Record.create([
-    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
-    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
-]);
-var myReader = new Roo.data.JsonReader({
-    totalProperty: "results",    // The property which contains the total dataset size (optional)
-    root: "rows",                // The property which contains an Array of row objects
-    id: "id"                     // The property within each row object that provides an ID for the record (optional)
-}, RecordDef);
-</code></pre>
- * <p>
- * This would consume a JSON file like this:
- * <pre><code>
-{ 'results': 2, 'rows': [
-    { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
-    { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
-}
-</code></pre>
- * @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.
- * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
- * @cfg {String} root name of the property which contains the Array of row objects.
- * @cfg {String} id Name of the property within a row object that contains a record identifier value.
- * @cfg {Array} fields Array of field definition objects
- * @constructor
- * Create a new JsonReader
- * @param {Object} meta Metadata configuration options
- * @param {Object} recordType Either an Array of field definition objects,
- * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
- */
-Roo.data.JsonReader = function(meta, recordType){
-    
-    meta = meta || {};
-    // set some defaults:
-    Roo.applyIf(meta, {
-        totalProperty: 'total',
-        successProperty : 'success',
-        root : 'data',
-        id : 'id'
-    });
-    
-    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
-};
-Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
-    
-    readerType : 'Json',
-    
     /**
-     * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
-     * Used by Store query builder to append _requestMeta to params.
-     * 
+     * Filter the records by a specified property.
+     * @param {String} field A field on your records
+     * @param {String/RegExp} value Either a string that the field
+     * should start with or a RegExp to test against the field
+     * @param {Boolean} anyMatch True to match any part not just the beginning
      */
-    metaFromRemote : false,
+    filter : function(property, value, anyMatch){
+        var fn = this.createFilterFn(property, value, anyMatch);
+        return fn ? this.filterBy(fn) : this.clearFilter();
+    },
+
     /**
-     * This method is only used by a DataProxy which has retrieved data from a remote server.
-     * @param {Object} response The XHR object which contains the JSON data in its responseText.
-     * @return {Object} data A data block which is used by an Roo.data.Store object as
-     * a cache of Roo.data.Records.
+     * Filter by a function. The specified function will be called with each
+     * record in this data source. If the function returns true the record is included,
+     * otherwise it is filtered.
+     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
+     * @param {Object} scope (optional) The scope of the function (defaults to this)
      */
-    read : function(response){
-        var json = response.responseText;
-       
-        var o = /* eval:var:o */ eval("("+json+")");
-        if(!o) {
-            throw {message: "JsonReader.read: Json object not found"};
-        }
-        
-        if(o.metaData){
-            
-            delete this.ef;
-            this.metaFromRemote = true;
-            this.meta = o.metaData;
-            this.recordType = Roo.data.Record.create(o.metaData.fields);
-            this.onMetaChange(this.meta, this.recordType, o);
-        }
-        return this.readRecords(o);
+    filterBy : function(fn, scope){
+        this.snapshot = this.snapshot || this.data;
+        this.data = this.queryBy(fn, scope||this);
+        this.fireEvent("datachanged", this);
     },
 
-    // private function a store will implement
-    onMetaChange : function(meta, recordType, o){
-
+    /**
+     * Query the records by a specified property.
+     * @param {String} field A field on your records
+     * @param {String/RegExp} value Either a string that the field
+     * should start with or a RegExp to test against the field
+     * @param {Boolean} anyMatch True to match any part not just the beginning
+     * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
+     */
+    query : function(property, value, anyMatch){
+        var fn = this.createFilterFn(property, value, anyMatch);
+        return fn ? this.queryBy(fn) : this.data.clone();
     },
 
     /**
-        * @ignore
-        */
-    simpleAccess: function(obj, subsc) {
-       return obj[subsc];
+     * Query by a function. The specified function will be called with each
+     * record in this data source. If the function returns true the record is included
+     * in the results.
+     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
+     * @param {Object} scope (optional) The scope of the function (defaults to this)
+      @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
+     **/
+    queryBy : function(fn, scope){
+        var data = this.snapshot || this.data;
+        return data.filterBy(fn, scope||this);
     },
 
-       /**
-        * @ignore
-        */
-    getJsonAccessor: function(){
-        var re = /[\[\.]/;
-        return function(expr) {
-            try {
-                return(re.test(expr))
-                    ? new Function("obj", "return obj." + expr)
-                    : function(obj){
-                        return obj[expr];
-                    };
-            } catch(e){}
-            return Roo.emptyFn;
-        };
-    }(),
-
     /**
-     * Create a data block containing Roo.data.Records from an XML document.
-     * @param {Object} o An object which contains an Array of row objects in the property specified
-     * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
-     * which contains the total size of the dataset.
-     * @return {Object} data A data block which is used by an Roo.data.Store object as
-     * a cache of Roo.data.Records.
-     */
-    readRecords : function(o){
-        /**
-         * After any data loads, the raw JSON data is available for further custom processing.
-         * @type Object
-         */
-        this.o = o;
-        var s = this.meta, Record = this.recordType,
-            f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
-
-//      Generate extraction functions for the totalProperty, the root, the id, and for each field
-        if (!this.ef) {
-            if(s.totalProperty) {
-                   this.getTotal = this.getJsonAccessor(s.totalProperty);
-               }
-               if(s.successProperty) {
-                   this.getSuccess = this.getJsonAccessor(s.successProperty);
-               }
-               this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
-               if (s.id) {
-                       var g = this.getJsonAccessor(s.id);
-                       this.getId = function(rec) {
-                               var r = g(rec);  
-                               return (r === undefined || r === "") ? null : r;
-                       };
-               } else {
-                       this.getId = function(){return null;};
-               }
-            this.ef = [];
-            for(var jj = 0; jj < fl; jj++){
-                f = fi[jj];
-                var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
-                this.ef[jj] = this.getJsonAccessor(map);
+     * 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 d = (bypassFilter === true && this.snapshot) ?
+                this.snapshot.items : this.data.items;
+        var v, sv, r = [], l = {};
+        for(var i = 0, len = d.length; i < len; i++){
+            v = d[i].data[dataIndex];
+            sv = String(v);
+            if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
+                l[sv] = true;
+                r[r.length] = v;
             }
         }
+        return r;
+    },
 
-       var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
-       if(s.totalProperty){
-            var vt = parseInt(this.getTotal(o), 10);
-            if(!isNaN(vt)){
-                totalRecords = vt;
+    /**
+     * Revert to a view of the Record cache with no filtering applied.
+     * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
+     */
+    clearFilter : function(suppressEvent){
+        if(this.snapshot && this.snapshot != this.data){
+            this.data = this.snapshot;
+            delete this.snapshot;
+            if(suppressEvent !== true){
+                this.fireEvent("datachanged", this);
             }
         }
-        if(s.successProperty){
-            var vs = this.getSuccess(o);
-            if(vs === false || vs === 'false'){
-                success = false;
-            }
+    },
+
+    // private
+    afterEdit : function(record){
+        if(this.modified.indexOf(record) == -1){
+            this.modified.push(record);
         }
-        var records = [];
-        for(var i = 0; i < c; i++){
-                var n = root[i];
-            var values = {};
-            var id = this.getId(n);
-            for(var j = 0; j < fl; j++){
-                f = fi[j];
-            var v = this.ef[j](n);
-            if (!f.convert) {
-                Roo.log('missing convert for ' + f.name);
-                Roo.log(f);
-                continue;
-            }
-            values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
-            }
-            var record = new Record(values, id);
-            record.json = n;
-            records[i] = record;
+        this.fireEvent("update", this, record, Roo.data.Record.EDIT);
+    },
+    
+    // private
+    afterReject : function(record){
+        this.modified.remove(record);
+        this.fireEvent("update", this, record, Roo.data.Record.REJECT);
+    },
+
+    // private
+    afterCommit : function(record){
+        this.modified.remove(record);
+        this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
+    },
+
+    /**
+     * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
+     * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
+     */
+    commitChanges : function(){
+        var m = this.modified.slice(0);
+        this.modified = [];
+        for(var i = 0, len = m.length; i < len; i++){
+            m[i].commit();
         }
-        return {
-            raw : o,
-            success : success,
-            records : records,
-            totalRecords : totalRecords
-        };
     },
-    // used when loading children.. @see loadDataFromChildren
-    toLoadData: function(rec)
-    {
-       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
-       var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
-       return { data : data, total : data.length };
-       
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
 
-/**
- * @class Roo.data.XmlReader
- * @extends Roo.data.DataReader
- * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
- * based on mappings in a provided Roo.data.Record constructor.<br><br>
- * <p>
- * <em>Note that 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".</em>
- * <p>
- * Example code:
- * <pre><code>
-var RecordDef = Roo.data.Record.create([
-   {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
-   {name: 'occupation'}                 // This field will use "occupation" as the mapping.
-]);
-var myReader = new Roo.data.XmlReader({
-   totalRecords: "results", // The element which contains the total dataset size (optional)
-   record: "row",           // The repeated element which contains row information
-   id: "id"                 // The element within the row that provides an ID for the record (optional)
-}, RecordDef);
-</code></pre>
- * <p>
- * This would consume an XML file like this:
- * <pre><code>
-&lt;?xml?>
-&lt;dataset>
- &lt;results>2&lt;/results>
- &lt;row>
-   &lt;id>1&lt;/id>
-   &lt;name>Bill&lt;/name>
-   &lt;occupation>Gardener&lt;/occupation>
- &lt;/row>
- &lt;row>
-   &lt;id>2&lt;/id>
-   &lt;name>Ben&lt;/name>
-   &lt;occupation>Horticulturalist&lt;/occupation>
- &lt;/row>
-&lt;/dataset>
-</code></pre>
- * @cfg {String} totalRecords The DomQuery path 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.
- * @cfg {String} record The DomQuery path to the repeated element which contains record information.
- * @cfg {String} success The DomQuery path to the success attribute used by forms.
- * @cfg {String} id The DomQuery path relative from the record element to the element that contains
- * a record identifier value.
- * @constructor
- * Create a new XmlReader
- * @param {Object} meta Metadata configuration options
- * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
- * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
- * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
- */
-Roo.data.XmlReader = function(meta, recordType){
-    meta = meta || {};
-    Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
-};
-Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
-    
-    readerType : 'Xml',
-    
     /**
-     * This method is only used by a DataProxy which has retrieved data from a remote server.
-        * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
-        * to contain a method called 'responseXML' that returns an XML document object.
-     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
-     * a cache of Roo.data.Records.
+     * Cancel outstanding changes on all changed records.
      */
-    read : function(response){
-        var doc = response.responseXML;
-        if(!doc) {
-            throw {message: "XmlReader.read: XML Document not available"};
+    rejectChanges : function(){
+        var m = this.modified.slice(0);
+        this.modified = [];
+        for(var i = 0, len = m.length; i < len; i++){
+            m[i].reject();
         }
-        return this.readRecords(doc);
     },
 
-    /**
-     * Create a data block containing Roo.data.Records from an XML document.
-        * @param {Object} doc A parsed XML document.
-     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
-     * a cache of Roo.data.Records.
-     */
-    readRecords : function(doc){
-        /**
-         * After any data loads/reads, the raw XML Document is available for further custom processing.
-         * @type XMLDocument
-         */
-        this.xmlData = doc;
-        var root = doc.documentElement || doc;
-       var q = Roo.DomQuery;
-       var recordType = this.recordType, fields = recordType.prototype.fields;
-       var sid = this.meta.id;
-       var totalRecords = 0, success = true;
-       if(this.meta.totalRecords){
-           totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
-       }
+    onMetaChange : function(meta, rtype, o){
+        this.recordType = rtype;
+        this.fields = rtype.prototype.fields;
+        delete this.snapshot;
+        this.sortInfo = meta.sortInfo || this.sortInfo;
+        this.modified = [];
+        this.fireEvent('metachange', this, this.reader.meta);
+    },
+    
+    moveIndex : function(data, type)
+    {
+        var index = this.indexOf(data);
+        
+        var newIndex = index + type;
+        
+        this.remove(data);
+        
+        this.insert(newIndex, data);
         
-        if(this.meta.success){
-            var sv = q.selectValue(this.meta.success, root, true);
-            success = sv !== false && sv !== 'false';
-       }
-       var records = [];
-       var ns = q.select(this.meta.record, root);
-        for(var i = 0, len = ns.length; i < len; i++) {
-               var n = ns[i];
-               var values = {};
-               var id = sid ? q.selectValue(sid, n) : undefined;
-               for(var j = 0, jlen = fields.length; j < jlen; j++){
-                   var f = fields.items[j];
-                var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
-                   v = f.convert(v);
-                   values[f.name] = v;
-               }
-               var record = new recordType(values, id);
-               record.node = n;
-               records[records.length] = record;
-           }
-
-           return {
-               success : success,
-               records : records,
-               totalRecords : totalRecords || records.length
-           };
     }
 });/*
  * Based on:
@@ -24630,91 +24035,222 @@ Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
  */
 
 /**
- * @class Roo.data.ArrayReader
- * @extends Roo.data.DataReader
- * Data reader class to create an Array of Roo.data.Record objects from an Array.
- * Each element of that Array represents a row of data fields. The
- * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
- * of the field definition if it exists, or the field's ordinal position in the definition.<br>
- * <p>
- * Example code:.
- * <pre><code>
-var RecordDef = Roo.data.Record.create([
-    {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
-    {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
-]);
-var myReader = new Roo.data.ArrayReader({
-    id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
-}, RecordDef);
+ * @class Roo.data.SimpleStore
+ * @extends Roo.data.Store
+ * Small helper class to make creating Stores from Array data easier.
+ * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
+ * @cfg {Array} fields An array of field definition objects, or field name strings.
+ * @cfg {Object} an existing reader (eg. copied from another store)
+ * @cfg {Array} data The multi-dimensional array of data
+ * @constructor
+ * @param {Object} config
+ */
+Roo.data.SimpleStore = function(config)
+{
+    Roo.data.SimpleStore.superclass.constructor.call(this, {
+        isLocal : true,
+        reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
+                id: config.id
+            },
+            Roo.data.Record.create(config.fields)
+        ),
+        proxy : new Roo.data.MemoryProxy(config.data)
+    });
+    this.load();
+};
+Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+/**
+ * @extends Roo.data.Store
+ * @class Roo.data.JsonStore
+ * Small helper class to make creating Stores for JSON data easier. <br/>
+<pre><code>
+var store = new Roo.data.JsonStore({
+    url: 'get-images.php',
+    root: 'images',
+    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
+});
 </code></pre>
- * <p>
- * This would consume an Array like this:
- * <pre><code>
-[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
-  </code></pre>
+ * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
+ * JsonReader and HttpProxy (unless inline data is provided).</b>
+ * @cfg {Array} fields An array of field definition objects, or field name strings.
  * @constructor
- * Create a new JsonReader
- * @param {Object} meta Metadata configuration options.
- * @param {Object|Array} recordType Either an Array of field definition objects
- * 
- * @cfg {Array} fields Array of field definition objects
- * @cfg {String} id Name of the property within a row object that contains a record identifier value.
- * as specified to {@link Roo.data.Record#create},
- * or an {@link Roo.data.Record} object
+ * @param {Object} config
+ */
+Roo.data.JsonStore = function(c){
+    Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
+        proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
+        reader: new Roo.data.JsonReader(c, c.fields)
+    }));
+};
+Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+Roo.data.Field = function(config){
+    if(typeof config == "string"){
+        config = {name: config};
+    }
+    Roo.apply(this, config);
+    
+    if(!this.type){
+        this.type = "auto";
+    }
+    
+    var st = Roo.data.SortTypes;
+    // named sortTypes are supported, here we look them up
+    if(typeof this.sortType == "string"){
+        this.sortType = st[this.sortType];
+    }
+    
+    // set default sortType for strings and dates
+    if(!this.sortType){
+        switch(this.type){
+            case "string":
+                this.sortType = st.asUCString;
+                break;
+            case "date":
+                this.sortType = st.asDate;
+                break;
+            default:
+                this.sortType = st.none;
+        }
+    }
+
+    // define once
+    var stripRe = /[\$,%]/g;
+
+    // prebuilt conversion function for this field, instead of
+    // switching every time we're reading a value
+    if(!this.convert){
+        var cv, dateFormat = this.dateFormat;
+        switch(this.type){
+            case "":
+            case "auto":
+            case undefined:
+                cv = function(v){ return v; };
+                break;
+            case "string":
+                cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
+                break;
+            case "int":
+                cv = function(v){
+                    return v !== undefined && v !== null && v !== '' ?
+                           parseInt(String(v).replace(stripRe, ""), 10) : '';
+                    };
+                break;
+            case "float":
+                cv = function(v){
+                    return v !== undefined && v !== null && v !== '' ?
+                           parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
+                    };
+                break;
+            case "bool":
+            case "boolean":
+                cv = function(v){ return v === true || v === "true" || v == 1; };
+                break;
+            case "date":
+                cv = function(v){
+                    if(!v){
+                        return '';
+                    }
+                    if(v instanceof Date){
+                        return v;
+                    }
+                    if(dateFormat){
+                        if(dateFormat == "timestamp"){
+                            return new Date(v*1000);
+                        }
+                        return Date.parseDate(v, dateFormat);
+                    }
+                    var parsed = Date.parse(v);
+                    return parsed ? new Date(parsed) : null;
+                };
+             break;
+            
+        }
+        this.convert = cv;
+    }
+};
+
+Roo.data.Field.prototype = {
+    dateFormat: null,
+    defaultValue: "",
+    mapping: null,
+    sortType : null,
+    sortDir : "ASC"
+};/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
  *
- * 
- * created using {@link Roo.data.Record#create}.
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
  */
-Roo.data.ArrayReader = function(meta, recordType)
-{    
-    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+// Base class for reading structured data from a data source.  This class is intended to be
+// extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
+
+/**
+ * @class Roo.data.DataReader
+ * Base class for reading structured data from a data source.  This class is intended to be
+ * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
+ */
+
+Roo.data.DataReader = function(meta, recordType){
+    
+    this.meta = meta;
+    
+    this.recordType = recordType instanceof Array ? 
+        Roo.data.Record.create(recordType) : recordType;
 };
 
-Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
+Roo.data.DataReader.prototype = {
     
-      /**
-     * Create a data block containing Roo.data.Records from an XML document.
-     * @param {Object} o An Array of row objects which represents the dataset.
-     * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
-     * a cache of Roo.data.Records.
+    
+    readerType : 'Data',
+     /**
+     * Create an empty record
+     * @param {Object} data (optional) - overlay some values
+     * @return {Roo.data.Record} record created.
      */
-    readRecords : function(o)
-    {
-        var sid = this.meta ? this.meta.id : null;
-       var recordType = this.recordType, fields = recordType.prototype.fields;
-       var records = [];
-       var root = o;
-       for(var i = 0; i < root.length; i++){
-               var n = root[i];
-           var values = {};
-           var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
-           for(var j = 0, jlen = fields.length; j < jlen; j++){
-               var f = fields.items[j];
-               var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
-               var v = n[k] !== undefined ? n[k] : f.defaultValue;
-               v = f.convert(v);
-               values[f.name] = v;
-           }
-           var record = new recordType(values, id);
-           record.json = n;
-           records[records.length] = record;
-       }
-       return {
-           records : records,
-           totalRecords : records.length
-       };
-    },
-    // used when loading children.. @see loadDataFromChildren
-    toLoadData: function(rec)
-    {
-       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
-       return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
-       
+    newRow :  function(d) {
+        var da =  {};
+        this.recordType.prototype.fields.each(function(c) {
+            switch( c.type) {
+                case 'int' : da[c.name] = 0; break;
+                case 'date' : da[c.name] = new Date(); break;
+                case 'float' : da[c.name] = 0.0; break;
+                case 'boolean' : da[c.name] = false; break;
+                default : da[c.name] = ""; break;
+            }
+            
+        });
+        return new this.recordType(Roo.apply(da, d));
     }
     
     
-});/*
+};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -24725,1198 +24261,1662 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  * <script type="text/javascript">
  */
 
-
 /**
- * @class Roo.data.Tree
- * @extends Roo.util.Observable
- * Represents a tree data structure and bubbles all the events for its nodes. The nodes
- * in the tree have most standard DOM functionality.
- * @constructor
- * @param {Node} root (optional) The root node
+ * @class Roo.data.DataProxy
+ * @extends Roo.data.Observable
+ * This class is an abstract base class for implementations which provide retrieval of
+ * unformatted data objects.<br>
+ * <p>
+ * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
+ * (of the appropriate type which knows how to parse the data object) to provide a block of
+ * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
+ * <p>
+ * Custom implementations must implement the load method as described in
+ * {@link Roo.data.HttpProxy#load}.
  */
-Roo.data.Tree = function(root){
-   this.nodeHash = {};
-   /**
-    * The root node for this tree
-    * @type Node
-    */
-   this.root = null;
-   if(root){
-       this.setRootNode(root);
-   }
-   this.addEvents({
-       /**
-        * @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
-        */
-       "append" : true,
-       /**
-        * @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
-        */
-       "remove" : true,
-       /**
-        * @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
-        */
-       "move" : true,
-       /**
-        * @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
-        */
-       "insert" : true,
-       /**
-        * @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
-        */
-       "beforeappend" : true,
-       /**
-        * @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
-        */
-       "beforeremove" : true,
-       /**
-        * @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
-        */
-       "beforemove" : true,
-       /**
-        * @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
-        */
-       "beforeinsert" : true
-   });
-
-    Roo.data.Tree.superclass.constructor.call(this);
+Roo.data.DataProxy = function(){
+    this.addEvents({
+        /**
+         * @event beforeload
+         * Fires before a network request is made to retrieve a data object.
+         * @param {Object} This DataProxy object.
+         * @param {Object} params The params parameter to the load function.
+         */
+        beforeload : true,
+        /**
+         * @event load
+         * Fires before the load method's callback is called.
+         * @param {Object} This DataProxy object.
+         * @param {Object} o The data object.
+         * @param {Object} arg The callback argument object passed to the load function.
+         */
+        load : true,
+        /**
+         * @event loadexception
+         * Fires if an Exception occurs during data retrieval.
+         * @param {Object} This DataProxy object.
+         * @param {Object} o The data object.
+         * @param {Object} arg The callback argument object passed to the load function.
+         * @param {Object} e The Exception.
+         */
+        loadexception : true
+    });
+    Roo.data.DataProxy.superclass.constructor.call(this);
 };
 
-Roo.extend(Roo.data.Tree, Roo.util.Observable, {
-    pathSeparator: "/",
-
-    proxyNodeEvent : function(){
-        return this.fireEvent.apply(this, arguments);
-    },
-
-    /**
-     * Returns the root node for this tree.
-     * @return {Node}
-     */
-    getRootNode : function(){
-        return this.root;
-    },
+Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
 
     /**
-     * Sets the root node for this tree.
-     * @param {Node} node
-     * @return {Node}
+     * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
      */
-    setRootNode : function(node){
-        this.root = node;
-        node.ownerTree = this;
-        node.isRoot = true;
-        this.registerNode(node);
-        return node;
-    },
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.data.MemoryProxy
+ * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
+ * to the Reader when its load method is called.
+ * @constructor
+ * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
+ */
+Roo.data.MemoryProxy = function(data){
+    if (data.data) {
+        data = data.data;
+    }
+    Roo.data.MemoryProxy.superclass.constructor.call(this);
+    this.data = data;
+};
 
+Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
+    
     /**
-     * Gets a node in this tree by its id.
-     * @param {String} id
-     * @return {Node}
+     * Load data from the requested source (in this case an in-memory
+     * data object passed to the constructor), read the data object into
+     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
+     * process that block using the passed callback.
+     * @param {Object} params This parameter is not used by the MemoryProxy class.
+     * @param {Roo.data.DataReader} reader The Reader object which converts the data
+     * object into a block of Roo.data.Records.
+     * @param {Function} callback The function into which to pass the block of Roo.data.records.
+     * The function must be passed <ul>
+     * <li>The Record block object</li>
+     * <li>The "arg" argument from the load function</li>
+     * <li>A boolean success indicator</li>
+     * </ul>
+     * @param {Object} scope The scope in which to call the callback
+     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
      */
-    getNodeById : function(id){
-        return this.nodeHash[id];
-    },
-
-    registerNode : function(node){
-        this.nodeHash[node.id] = node;
-    },
-
-    unregisterNode : function(node){
-        delete this.nodeHash[node.id];
+    load : function(params, reader, callback, scope, arg){
+        params = params || {};
+        var result;
+        try {
+            result = reader.readRecords(params.data ? params.data :this.data);
+        }catch(e){
+            this.fireEvent("loadexception", this, arg, null, e);
+            callback.call(scope, null, arg, false);
+            return;
+        }
+        callback.call(scope, result, arg, true);
     },
-
-    toString : function(){
-        return "[Tree"+(this.id?" "+this.id:"")+"]";
+    
+    // private
+    update : function(params, records){
+        
     }
-});
-
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 /**
- * @class Roo.data.Node
- * @extends Roo.util.Observable
- * @cfg {Boolean} leaf true if this node is a leaf and does not have children
- * @cfg {String} id The id for this node. If one is not specified, one is generated.
+ * @class Roo.data.HttpProxy
+ * @extends Roo.data.DataProxy
+ * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
+ * configured to reference a certain URL.<br><br>
+ * <p>
+ * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
+ * from which the running page was served.<br><br>
+ * <p>
+ * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
+ * <p>
+ * Be aware that to enable the browser to parse an XML document, the server must set
+ * the Content-Type header in the HTTP response to "text/xml".
  * @constructor
- * @param {Object} attributes The attributes/config for the node
+ * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
+ * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
+ * will be used to make the request.
  */
-Roo.data.Node = function(attributes){
+Roo.data.HttpProxy = function(conn){
+    Roo.data.HttpProxy.superclass.constructor.call(this);
+    // is conn a conn config or a real conn?
+    this.conn = conn;
+    this.useAjax = !conn || !conn.events;
+  
+};
+
+Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
+    // thse are take from connection...
+    
     /**
-     * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
-     * @type {Object}
+     * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
      */
-    this.attributes = attributes || {};
-    this.leaf = this.attributes.leaf;
     /**
-     * The node id. @type String
+     * @cfg {Object} extraParams (Optional) An object containing properties which are used as
+     * extra parameters to each request made by this object. (defaults to undefined)
      */
-    this.id = this.attributes.id;
-    if(!this.id){
-        this.id = Roo.id(null, "ynode-");
-        this.attributes.id = this.id;
-    }
-     
-    
     /**
-     * All child nodes of this node. @type Array
+     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
+     *  to each request made by this object. (defaults to undefined)
      */
-    this.childNodes = [];
-    if(!this.childNodes.indexOf){ // indexOf is a must
-        this.childNodes.indexOf = function(o){
-            for(var i = 0, len = this.length; i < len; i++){
-                if(this[i] == o) {
-                    return i;
-                }
-            }
-            return -1;
-        };
-    }
     /**
-     * The parent node for this node. @type Node
+     * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
      */
-    this.parentNode = null;
     /**
-     * The first direct child node of this node, or null if this node has no child nodes. @type Node
+     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
      */
-    this.firstChild = null;
-    /**
-     * The last direct child node of this node, or null if this node has no child nodes. @type Node
+     /**
+     * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
+     * @type Boolean
      */
-    this.lastChild = null;
+  
+
     /**
-     * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
+     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
+     * @type Boolean
      */
-    this.previousSibling = null;
     /**
-     * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
+     * Return the {@link Roo.data.Connection} object being used by this Proxy.
+     * @return {Connection} The Connection object. This object may be used to subscribe to events on
+     * a finer-grained basis than the DataProxy events.
      */
-    this.nextSibling = null;
-
-    this.addEvents({
-       /**
-        * @event append
-        * Fires when a new child node is appended
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The newly appended node
-        * @param {Number} index The index of the newly appended node
-        */
-       "append" : true,
-       /**
-        * @event remove
-        * Fires when a child node is removed
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The removed node
-        */
-       "remove" : true,
-       /**
-        * @event move
-        * Fires when this node is moved to a new location in the tree
-        * @param {Tree} tree The owner 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 {Number} index The index it was moved to
-        */
-       "move" : true,
-       /**
-        * @event insert
-        * Fires when a new child node is inserted.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The child node inserted
-        * @param {Node} refNode The child node the node was inserted before
-        */
-       "insert" : true,
-       /**
-        * @event beforeappend
-        * Fires before a new child is appended, return false to cancel the append.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The child node to be appended
-        */
-       "beforeappend" : true,
-       /**
-        * @event beforeremove
-        * Fires before a child is removed, return false to cancel the remove.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The child node to be removed
-        */
-       "beforeremove" : true,
-       /**
-        * @event beforemove
-        * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
-        * @param {Tree} tree The owner tree
-        * @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 {Number} index The index it is being moved to
-        */
-       "beforemove" : true,
-       /**
-        * @event beforeinsert
-        * Fires before a new child is inserted, return false to cancel the insert.
-        * @param {Tree} tree The owner tree
-        * @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
-        */
-       "beforeinsert" : true
-   });
-    this.listeners = this.attributes.listeners;
-    Roo.data.Node.superclass.constructor.call(this);
-};
+    getConnection : function(){
+        return this.useAjax ? Roo.Ajax : this.conn;
+    },
 
-Roo.extend(Roo.data.Node, Roo.util.Observable, {
-    fireEvent : function(evtName){
-        // first do standard event for this node
-        if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
-            return false;
-        }
-        // then bubble it up to the tree if the event wasn't cancelled
-        var ot = this.getOwnerTree();
-        if(ot){
-            if(ot.proxyNodeEvent.apply(ot, arguments) === false){
-                return false;
+    /**
+     * Load data from the configured {@link Roo.data.Connection}, read the data object into
+     * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
+     * process that block using the passed callback.
+     * @param {Object} params An object containing properties which are to be used as HTTP parameters
+     * for the request to the remote server.
+     * @param {Roo.data.DataReader} reader The Reader object which converts the data
+     * object into a block of Roo.data.Records.
+     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
+     * The function must be passed <ul>
+     * <li>The Record block object</li>
+     * <li>The "arg" argument from the load function</li>
+     * <li>A boolean success indicator</li>
+     * </ul>
+     * @param {Object} scope The scope in which to call the callback
+     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+     */
+    load : function(params, reader, callback, scope, arg){
+        if(this.fireEvent("beforeload", this, params) !== false){
+            var  o = {
+                params : params || {},
+                request: {
+                    callback : callback,
+                    scope : scope,
+                    arg : arg
+                },
+                reader: reader,
+                callback : this.loadResponse,
+                scope: this
+            };
+            if(this.useAjax){
+                Roo.applyIf(o, this.conn);
+                if(this.activeRequest){
+                    Roo.Ajax.abort(this.activeRequest);
+                }
+                this.activeRequest = Roo.Ajax.request(o);
+            }else{
+                this.conn.request(o);
             }
+        }else{
+            callback.call(scope||this, null, arg, false);
         }
-        return true;
     },
 
-    /**
-     * Returns true if this node is a leaf
-     * @return {Boolean}
-     */
-    isLeaf : function(){
-        return this.leaf === true;
+    // private
+    loadResponse : function(o, success, response){
+        delete this.activeRequest;
+        if(!success){
+            this.fireEvent("loadexception", this, o, response);
+            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+            return;
+        }
+        var result;
+        try {
+            result = o.reader.read(response);
+        }catch(e){
+            this.fireEvent("loadexception", this, o, response, e);
+            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+            return;
+        }
+        
+        this.fireEvent("load", this, o, o.request.arg);
+        o.request.callback.call(o.request.scope, result, o.request.arg, true);
     },
 
     // private
-    setFirstChild : function(node){
-        this.firstChild = node;
-    },
+    update : function(dataSet){
 
-    //private
-    setLastChild : function(node){
-        this.lastChild = node;
     },
 
+    // private
+    updateResponse : function(dataSet){
+
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.data.ScriptTagProxy
+ * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
+ * other than the originating domain of the running page.<br><br>
+ * <p>
+ * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
+ * of the running page, you must use this class, rather than DataProxy.</em><br><br>
+ * <p>
+ * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
+ * source code that is used as the source inside a &lt;script> tag.<br><br>
+ * <p>
+ * In order for the browser to process the returned data, the server must wrap the data object
+ * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
+ * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
+ * depending on whether the callback name was passed:
+ * <p>
+ * <pre><code>
+boolean scriptTag = false;
+String cb = request.getParameter("callback");
+if (cb != null) {
+    scriptTag = true;
+    response.setContentType("text/javascript");
+} else {
+    response.setContentType("application/x-json");
+}
+Writer out = response.getWriter();
+if (scriptTag) {
+    out.write(cb + "(");
+}
+out.print(dataBlock.toJsonString());
+if (scriptTag) {
+    out.write(");");
+}
+</pre></code>
+ *
+ * @constructor
+ * @param {Object} config A configuration object.
+ */
+Roo.data.ScriptTagProxy = function(config){
+    Roo.data.ScriptTagProxy.superclass.constructor.call(this);
+    Roo.apply(this, config);
+    this.head = document.getElementsByTagName("head")[0];
+};
+
+Roo.data.ScriptTagProxy.TRANS_ID = 1000;
 
+Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
     /**
-     * Returns true if this node is the last child of its parent
-     * @return {Boolean}
+     * @cfg {String} url The URL from which to request the data object.
      */
-    isLast : function(){
-       return (!this.parentNode ? true : this.parentNode.lastChild == this);
-    },
-
     /**
-     * Returns true if this node is the first child of its parent
-     * @return {Boolean}
+     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
      */
-    isFirst : function(){
-       return (!this.parentNode ? true : this.parentNode.firstChild == this);
-    },
-
-    hasChildNodes : function(){
-        return !this.isLeaf() && this.childNodes.length > 0;
-    },
+    timeout : 30000,
+    /**
+     * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
+     * the server the name of the callback function set up by the load call to process the returned data object.
+     * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
+     * javascript output which calls this named function passing the data object as its only parameter.
+     */
+    callbackParam : "callback",
+    /**
+     *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
+     * name to the request.
+     */
+    nocache : true,
 
     /**
-     * Insert node(s) as the last child node of this node.
-     * @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
+     * Load data from the configured URL, read the data object into
+     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
+     * process that block using the passed callback.
+     * @param {Object} params An object containing properties which are to be used as HTTP parameters
+     * for the request to the remote server.
+     * @param {Roo.data.DataReader} reader The Reader object which converts the data
+     * object into a block of Roo.data.Records.
+     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
+     * The function must be passed <ul>
+     * <li>The Record block object</li>
+     * <li>The "arg" argument from the load function</li>
+     * <li>A boolean success indicator</li>
+     * </ul>
+     * @param {Object} scope The scope in which to call the callback
+     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
      */
-    appendChild : function(node){
-        var multi = false;
-        if(node instanceof Array){
-            multi = node;
-        }else if(arguments.length > 1){
-            multi = arguments;
-        }
-        
-        // if passed an array or multiple args do them one by one
-        if(multi){
-            for(var i = 0, len = multi.length; i < len; i++) {
-               this.appendChild(multi[i]);
-            }
-        }else{
-            if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
-                return false;
-            }
-            var index = this.childNodes.length;
-            var oldParent = node.parentNode;
-            // it's a move, make sure we move it cleanly
-            if(oldParent){
-                if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
-                    return false;
-                }
-                oldParent.removeChild(node);
-            }
-            
-            index = this.childNodes.length;
-            if(index == 0){
-                this.setFirstChild(node);
-            }
-            this.childNodes.push(node);
-            node.parentNode = this;
-            var ps = this.childNodes[index-1];
-            if(ps){
-                node.previousSibling = ps;
-                ps.nextSibling = node;
-            }else{
-                node.previousSibling = null;
-            }
-            node.nextSibling = null;
-            this.setLastChild(node);
-            node.setOwnerTree(this.getOwnerTree());
-            this.fireEvent("append", this.ownerTree, this, node, index);
-            if(this.ownerTree) {
-                this.ownerTree.fireEvent("appendnode", this, node, index);
+    load : function(params, reader, callback, scope, arg){
+        if(this.fireEvent("beforeload", this, params) !== false){
+
+            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
+
+            var url = this.url;
+            url += (url.indexOf("?") != -1 ? "&" : "?") + p;
+            if(this.nocache){
+                url += "&_dc=" + (new Date().getTime());
             }
-            if(oldParent){
-                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
+            var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
+            var trans = {
+                id : transId,
+                cb : "stcCallback"+transId,
+                scriptId : "stcScript"+transId,
+                params : params,
+                arg : arg,
+                url : url,
+                callback : callback,
+                scope : scope,
+                reader : reader
+            };
+            var conn = this;
+
+            window[trans.cb] = function(o){
+                conn.handleResponse(o, trans);
+            };
+
+            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
+
+            if(this.autoAbort !== false){
+                this.abort();
             }
-            return node;
+
+            trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
+
+            var script = document.createElement("script");
+            script.setAttribute("src", url);
+            script.setAttribute("type", "text/javascript");
+            script.setAttribute("id", trans.scriptId);
+            this.head.appendChild(script);
+
+            this.trans = trans;
+        }else{
+            callback.call(scope||this, null, arg, false);
         }
     },
 
+    // private
+    isLoading : function(){
+        return this.trans ? true : false;
+    },
+
     /**
-     * Removes a child node from this node.
-     * @param {Node} node The node to remove
-     * @return {Node} The removed node
+     * Abort the current server request.
      */
-    removeChild : function(node){
-        var index = this.childNodes.indexOf(node);
-        if(index == -1){
-            return false;
-        }
-        if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
-            return false;
+    abort : function(){
+        if(this.isLoading()){
+            this.destroyTrans(this.trans);
         }
+    },
 
-        // remove it from childNodes collection
-        this.childNodes.splice(index, 1);
-
-        // update siblings
-        if(node.previousSibling){
-            node.previousSibling.nextSibling = node.nextSibling;
-        }
-        if(node.nextSibling){
-            node.nextSibling.previousSibling = node.previousSibling;
+    // private
+    destroyTrans : function(trans, isLoaded){
+        this.head.removeChild(document.getElementById(trans.scriptId));
+        clearTimeout(trans.timeoutId);
+        if(isLoaded){
+            window[trans.cb] = undefined;
+            try{
+                delete window[trans.cb];
+            }catch(e){}
+        }else{
+            // if hasn't been loaded, wait for load to remove it to prevent script error
+            window[trans.cb] = function(){
+                window[trans.cb] = undefined;
+                try{
+                    delete window[trans.cb];
+                }catch(e){}
+            };
         }
+    },
 
-        // update child refs
-        if(this.firstChild == node){
-            this.setFirstChild(node.nextSibling);
-        }
-        if(this.lastChild == node){
-            this.setLastChild(node.previousSibling);
+    // private
+    handleResponse : function(o, trans){
+        this.trans = false;
+        this.destroyTrans(trans, true);
+        var result;
+        try {
+            result = trans.reader.readRecords(o);
+        }catch(e){
+            this.fireEvent("loadexception", this, o, trans.arg, e);
+            trans.callback.call(trans.scope||window, null, trans.arg, false);
+            return;
         }
-
-        node.setOwnerTree(null);
-        // clear any references from the node
-        node.parentNode = null;
-        node.previousSibling = null;
-        node.nextSibling = null;
-        this.fireEvent("remove", this.ownerTree, this, node);
-        return node;
+        this.fireEvent("load", this, o, trans.arg);
+        trans.callback.call(trans.scope||window, result, trans.arg, true);
     },
 
+    // private
+    handleFailure : function(trans){
+        this.trans = false;
+        this.destroyTrans(trans, false);
+        this.fireEvent("loadexception", this, null, trans.arg);
+        trans.callback.call(trans.scope||window, null, trans.arg, false);
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.data.JsonReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of Roo.data.Record objects from a JSON response
+ * based on mappings in a provided Roo.data.Record constructor.
+ * 
+ * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
+ * in the reply previously. 
+ * 
+ * <p>
+ * Example code:
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
+    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
+]);
+var myReader = new Roo.data.JsonReader({
+    totalProperty: "results",    // The property which contains the total dataset size (optional)
+    root: "rows",                // The property which contains an Array of row objects
+    id: "id"                     // The property within each row object that provides an ID for the record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume a JSON file like this:
+ * <pre><code>
+{ 'results': 2, 'rows': [
+    { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
+    { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
+}
+</code></pre>
+ * @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.
+ * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
+ * @cfg {String} root name of the property which contains the Array of row objects.
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
+ * @cfg {Array} fields Array of field definition objects
+ * @constructor
+ * Create a new JsonReader
+ * @param {Object} meta Metadata configuration options
+ * @param {Object} recordType Either an Array of field definition objects,
+ * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
+ */
+Roo.data.JsonReader = function(meta, recordType){
+    
+    meta = meta || {};
+    // set some defaults:
+    Roo.applyIf(meta, {
+        totalProperty: 'total',
+        successProperty : 'success',
+        root : 'data',
+        id : 'id'
+    });
+    
+    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+};
+Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
+    
+    readerType : 'Json',
+    
     /**
-     * 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
+     * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
+     * Used by Store query builder to append _requestMeta to params.
+     * 
      */
-    insertBefore : function(node, refNode){
-        if(!refNode){ // like standard Dom, refNode can be null for append
-            return this.appendChild(node);
+    metaFromRemote : false,
+    /**
+     * This method is only used by a DataProxy which has retrieved data from a remote server.
+     * @param {Object} response The XHR object which contains the JSON data in its responseText.
+     * @return {Object} data A data block which is used by an Roo.data.Store object as
+     * a cache of Roo.data.Records.
+     */
+    read : function(response){
+        var json = response.responseText;
+       
+        var o = /* eval:var:o */ eval("("+json+")");
+        if(!o) {
+            throw {message: "JsonReader.read: Json object not found"};
         }
-        // nothing to do
-        if(node == refNode){
-            return false;
+        
+        if(o.metaData){
+            
+            delete this.ef;
+            this.metaFromRemote = true;
+            this.meta = o.metaData;
+            this.recordType = Roo.data.Record.create(o.metaData.fields);
+            this.onMetaChange(this.meta, this.recordType, o);
         }
+        return this.readRecords(o);
+    },
 
-        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
-            return false;
-        }
-        var index = this.childNodes.indexOf(refNode);
-        var oldParent = node.parentNode;
-        var refIndex = index;
+    // private function a store will implement
+    onMetaChange : function(meta, recordType, o){
 
-        // when moving internally, indexes will change after remove
-        if(oldParent == this && this.childNodes.indexOf(node) < index){
-            refIndex--;
+    },
+
+    /**
+        * @ignore
+        */
+    simpleAccess: function(obj, subsc) {
+       return obj[subsc];
+    },
+
+       /**
+        * @ignore
+        */
+    getJsonAccessor: function(){
+        var re = /[\[\.]/;
+        return function(expr) {
+            try {
+                return(re.test(expr))
+                    ? new Function("obj", "return obj." + expr)
+                    : function(obj){
+                        return obj[expr];
+                    };
+            } catch(e){}
+            return Roo.emptyFn;
+        };
+    }(),
+
+    /**
+     * Create a data block containing Roo.data.Records from an XML document.
+     * @param {Object} o An object which contains an Array of row objects in the property specified
+     * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
+     * which contains the total size of the dataset.
+     * @return {Object} data A data block which is used by an Roo.data.Store object as
+     * a cache of Roo.data.Records.
+     */
+    readRecords : function(o){
+        /**
+         * After any data loads, the raw JSON data is available for further custom processing.
+         * @type Object
+         */
+        this.o = o;
+        var s = this.meta, Record = this.recordType,
+            f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
+
+//      Generate extraction functions for the totalProperty, the root, the id, and for each field
+        if (!this.ef) {
+            if(s.totalProperty) {
+                   this.getTotal = this.getJsonAccessor(s.totalProperty);
+               }
+               if(s.successProperty) {
+                   this.getSuccess = this.getJsonAccessor(s.successProperty);
+               }
+               this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
+               if (s.id) {
+                       var g = this.getJsonAccessor(s.id);
+                       this.getId = function(rec) {
+                               var r = g(rec);  
+                               return (r === undefined || r === "") ? null : r;
+                       };
+               } else {
+                       this.getId = function(){return null;};
+               }
+            this.ef = [];
+            for(var jj = 0; jj < fl; jj++){
+                f = fi[jj];
+                var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
+                this.ef[jj] = this.getJsonAccessor(map);
+            }
         }
 
-        // it's a move, make sure we move it cleanly
-        if(oldParent){
-            if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
-                return false;
+       var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
+       if(s.totalProperty){
+            var vt = parseInt(this.getTotal(o), 10);
+            if(!isNaN(vt)){
+                totalRecords = vt;
             }
-            oldParent.removeChild(node);
         }
-        if(refIndex == 0){
-            this.setFirstChild(node);
-        }
-        this.childNodes.splice(refIndex, 0, node);
-        node.parentNode = this;
-        var ps = this.childNodes[refIndex-1];
-        if(ps){
-            node.previousSibling = ps;
-            ps.nextSibling = node;
-        }else{
-            node.previousSibling = null;
+        if(s.successProperty){
+            var vs = this.getSuccess(o);
+            if(vs === false || vs === 'false'){
+                success = false;
+            }
         }
-        node.nextSibling = refNode;
-        refNode.previousSibling = node;
-        node.setOwnerTree(this.getOwnerTree());
-        this.fireEvent("insert", this.ownerTree, this, node, refNode);
-        if(oldParent){
-            node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
+        var records = [];
+        for(var i = 0; i < c; i++){
+                var n = root[i];
+            var values = {};
+            var id = this.getId(n);
+            for(var j = 0; j < fl; j++){
+                f = fi[j];
+            var v = this.ef[j](n);
+            if (!f.convert) {
+                Roo.log('missing convert for ' + f.name);
+                Roo.log(f);
+                continue;
+            }
+            values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
+            }
+            var record = new Record(values, id);
+            record.json = n;
+            records[i] = record;
         }
-        return node;
+        return {
+            raw : o,
+            success : success,
+            records : records,
+            totalRecords : totalRecords
+        };
     },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       return { data : data, total : data.length };
+       
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
+/**
+ * @class Roo.data.XmlReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
+ * based on mappings in a provided Roo.data.Record constructor.<br><br>
+ * <p>
+ * <em>Note that 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".</em>
+ * <p>
+ * Example code:
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+   {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
+   {name: 'occupation'}                 // This field will use "occupation" as the mapping.
+]);
+var myReader = new Roo.data.XmlReader({
+   totalRecords: "results", // The element which contains the total dataset size (optional)
+   record: "row",           // The repeated element which contains row information
+   id: "id"                 // The element within the row that provides an ID for the record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume an XML file like this:
+ * <pre><code>
+&lt;?xml?>
+&lt;dataset>
+ &lt;results>2&lt;/results>
+ &lt;row>
+   &lt;id>1&lt;/id>
+   &lt;name>Bill&lt;/name>
+   &lt;occupation>Gardener&lt;/occupation>
+ &lt;/row>
+ &lt;row>
+   &lt;id>2&lt;/id>
+   &lt;name>Ben&lt;/name>
+   &lt;occupation>Horticulturalist&lt;/occupation>
+ &lt;/row>
+&lt;/dataset>
+</code></pre>
+ * @cfg {String} totalRecords The DomQuery path 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.
+ * @cfg {String} record The DomQuery path to the repeated element which contains record information.
+ * @cfg {String} success The DomQuery path to the success attribute used by forms.
+ * @cfg {String} id The DomQuery path relative from the record element to the element that contains
+ * a record identifier value.
+ * @constructor
+ * Create a new XmlReader
+ * @param {Object} meta Metadata configuration options
+ * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
+ * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
+ * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
+ */
+Roo.data.XmlReader = function(meta, recordType){
+    meta = meta || {};
+    Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+};
+Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
+    
+    readerType : 'Xml',
+    
     /**
-     * Returns the child node at the specified index.
-     * @param {Number} index
-     * @return {Node}
+     * This method is only used by a DataProxy which has retrieved data from a remote server.
+        * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
+        * to contain a method called 'responseXML' that returns an XML document object.
+     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
+     * a cache of Roo.data.Records.
      */
-    item : function(index){
-        return this.childNodes[index];
+    read : function(response){
+        var doc = response.responseXML;
+        if(!doc) {
+            throw {message: "XmlReader.read: XML Document not available"};
+        }
+        return this.readRecords(doc);
     },
 
     /**
-     * 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
+     * Create a data block containing Roo.data.Records from an XML document.
+        * @param {Object} doc A parsed XML document.
+     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
+     * a cache of Roo.data.Records.
      */
-    replaceChild : function(newChild, oldChild){
-        this.insertBefore(newChild, oldChild);
-        this.removeChild(oldChild);
-        return oldChild;
-    },
+    readRecords : function(doc){
+        /**
+         * After any data loads/reads, the raw XML Document is available for further custom processing.
+         * @type XMLDocument
+         */
+        this.xmlData = doc;
+        var root = doc.documentElement || doc;
+       var q = Roo.DomQuery;
+       var recordType = this.recordType, fields = recordType.prototype.fields;
+       var sid = this.meta.id;
+       var totalRecords = 0, success = true;
+       if(this.meta.totalRecords){
+           totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
+       }
+        
+        if(this.meta.success){
+            var sv = q.selectValue(this.meta.success, root, true);
+            success = sv !== false && sv !== 'false';
+       }
+       var records = [];
+       var ns = q.select(this.meta.record, root);
+        for(var i = 0, len = ns.length; i < len; i++) {
+               var n = ns[i];
+               var values = {};
+               var id = sid ? q.selectValue(sid, n) : undefined;
+               for(var j = 0, jlen = fields.length; j < jlen; j++){
+                   var f = fields.items[j];
+                var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
+                   v = f.convert(v);
+                   values[f.name] = v;
+               }
+               var record = new recordType(values, id);
+               record.node = n;
+               records[records.length] = record;
+           }
 
-    /**
-     * Returns the index of a child node
-     * @param {Node} node
-     * @return {Number} The index of the node or -1 if it was not found
-     */
-    indexOf : function(child){
-        return this.childNodes.indexOf(child);
-    },
+           return {
+               success : success,
+               records : records,
+               totalRecords : totalRecords || records.length
+           };
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.data.ArrayReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of Roo.data.Record objects from an Array.
+ * Each element of that Array represents a row of data fields. The
+ * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
+ * of the field definition if it exists, or the field's ordinal position in the definition.<br>
+ * <p>
+ * Example code:.
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+    {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
+    {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
+]);
+var myReader = new Roo.data.ArrayReader({
+    id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume an Array like this:
+ * <pre><code>
+[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
+  </code></pre>
+ * @constructor
+ * Create a new JsonReader
+ * @param {Object} meta Metadata configuration options.
+ * @param {Object|Array} recordType Either an Array of field definition objects
+ * 
+ * @cfg {Array} fields Array of field definition objects
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
+ * as specified to {@link Roo.data.Record#create},
+ * or an {@link Roo.data.Record} object
+ *
+ * 
+ * created using {@link Roo.data.Record#create}.
+ */
+Roo.data.ArrayReader = function(meta, recordType)
+{    
+    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+};
 
-    /**
-     * Returns the tree this node is in.
-     * @return {Tree}
+Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
+    
+      /**
+     * Create a data block containing Roo.data.Records from an XML document.
+     * @param {Object} o An Array of row objects which represents the dataset.
+     * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
+     * a cache of Roo.data.Records.
      */
-    getOwnerTree : function(){
-        // if it doesn't have one, look for one
-        if(!this.ownerTree){
-            var p = this;
-            while(p){
-                if(p.ownerTree){
-                    this.ownerTree = p.ownerTree;
-                    break;
-                }
-                p = p.parentNode;
-            }
-        }
-        return this.ownerTree;
+    readRecords : function(o)
+    {
+        var sid = this.meta ? this.meta.id : null;
+       var recordType = this.recordType, fields = recordType.prototype.fields;
+       var records = [];
+       var root = o;
+       for(var i = 0; i < root.length; i++){
+               var n = root[i];
+           var values = {};
+           var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+           for(var j = 0, jlen = fields.length; j < jlen; j++){
+               var f = fields.items[j];
+               var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
+               var v = n[k] !== undefined ? n[k] : f.defaultValue;
+               v = f.convert(v);
+               values[f.name] = v;
+           }
+           var record = new recordType(values, id);
+           record.json = n;
+           records[records.length] = record;
+       }
+       return {
+           records : records,
+           totalRecords : records.length
+       };
     },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       
+    }
+    
+    
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
-    /**
-     * Returns depth of this node (the root node has a depth of 0)
-     * @return {Number}
-     */
-    getDepth : function(){
-        var depth = 0;
-        var p = this;
-        while(p.parentNode){
-            ++depth;
-            p = p.parentNode;
-        }
-        return depth;
-    },
 
-    // private
-    setOwnerTree : function(tree){
-        // if it's move, we need to update everyone
-        if(tree != this.ownerTree){
-            if(this.ownerTree){
-                this.ownerTree.unregisterNode(this);
-            }
-            this.ownerTree = tree;
-            var cs = this.childNodes;
-            for(var i = 0, len = cs.length; i < len; i++) {
-               cs[i].setOwnerTree(tree);
-            }
-            if(tree){
-                tree.registerNode(this);
-            }
-        }
-    },
+/**
+ * @class Roo.data.Tree
+ * @extends Roo.util.Observable
+ * Represents a tree data structure and bubbles all the events for its nodes. The nodes
+ * in the tree have most standard DOM functionality.
+ * @constructor
+ * @param {Node} root (optional) The root node
+ */
+Roo.data.Tree = function(root){
+   this.nodeHash = {};
+   /**
+    * The root node for this tree
+    * @type Node
+    */
+   this.root = null;
+   if(root){
+       this.setRootNode(root);
+   }
+   this.addEvents({
+       /**
+        * @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
+        */
+       "append" : true,
+       /**
+        * @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
+        */
+       "remove" : true,
+       /**
+        * @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
+        */
+       "move" : true,
+       /**
+        * @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
+        */
+       "insert" : true,
+       /**
+        * @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
+        */
+       "beforeappend" : true,
+       /**
+        * @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
+        */
+       "beforeremove" : true,
+       /**
+        * @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
+        */
+       "beforemove" : true,
+       /**
+        * @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
+        */
+       "beforeinsert" : true
+   });
 
-    /**
-     * Returns the path for this node. The path can be used to expand or select this node programmatically.
-     * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
-     * @return {String} The path
-     */
-    getPath : function(attr){
-        attr = attr || "id";
-        var p = this.parentNode;
-        var b = [this.attributes[attr]];
-        while(p){
-            b.unshift(p.attributes[attr]);
-            p = p.parentNode;
-        }
-        var sep = this.getOwnerTree().pathSeparator;
-        return sep + b.join(sep);
-    },
+    Roo.data.Tree.superclass.constructor.call(this);
+};
 
-    /**
-     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * 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 of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
-     */
-    bubble : function(fn, scope, args){
-        var p = this;
-        while(p){
-            if(fn.call(scope || p, args || p) === false){
-                break;
-            }
-            p = p.parentNode;
-        }
+Roo.extend(Roo.data.Tree, Roo.util.Observable, {
+    pathSeparator: "/",
+
+    proxyNodeEvent : function(){
+        return this.fireEvent.apply(this, arguments);
     },
 
     /**
-     * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * 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 of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     * Returns the root node for this tree.
+     * @return {Node}
      */
-    cascade : function(fn, scope, args){
-        if(fn.call(scope || this, args || this) !== false){
-            var cs = this.childNodes;
-            for(var i = 0, len = cs.length; i < len; i++) {
-               cs[i].cascade(fn, scope, args);
-            }
-        }
+    getRootNode : function(){
+        return this.root;
     },
 
     /**
-     * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * 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 of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     * Sets the root node for this tree.
+     * @param {Node} node
+     * @return {Node}
      */
-    eachChild : function(fn, scope, args){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(fn.call(scope || this, args || cs[i]) === false){
-                   break;
-               }
-        }
+    setRootNode : function(node){
+        this.root = node;
+        node.ownerTree = this;
+        node.isRoot = true;
+        this.registerNode(node);
+        return node;
     },
 
     /**
-     * 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
-     * @return {Node} The found child or null if none was found
+     * Gets a node in this tree by its id.
+     * @param {String} id
+     * @return {Node}
      */
-    findChild : function(attribute, value){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(cs[i].attributes[attribute] == value){
-                   return cs[i];
-               }
-        }
-        return null;
+    getNodeById : function(id){
+        return this.nodeHash[id];
     },
 
-    /**
-     * Finds the first child by a custom function. The child matches if the function passed
-     * returns true.
-     * @param {Function} fn
-     * @param {Object} scope (optional)
-     * @return {Node} The found child or null if none was found
-     */
-    findChildBy : function(fn, scope){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(fn.call(scope||cs[i], cs[i]) === true){
-                   return cs[i];
-               }
-        }
-        return null;
+    registerNode : function(node){
+        this.nodeHash[node.id] = node;
+    },
+
+    unregisterNode : function(node){
+        delete this.nodeHash[node.id];
     },
 
+    toString : function(){
+        return "[Tree"+(this.id?" "+this.id:"")+"]";
+    }
+});
+
+/**
+ * @class Roo.data.Node
+ * @extends Roo.util.Observable
+ * @cfg {Boolean} leaf true if this node is a leaf and does not have children
+ * @cfg {String} id The id for this node. If one is not specified, one is generated.
+ * @constructor
+ * @param {Object} attributes The attributes/config for the node
+ */
+Roo.data.Node = function(attributes){
     /**
-     * Sorts this nodes children using the supplied sort function
-     * @param {Function} fn
-     * @param {Object} scope (optional)
+     * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
+     * @type {Object}
      */
-    sort : function(fn, scope){
-        var cs = this.childNodes;
-        var len = cs.length;
-        if(len > 0){
-            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
-            cs.sort(sortFn);
-            for(var i = 0; i < len; i++){
-                var n = cs[i];
-                n.previousSibling = cs[i-1];
-                n.nextSibling = cs[i+1];
-                if(i == 0){
-                    this.setFirstChild(n);
-                }
-                if(i == len-1){
-                    this.setLastChild(n);
+    this.attributes = attributes || {};
+    this.leaf = this.attributes.leaf;
+    /**
+     * The node id. @type String
+     */
+    this.id = this.attributes.id;
+    if(!this.id){
+        this.id = Roo.id(null, "ynode-");
+        this.attributes.id = this.id;
+    }
+     
+    
+    /**
+     * All child nodes of this node. @type Array
+     */
+    this.childNodes = [];
+    if(!this.childNodes.indexOf){ // indexOf is a must
+        this.childNodes.indexOf = function(o){
+            for(var i = 0, len = this.length; i < len; i++){
+                if(this[i] == o) {
+                    return i;
                 }
             }
-        }
-    },
-
+            return -1;
+        };
+    }
     /**
-     * Returns true if this node is an ancestor (at any point) of the passed node.
-     * @param {Node} node
-     * @return {Boolean}
+     * The parent node for this node. @type Node
      */
-    contains : function(node){
-        return node.isAncestor(this);
+    this.parentNode = null;
+    /**
+     * The first direct child node of this node, or null if this node has no child nodes. @type Node
+     */
+    this.firstChild = null;
+    /**
+     * The last direct child node of this node, or null if this node has no child nodes. @type Node
+     */
+    this.lastChild = null;
+    /**
+     * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
+     */
+    this.previousSibling = null;
+    /**
+     * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
+     */
+    this.nextSibling = null;
+
+    this.addEvents({
+       /**
+        * @event append
+        * Fires when a new child node is appended
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The newly appended node
+        * @param {Number} index The index of the newly appended node
+        */
+       "append" : true,
+       /**
+        * @event remove
+        * Fires when a child node is removed
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The removed node
+        */
+       "remove" : true,
+       /**
+        * @event move
+        * Fires when this node is moved to a new location in the tree
+        * @param {Tree} tree The owner 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 {Number} index The index it was moved to
+        */
+       "move" : true,
+       /**
+        * @event insert
+        * Fires when a new child node is inserted.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The child node inserted
+        * @param {Node} refNode The child node the node was inserted before
+        */
+       "insert" : true,
+       /**
+        * @event beforeappend
+        * Fires before a new child is appended, return false to cancel the append.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The child node to be appended
+        */
+       "beforeappend" : true,
+       /**
+        * @event beforeremove
+        * Fires before a child is removed, return false to cancel the remove.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The child node to be removed
+        */
+       "beforeremove" : true,
+       /**
+        * @event beforemove
+        * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
+        * @param {Tree} tree The owner tree
+        * @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 {Number} index The index it is being moved to
+        */
+       "beforemove" : true,
+       /**
+        * @event beforeinsert
+        * Fires before a new child is inserted, return false to cancel the insert.
+        * @param {Tree} tree The owner tree
+        * @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
+        */
+       "beforeinsert" : true
+   });
+    this.listeners = this.attributes.listeners;
+    Roo.data.Node.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.data.Node, Roo.util.Observable, {
+    fireEvent : function(evtName){
+        // first do standard event for this node
+        if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
+            return false;
+        }
+        // then bubble it up to the tree if the event wasn't cancelled
+        var ot = this.getOwnerTree();
+        if(ot){
+            if(ot.proxyNodeEvent.apply(ot, arguments) === false){
+                return false;
+            }
+        }
+        return true;
     },
 
     /**
-     * Returns true if the passed node is an ancestor (at any point) of this node.
-     * @param {Node} node
+     * Returns true if this node is a leaf
      * @return {Boolean}
      */
-    isAncestor : function(node){
-        var p = this.parentNode;
-        while(p){
-            if(p == node){
-                return true;
-            }
-            p = p.parentNode;
-        }
-        return false;
+    isLeaf : function(){
+        return this.leaf === true;
     },
 
-    toString : function(){
-        return "[Node"+(this.id?" "+this.id:"")+"]";
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
- (function(){ 
-/**
- * @class Roo.Layer
- * @extends Roo.Element
- * An extended {@link Roo.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 create a shadow element with default class "x-layer-shadow", or
- * you can pass a string with a CSS class name. False turns off the shadow.
- * @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 3)
- * @constructor
- * @param {Object} config An object with config options.
- * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
- */
-
-Roo.Layer = function(config, existingEl){
-    config = config || {};
-    var dh = Roo.DomHelper;
-    var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
-    if(existingEl){
-        this.dom = Roo.getDom(existingEl);
-    }
-    if(!this.dom){
-        var o = config.dh || {tag: "div", cls: "x-layer"};
-        this.dom = dh.append(pel, o);
-    }
-    if(config.cls){
-        this.addClass(config.cls);
-    }
-    this.constrain = config.constrain !== false;
-    this.visibilityMode = Roo.Element.VISIBILITY;
-    if(config.id){
-        this.id = this.dom.id = config.id;
-    }else{
-        this.id = Roo.id(this.dom);
-    }
-    this.zindex = config.zindex || this.getZIndex();
-    this.position("absolute", this.zindex);
-    if(config.shadow){
-        this.shadowOffset = config.shadowOffset || 4;
-        this.shadow = new Roo.Shadow({
-            offset : this.shadowOffset,
-            mode : config.shadow
-        });
-    }else{
-        this.shadowOffset = 0;
-    }
-    this.useShim = config.shim !== false && Roo.useShims;
-    this.useDisplay = config.useDisplay;
-    this.hide();
-};
-
-var supr = Roo.Element.prototype;
+    // private
+    setFirstChild : function(node){
+        this.firstChild = node;
+    },
 
-// shims are shared among layer to keep from having 100 iframes
-var shims = [];
+    //private
+    setLastChild : function(node){
+        this.lastChild = node;
+    },
 
-Roo.extend(Roo.Layer, Roo.Element, {
 
-    getZIndex : function(){
-        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
+    /**
+     * Returns true if this node is the last child of its parent
+     * @return {Boolean}
+     */
+    isLast : function(){
+       return (!this.parentNode ? true : this.parentNode.lastChild == this);
     },
 
-    getShim : function(){
-        if(!this.useShim){
-            return null;
-        }
-        if(this.shim){
-            return this.shim;
-        }
-        var shim = shims.shift();
-        if(!shim){
-            shim = this.createShim();
-            shim.enableDisplayMode('block');
-            shim.dom.style.display = 'none';
-            shim.dom.style.visibility = 'visible';
-        }
-        var pn = this.dom.parentNode;
-        if(shim.dom.parentNode != pn){
-            pn.insertBefore(shim.dom, this.dom);
-        }
-        shim.setStyle('z-index', this.getZIndex()-2);
-        this.shim = shim;
-        return shim;
+    /**
+     * Returns true if this node is the first child of its parent
+     * @return {Boolean}
+     */
+    isFirst : function(){
+       return (!this.parentNode ? true : this.parentNode.firstChild == this);
     },
 
-    hideShim : function(){
-        if(this.shim){
-            this.shim.setDisplayed(false);
-            shims.push(this.shim);
-            delete this.shim;
-        }
+    hasChildNodes : function(){
+        return !this.isLeaf() && this.childNodes.length > 0;
     },
 
-    disableShadow : function(){
-        if(this.shadow){
-            this.shadowDisabled = true;
-            this.shadow.hide();
-            this.lastShadowOffset = this.shadowOffset;
-            this.shadowOffset = 0;
+    /**
+     * Insert node(s) as the last child node of this node.
+     * @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
+     */
+    appendChild : function(node){
+        var multi = false;
+        if(node instanceof Array){
+            multi = node;
+        }else if(arguments.length > 1){
+            multi = arguments;
         }
-    },
-
-    enableShadow : function(show){
-        if(this.shadow){
-            this.shadowDisabled = false;
-            this.shadowOffset = this.lastShadowOffset;
-            delete this.lastShadowOffset;
-            if(show){
-                this.sync(true);
+        
+        // if passed an array or multiple args do them one by one
+        if(multi){
+            for(var i = 0, len = multi.length; i < len; i++) {
+               this.appendChild(multi[i]);
             }
-        }
-    },
-
-    // private
-    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
-    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
-    sync : function(doShow){
-        var sw = this.shadow;
-        if(!this.updating && this.isVisible() && (sw || this.useShim)){
-            var sh = this.getShim();
-
-            var w = this.getWidth(),
-                h = this.getHeight();
-
-            var l = this.getLeft(true),
-                t = this.getTop(true);
-
-            if(sw && !this.shadowDisabled){
-                if(doShow && !sw.isVisible()){
-                    sw.show(this);
-                }else{
-                    sw.realign(l, t, w, h);
-                }
-                if(sh){
-                    if(doShow){
-                       sh.show();
-                    }
-                    // fit the shim behind the shadow, so it is shimmed too
-                    var a = sw.adjusts, s = sh.dom.style;
-                    s.left = (Math.min(l, l+a.l))+"px";
-                    s.top = (Math.min(t, t+a.t))+"px";
-                    s.width = (w+a.w)+"px";
-                    s.height = (h+a.h)+"px";
-                }
-            }else if(sh){
-                if(doShow){
-                   sh.show();
+        }else{
+            if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
+                return false;
+            }
+            var index = this.childNodes.length;
+            var oldParent = node.parentNode;
+            // it's a move, make sure we move it cleanly
+            if(oldParent){
+                if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
+                    return false;
                 }
-                sh.setSize(w, h);
-                sh.setLeftTop(l, t);
+                oldParent.removeChild(node);
             }
             
+            index = this.childNodes.length;
+            if(index == 0){
+                this.setFirstChild(node);
+            }
+            this.childNodes.push(node);
+            node.parentNode = this;
+            var ps = this.childNodes[index-1];
+            if(ps){
+                node.previousSibling = ps;
+                ps.nextSibling = node;
+            }else{
+                node.previousSibling = null;
+            }
+            node.nextSibling = null;
+            this.setLastChild(node);
+            node.setOwnerTree(this.getOwnerTree());
+            this.fireEvent("append", this.ownerTree, this, node, index);
+            if(this.ownerTree) {
+                this.ownerTree.fireEvent("appendnode", this, node, index);
+            }
+            if(oldParent){
+                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
+            }
+            return node;
         }
     },
 
-    // private
-    destroy : function(){
-        this.hideShim();
-        if(this.shadow){
-            this.shadow.hide();
-        }
-        this.removeAllListeners();
-        var pn = this.dom.parentNode;
-        if(pn){
-            pn.removeChild(this.dom);
-        }
-        Roo.Element.uncache(this.id);
-    },
-
-    remove : function(){
-        this.destroy();
-    },
-
-    // private
-    beginUpdate : function(){
-        this.updating = true;
-    },
+    /**
+     * Removes a child node from this node.
+     * @param {Node} node The node to remove
+     * @return {Node} The removed node
+     */
+    removeChild : function(node){
+        var index = this.childNodes.indexOf(node);
+        if(index == -1){
+            return false;
+        }
+        if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
+            return false;
+        }
 
-    // private
-    endUpdate : function(){
-        this.updating = false;
-        this.sync(true);
-    },
+        // remove it from childNodes collection
+        this.childNodes.splice(index, 1);
 
-    // private
-    hideUnders : function(negOffset){
-        if(this.shadow){
-            this.shadow.hide();
+        // update siblings
+        if(node.previousSibling){
+            node.previousSibling.nextSibling = node.nextSibling;
+        }
+        if(node.nextSibling){
+            node.nextSibling.previousSibling = node.previousSibling;
         }
-        this.hideShim();
-    },
-
-    // private
-    constrainXY : function(){
-        if(this.constrain){
-            var vw = Roo.lib.Dom.getViewWidth(),
-                vh = Roo.lib.Dom.getViewHeight();
-            var s = Roo.get(document).getScroll();
 
-            var xy = this.getXY();
-            var x = xy[0], y = xy[1];   
-            var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
-            // only move it if it needs it
-            var moved = false;
-            // first validate right/bottom
-            if((x + w) > vw+s.left){
-                x = vw - w - this.shadowOffset;
-                moved = true;
-            }
-            if((y + h) > vh+s.top){
-                y = vh - h - this.shadowOffset;
-                moved = true;
-            }
-            // then make sure top/left isn't negative
-            if(x < s.left){
-                x = s.left;
-                moved = true;
-            }
-            if(y < s.top){
-                y = s.top;
-                moved = true;
-            }
-            if(moved){
-                if(this.avoidY){
-                    var ay = this.avoidY;
-                    if(y <= ay && (y+h) >= ay){
-                        y = ay-h-5;   
-                    }
-                }
-                xy = [x, y];
-                this.storeXY(xy);
-                supr.setXY.call(this, xy);
-                this.sync();
-            }
+        // update child refs
+        if(this.firstChild == node){
+            this.setFirstChild(node.nextSibling);
+        }
+        if(this.lastChild == node){
+            this.setLastChild(node.previousSibling);
         }
-    },
 
-    isVisible : function(){
-        return this.visible;    
+        node.setOwnerTree(null);
+        // clear any references from the node
+        node.parentNode = null;
+        node.previousSibling = null;
+        node.nextSibling = null;
+        this.fireEvent("remove", this.ownerTree, this, node);
+        return node;
     },
 
-    // private
-    showAction : function(){
-        this.visible = true; // track visibility to prevent getStyle calls
-        if(this.useDisplay === true){
-            this.setDisplayed("");
-        }else if(this.lastXY){
-            supr.setXY.call(this, this.lastXY);
-        }else if(this.lastLT){
-            supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
+    /**
+     * 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
+     */
+    insertBefore : function(node, refNode){
+        if(!refNode){ // like standard Dom, refNode can be null for append
+            return this.appendChild(node);
+        }
+        // nothing to do
+        if(node == refNode){
+            return false;
         }
-    },
 
-    // private
-    hideAction : function(){
-        this.visible = false;
-        if(this.useDisplay === true){
-            this.setDisplayed(false);
-        }else{
-            this.setLeftTop(-10000,-10000);
+        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
+            return false;
         }
-    },
+        var index = this.childNodes.indexOf(refNode);
+        var oldParent = node.parentNode;
+        var refIndex = index;
 
-    // overridden Element method
-    setVisible : function(v, a, d, c, e){
-        if(v){
-            this.showAction();
+        // when moving internally, indexes will change after remove
+        if(oldParent == this && this.childNodes.indexOf(node) < index){
+            refIndex--;
         }
-        if(a && v){
-            var cb = function(){
-                this.sync(true);
-                if(c){
-                    c();
-                }
-            }.createDelegate(this);
-            supr.setVisible.call(this, true, true, d, cb, e);
-        }else{
-            if(!v){
-                this.hideUnders(true);
-            }
-            var cb = c;
-            if(a){
-                cb = function(){
-                    this.hideAction();
-                    if(c){
-                        c();
-                    }
-                }.createDelegate(this);
-            }
-            supr.setVisible.call(this, v, a, d, cb, e);
-            if(v){
-                this.sync(true);
-            }else if(!a){
-                this.hideAction();
+
+        // it's a move, make sure we move it cleanly
+        if(oldParent){
+            if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
+                return false;
             }
+            oldParent.removeChild(node);
         }
+        if(refIndex == 0){
+            this.setFirstChild(node);
+        }
+        this.childNodes.splice(refIndex, 0, node);
+        node.parentNode = this;
+        var ps = this.childNodes[refIndex-1];
+        if(ps){
+            node.previousSibling = ps;
+            ps.nextSibling = node;
+        }else{
+            node.previousSibling = null;
+        }
+        node.nextSibling = refNode;
+        refNode.previousSibling = node;
+        node.setOwnerTree(this.getOwnerTree());
+        this.fireEvent("insert", this.ownerTree, this, node, refNode);
+        if(oldParent){
+            node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
+        }
+        return node;
     },
 
-    storeXY : function(xy){
-        delete this.lastLT;
-        this.lastXY = xy;
-    },
-
-    storeLeftTop : function(left, top){
-        delete this.lastXY;
-        this.lastLT = [left, top];
+    /**
+     * Returns the child node at the specified index.
+     * @param {Number} index
+     * @return {Node}
+     */
+    item : function(index){
+        return this.childNodes[index];
     },
 
-    // private
-    beforeFx : function(){
-        this.beforeAction();
-        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    /**
+     * 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
+     */
+    replaceChild : function(newChild, oldChild){
+        this.insertBefore(newChild, oldChild);
+        this.removeChild(oldChild);
+        return oldChild;
     },
 
-    // private
-    afterFx : function(){
-        Roo.Layer.superclass.afterFx.apply(this, arguments);
-        this.sync(this.isVisible());
+    /**
+     * Returns the index of a child node
+     * @param {Node} node
+     * @return {Number} The index of the node or -1 if it was not found
+     */
+    indexOf : function(child){
+        return this.childNodes.indexOf(child);
     },
 
-    // private
-    beforeAction : function(){
-        if(!this.updating && this.shadow){
-            this.shadow.hide();
+    /**
+     * Returns the tree this node is in.
+     * @return {Tree}
+     */
+    getOwnerTree : function(){
+        // if it doesn't have one, look for one
+        if(!this.ownerTree){
+            var p = this;
+            while(p){
+                if(p.ownerTree){
+                    this.ownerTree = p.ownerTree;
+                    break;
+                }
+                p = p.parentNode;
+            }
         }
+        return this.ownerTree;
     },
 
-    // overridden Element method
-    setLeft : function(left){
-        this.storeLeftTop(left, this.getTop(true));
-        supr.setLeft.apply(this, arguments);
-        this.sync();
-    },
-
-    setTop : function(top){
-        this.storeLeftTop(this.getLeft(true), top);
-        supr.setTop.apply(this, arguments);
-        this.sync();
+    /**
+     * Returns depth of this node (the root node has a depth of 0)
+     * @return {Number}
+     */
+    getDepth : function(){
+        var depth = 0;
+        var p = this;
+        while(p.parentNode){
+            ++depth;
+            p = p.parentNode;
+        }
+        return depth;
     },
 
-    setLeftTop : function(left, top){
-        this.storeLeftTop(left, top);
-        supr.setLeftTop.apply(this, arguments);
-        this.sync();
+    // private
+    setOwnerTree : function(tree){
+        // if it's move, we need to update everyone
+        if(tree != this.ownerTree){
+            if(this.ownerTree){
+                this.ownerTree.unregisterNode(this);
+            }
+            this.ownerTree = tree;
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].setOwnerTree(tree);
+            }
+            if(tree){
+                tree.registerNode(this);
+            }
+        }
     },
 
-    setXY : function(xy, a, d, c, e){
-        this.fixDisplay();
-        this.beforeAction();
-        this.storeXY(xy);
-        var cb = this.createCB(c);
-        supr.setXY.call(this, xy, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Returns the path for this node. The path can be used to expand or select this node programmatically.
+     * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
+     * @return {String} The path
+     */
+    getPath : function(attr){
+        attr = attr || "id";
+        var p = this.parentNode;
+        var b = [this.attributes[attr]];
+        while(p){
+            b.unshift(p.attributes[attr]);
+            p = p.parentNode;
         }
+        var sep = this.getOwnerTree().pathSeparator;
+        return sep + b.join(sep);
     },
 
-    // private
-    createCB : function(c){
-        var el = this;
-        return function(){
-            el.constrainXY();
-            el.sync(true);
-            if(c){
-                c();
+    /**
+     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * 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 of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    bubble : function(fn, scope, args){
+        var p = this;
+        while(p){
+            if(fn.call(scope || p, args || p) === false){
+                break;
             }
-        };
+            p = p.parentNode;
+        }
     },
 
-    // overridden Element method
-    setX : function(x, a, d, c, e){
-        this.setXY([x, this.getY()], a, d, c, e);
+    /**
+     * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * 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 of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    cascade : function(fn, scope, args){
+        if(fn.call(scope || this, args || this) !== false){
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].cascade(fn, scope, args);
+            }
+        }
     },
 
-    // overridden Element method
-    setY : function(y, a, d, c, e){
-        this.setXY([this.getX(), y], a, d, c, e);
+    /**
+     * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * 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 of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    eachChild : function(fn, scope, args){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(fn.call(scope || this, args || cs[i]) === false){
+                   break;
+               }
+        }
     },
 
-    // overridden Element method
-    setSize : function(w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setSize.call(this, w, h, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * 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
+     * @return {Node} The found child or null if none was found
+     */
+    findChild : function(attribute, value){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(cs[i].attributes[attribute] == value){
+                   return cs[i];
+               }
         }
+        return null;
     },
 
-    // overridden Element method
-    setWidth : function(w, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setWidth.call(this, w, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Finds the first child by a custom function. The child matches if the function passed
+     * returns true.
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     * @return {Node} The found child or null if none was found
+     */
+    findChildBy : function(fn, scope){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(fn.call(scope||cs[i], cs[i]) === true){
+                   return cs[i];
+               }
         }
+        return null;
     },
 
-    // overridden Element method
-    setHeight : function(h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setHeight.call(this, h, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Sorts this nodes children using the supplied sort function
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     */
+    sort : function(fn, scope){
+        var cs = this.childNodes;
+        var len = cs.length;
+        if(len > 0){
+            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
+            cs.sort(sortFn);
+            for(var i = 0; i < len; i++){
+                var n = cs[i];
+                n.previousSibling = cs[i-1];
+                n.nextSibling = cs[i+1];
+                if(i == 0){
+                    this.setFirstChild(n);
+                }
+                if(i == len-1){
+                    this.setLastChild(n);
+                }
+            }
         }
     },
 
-    // overridden Element method
-    setBounds : function(x, y, w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        if(!a){
-            this.storeXY([x, y]);
-            supr.setXY.call(this, [x, y]);
-            supr.setSize.call(this, w, h, a, d, cb, e);
-            cb();
-        }else{
-            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
-        }
-        return this;
+    /**
+     * Returns true if this node is an ancestor (at any point) of the passed node.
+     * @param {Node} node
+     * @return {Boolean}
+     */
+    contains : function(node){
+        return node.isAncestor(this);
     },
-    
+
     /**
-     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
-     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
-     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
-     * @param {Number} zindex The new z-index to set
-     * @return {this} The Layer
+     * Returns true if the passed node is an ancestor (at any point) of this node.
+     * @param {Node} node
+     * @return {Boolean}
      */
-    setZIndex : function(zindex){
-        this.zindex = zindex;
-        this.setStyle("z-index", zindex + 2);
-        if(this.shadow){
-            this.shadow.setZIndex(zindex + 1);
-        }
-        if(this.shim){
-            this.shim.setStyle("z-index", zindex);
+    isAncestor : function(node){
+        var p = this.parentNode;
+        while(p){
+            if(p == node){
+                return true;
+            }
+            p = p.parentNode;
         }
+        return false;
+    },
+
+    toString : function(){
+        return "[Node"+(this.id?" "+this.id:"")+"]";
     }
-});
-})();/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -30444,7 +30444,7 @@ Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
  * A simple class that renders text directly into a toolbar.
  * @constructor
  * Creates a new TextItem
- * @param {String} text
+ * @cfg {string} text 
  */
 Roo.Toolbar.TextItem = function(cfg){
     var  text = cfg || "";
@@ -38846,6 +38846,14 @@ Roo.extend(Roo.form.TextItem, Roo.BoxComponent,  {
             }
             this.el = ct.createChild(cfg, position);
         }
+    },
+    /*
+     * setHTML
+     * @param {String} html update the Contents of the element.
+     */
+    setHTML : function(html)
+    {
+        this.fieldEl.dom.innerHTML = html;
     }
     
 });/*