roojs-debug.js
authorAlan Knowles <alan@akbkhome.com>
Fri, 16 Jul 2010 05:30:41 +0000 (13:30 +0800)
committerAlan Knowles <alan@akbkhome.com>
Fri, 16 Jul 2010 05:30:41 +0000 (13:30 +0800)
roojs-debug.js

index 74d1d5a..3873aa2 100644 (file)
@@ -556,3 +556,4842 @@ Roo.factory(conf, Roo.data);
 
 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
+/*
+ * 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() {    
+    // wrappedn so fnCleanup is not in global scope...
+    if(Roo.isIE) {
+        function fnCleanUp() {
+            var p = Function.prototype;
+            delete p.createSequence;
+            delete p.defer;
+            delete p.createDelegate;
+            delete p.createCallback;
+            delete p.createInterceptor;
+
+            window.detachEvent("onunload", fnCleanUp);
+        }
+        window.attachEvent("onunload", fnCleanUp);
+    }
+})();
+
+
+/**
+ * @class Function
+ * These functions are available on every Function object (any JavaScript function).
+ */
+Roo.apply(Function.prototype, {
+     /**
+     * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
+     * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
+     * Will create a function that is bound to those 2 args.
+     * @return {Function} The new function
+    */
+    createCallback : function(/*args...*/){
+        // make args available, in function below
+        var args = arguments;
+        var method = this;
+        return function() {
+            return method.apply(window, args);
+        };
+    },
+
+    /**
+     * Creates a delegate (callback) that sets the scope to obj.
+     * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
+     * Will create a function that is automatically scoped to this.
+     * @param {Object} obj (optional) The object for which the scope is set
+     * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
+     * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
+     *                                             if a number the args are inserted at the specified position
+     * @return {Function} The new function
+     */
+    createDelegate : function(obj, args, appendArgs){
+        var method = this;
+        return function() {
+            var callArgs = args || arguments;
+            if(appendArgs === true){
+                callArgs = Array.prototype.slice.call(arguments, 0);
+                callArgs = callArgs.concat(args);
+            }else if(typeof appendArgs == "number"){
+                callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
+                var applyArgs = [appendArgs, 0].concat(args); // create method call params
+                Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
+            }
+            return method.apply(obj || window, callArgs);
+        };
+    },
+
+    /**
+     * Calls this function after the number of millseconds specified.
+     * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
+     * @param {Object} obj (optional) The object for which the scope is set
+     * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
+     * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
+     *                                             if a number the args are inserted at the specified position
+     * @return {Number} The timeout id that can be used with clearTimeout
+     */
+    defer : function(millis, obj, args, appendArgs){
+        var fn = this.createDelegate(obj, args, appendArgs);
+        if(millis){
+            return setTimeout(fn, millis);
+        }
+        fn();
+        return 0;
+    },
+    /**
+     * Create a combined function call sequence of the original function + the passed function.
+     * The resulting function returns the results of the original function.
+     * The passed fcn is called with the parameters of the original function
+     * @param {Function} fcn The function to sequence
+     * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
+     * @return {Function} The new function
+     */
+    createSequence : function(fcn, scope){
+        if(typeof fcn != "function"){
+            return this;
+        }
+        var method = this;
+        return function() {
+            var retval = method.apply(this || window, arguments);
+            fcn.apply(scope || this || window, arguments);
+            return retval;
+        };
+    },
+
+    /**
+     * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
+     * The resulting function returns the results of the original function.
+     * The passed fcn is called with the parameters of the original function.
+     * @addon
+     * @param {Function} fcn The function to call before the original
+     * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
+     * @return {Function} The new function
+     */
+    createInterceptor : function(fcn, scope){
+        if(typeof fcn != "function"){
+            return this;
+        }
+        var method = this;
+        return function() {
+            fcn.target = this;
+            fcn.method = method;
+            if(fcn.apply(scope || this || window, arguments) === false){
+                return;
+            }
+            return method.apply(this || window, arguments);
+        };
+    }
+});
+/*
+ * 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.applyIf(String, {
+    
+    /** @scope String */
+    
+    /**
+     * Escapes the passed string for ' and \
+     * @param {String} string The string to escape
+     * @return {String} The escaped string
+     * @static
+     */
+    escape : function(string) {
+        return string.replace(/('|\\)/g, "\\$1");
+    },
+
+    /**
+     * Pads the left side of a string with a specified character.  This is especially useful
+     * for normalizing number and date strings.  Example usage:
+     * <pre><code>
+var s = String.leftPad('123', 5, '0');
+// s now contains the string: '00123'
+</code></pre>
+     * @param {String} string The original string
+     * @param {Number} size The total length of the output string
+     * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
+     * @return {String} The padded string
+     * @static
+     */
+    leftPad : function (val, size, ch) {
+        var result = new String(val);
+        if(ch === null || ch === undefined || ch === '') {
+            ch = " ";
+        }
+        while (result.length < size) {
+            result = ch + result;
+        }
+        return result;
+    },
+
+    /**
+     * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
+     * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
+     * <pre><code>
+var cls = 'my-class', text = 'Some text';
+var s = String.format('<div class="{0}">{1}</div>', cls, text);
+// s now contains the string: '<div class="my-class">Some text</div>'
+</code></pre>
+     * @param {String} string The tokenized string to be formatted
+     * @param {String} value1 The value to replace token {0}
+     * @param {String} value2 Etc...
+     * @return {String} The formatted string
+     * @static
+     */
+    format : function(format){
+        var args = Array.prototype.slice.call(arguments, 1);
+        return format.replace(/\{(\d+)\}/g, function(m, i){
+            return Roo.util.Format.htmlEncode(args[i]);
+        });
+    }
+});
+
+/**
+ * Utility function that allows you to easily switch a string between two alternating values.  The passed value
+ * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
+ * they are already different, the first value passed in is returned.  Note that this method returns the new value
+ * but does not change the current string.
+ * <pre><code>
+// alternate sort directions
+sort = sort.toggle('ASC', 'DESC');
+
+// instead of conditional logic:
+sort = (sort == 'ASC' ? 'DESC' : 'ASC');
+</code></pre>
+ * @param {String} value The value to compare to the current string
+ * @param {String} other The new value to use if the string already equals the first value passed in
+ * @return {String} The new value
+ */
+String.prototype.toggle = function(value, other){
+    return this == value ? other : value;
+};/*
+ * 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 Number
+ */
+Roo.applyIf(Number.prototype, {
+    /**
+     * Checks whether or not the current number is within a desired range.  If the number is already within the
+     * range it is returned, otherwise the min or max value is returned depending on which side of the range is
+     * exceeded.  Note that this method returns the constrained value but does not change the current number.
+     * @param {Number} min The minimum number in the range
+     * @param {Number} max The maximum number in the range
+     * @return {Number} The constrained value if outside the range, otherwise the current value
+     */
+    constrain : function(min, max){
+        return Math.min(Math.max(this, min), max);
+    }
+});/*
+ * 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 Array
+ */
+Roo.applyIf(Array.prototype, {
+    /**
+     * Checks whether or not the specified object exists in the array.
+     * @param {Object} o The object to check for
+     * @return {Number} The index of o in the array (or -1 if it is not found)
+     */
+    indexOf : function(o){
+       for (var i = 0, len = this.length; i < len; i++){
+             if(this[i] == o) return i;
+       }
+          return -1;
+    },
+
+    /**
+     * Removes the specified object from the array.  If the object is not found nothing happens.
+     * @param {Object} o The object to remove
+     */
+    remove : function(o){
+       var index = this.indexOf(o);
+       if(index != -1){
+           this.splice(index, 1);
+       }
+    }
+});/*
+ * 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 Date
+ *
+ * The date parsing and format syntax is a subset of
+ * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
+ * supported will provide results equivalent to their PHP versions.
+ *
+ * Following is the list of all currently supported formats:
+ *<pre>
+Sample date:
+'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
+
+Format  Output      Description
+------  ----------  --------------------------------------------------------------
+  d      10         Day of the month, 2 digits with leading zeros
+  D      Wed        A textual representation of a day, three letters
+  j      10         Day of the month without leading zeros
+  l      Wednesday  A full textual representation of the day of the week
+  S      th         English ordinal day of month suffix, 2 chars (use with j)
+  w      3          Numeric representation of the day of the week
+  z      9          The julian date, or day of the year (0-365)
+  W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
+  F      January    A full textual representation of the month
+  m      01         Numeric representation of a month, with leading zeros
+  M      Jan        Month name abbreviation, three letters
+  n      1          Numeric representation of a month, without leading zeros
+  t      31         Number of days in the given month
+  L      0          Whether it's a leap year (1 if it is a leap year, else 0)
+  Y      2007       A full numeric representation of a year, 4 digits
+  y      07         A two digit representation of a year
+  a      pm         Lowercase Ante meridiem and Post meridiem
+  A      PM         Uppercase Ante meridiem and Post meridiem
+  g      3          12-hour format of an hour without leading zeros
+  G      15         24-hour format of an hour without leading zeros
+  h      03         12-hour format of an hour with leading zeros
+  H      15         24-hour format of an hour with leading zeros
+  i      05         Minutes with leading zeros
+  s      01         Seconds, with leading zeros
+  O      -0600      Difference to Greenwich time (GMT) in hours
+  T      CST        Timezone setting of the machine running the code
+  Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
+</pre>
+ *
+ * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
+ * <pre><code>
+var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
+document.write(dt.format('Y-m-d'));                         //2007-01-10
+document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
+document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
+ </code></pre>
+ *
+ * Here are some standard date/time patterns that you might find helpful.  They
+ * are not part of the source of Date.js, but to use them you can simply copy this
+ * block of code into any script that is included after Date.js and they will also become
+ * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
+ * <pre><code>
+Date.patterns = {
+    ISO8601Long:"Y-m-d H:i:s",
+    ISO8601Short:"Y-m-d",
+    ShortDate: "n/j/Y",
+    LongDate: "l, F d, Y",
+    FullDateTime: "l, F d, Y g:i:s A",
+    MonthDay: "F d",
+    ShortTime: "g:i A",
+    LongTime: "g:i:s A",
+    SortableDateTime: "Y-m-d\\TH:i:s",
+    UniversalSortableDateTime: "Y-m-d H:i:sO",
+    YearMonth: "F, Y"
+};
+</code></pre>
+ *
+ * Example usage:
+ * <pre><code>
+var dt = new Date();
+document.write(dt.format(Date.patterns.ShortDate));
+ </code></pre>
+ */
+
+/*
+ * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
+ * They generate precompiled functions from date formats instead of parsing and
+ * processing the pattern every time you format a date.  These functions are available
+ * on every Date object (any javascript function).
+ *
+ * The original article and download are here:
+ * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
+ *
+ */
+ // was in core
+/**
+ Returns the number of milliseconds between this date and date
+ @param {Date} date (optional) Defaults to now
+ @return {Number} The diff in milliseconds
+ @member Date getElapsed
+ */
+Date.prototype.getElapsed = function(date) {
+       return Math.abs((date || new Date()).getTime()-this.getTime());
+};
+// was in date file..
+
+
+// private
+Date.parseFunctions = {count:0};
+// private
+Date.parseRegexes = [];
+// private
+Date.formatFunctions = {count:0};
+
+// private
+Date.prototype.dateFormat = function(format) {
+    if (Date.formatFunctions[format] == null) {
+        Date.createNewFormat(format);
+    }
+    var func = Date.formatFunctions[format];
+    return this[func]();
+};
+
+
+/**
+ * Formats a date given the supplied format string
+ * @param {String} format The format string
+ * @return {String} The formatted date
+ * @method
+ */
+Date.prototype.format = Date.prototype.dateFormat;
+
+// private
+Date.createNewFormat = function(format) {
+    var funcName = "format" + Date.formatFunctions.count++;
+    Date.formatFunctions[format] = funcName;
+    var code = "Date.prototype." + funcName + " = function(){return ";
+    var special = false;
+    var ch = '';
+    for (var i = 0; i < format.length; ++i) {
+        ch = format.charAt(i);
+        if (!special && ch == "\\") {
+            special = true;
+        }
+        else if (special) {
+            special = false;
+            code += "'" + String.escape(ch) + "' + ";
+        }
+        else {
+            code += Date.getFormatCode(ch);
+        }
+    }
+    /** eval:var:zzzzzzzzzzzzz */
+    eval(code.substring(0, code.length - 3) + ";}");
+};
+
+// private
+Date.getFormatCode = function(character) {
+    switch (character) {
+    case "d":
+        return "String.leftPad(this.getDate(), 2, '0') + ";
+    case "D":
+        return "Date.dayNames[this.getDay()].substring(0, 3) + ";
+    case "j":
+        return "this.getDate() + ";
+    case "l":
+        return "Date.dayNames[this.getDay()] + ";
+    case "S":
+        return "this.getSuffix() + ";
+    case "w":
+        return "this.getDay() + ";
+    case "z":
+        return "this.getDayOfYear() + ";
+    case "W":
+        return "this.getWeekOfYear() + ";
+    case "F":
+        return "Date.monthNames[this.getMonth()] + ";
+    case "m":
+        return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
+    case "M":
+        return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
+    case "n":
+        return "(this.getMonth() + 1) + ";
+    case "t":
+        return "this.getDaysInMonth() + ";
+    case "L":
+        return "(this.isLeapYear() ? 1 : 0) + ";
+    case "Y":
+        return "this.getFullYear() + ";
+    case "y":
+        return "('' + this.getFullYear()).substring(2, 4) + ";
+    case "a":
+        return "(this.getHours() < 12 ? 'am' : 'pm') + ";
+    case "A":
+        return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
+    case "g":
+        return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
+    case "G":
+        return "this.getHours() + ";
+    case "h":
+        return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
+    case "H":
+        return "String.leftPad(this.getHours(), 2, '0') + ";
+    case "i":
+        return "String.leftPad(this.getMinutes(), 2, '0') + ";
+    case "s":
+        return "String.leftPad(this.getSeconds(), 2, '0') + ";
+    case "O":
+        return "this.getGMTOffset() + ";
+    case "T":
+        return "this.getTimezone() + ";
+    case "Z":
+        return "(this.getTimezoneOffset() * -60) + ";
+    default:
+        return "'" + String.escape(character) + "' + ";
+    }
+};
+
+/**
+ * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
+ * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
+ * the date format that is not specified will default to the current date value for that part.  Time parts can also
+ * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
+ * string or the parse operation will fail.
+ * Example Usage:
+<pre><code>
+//dt = Fri May 25 2007 (current date)
+var dt = new Date();
+
+//dt = Thu May 25 2006 (today's month/day in 2006)
+dt = Date.parseDate("2006", "Y");
+
+//dt = Sun Jan 15 2006 (all date parts specified)
+dt = Date.parseDate("2006-1-15", "Y-m-d");
+
+//dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
+dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
+</code></pre>
+ * @param {String} input The unparsed date as a string
+ * @param {String} format The format the date is in
+ * @return {Date} The parsed date
+ * @static
+ */
+Date.parseDate = function(input, format) {
+    if (Date.parseFunctions[format] == null) {
+        Date.createParser(format);
+    }
+    var func = Date.parseFunctions[format];
+    return Date[func](input);
+};
+
+// private
+Date.createParser = function(format) {
+    var funcName = "parse" + Date.parseFunctions.count++;
+    var regexNum = Date.parseRegexes.length;
+    var currentGroup = 1;
+    Date.parseFunctions[format] = funcName;
+
+    var code = "Date." + funcName + " = function(input){\n"
+        + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
+        + "var d = new Date();\n"
+        + "y = d.getFullYear();\n"
+        + "m = d.getMonth();\n"
+        + "d = d.getDate();\n"
+        + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
+        + "if (results && results.length > 0) {";
+    var regex = "";
+
+    var special = false;
+    var ch = '';
+    for (var i = 0; i < format.length; ++i) {
+        ch = format.charAt(i);
+        if (!special && ch == "\\") {
+            special = true;
+        }
+        else if (special) {
+            special = false;
+            regex += String.escape(ch);
+        }
+        else {
+            var obj = Date.formatCodeToRegex(ch, currentGroup);
+            currentGroup += obj.g;
+            regex += obj.s;
+            if (obj.g && obj.c) {
+                code += obj.c;
+            }
+        }
+    }
+
+    code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
+        + "{v = new Date(y, m, d, h, i, s);}\n"
+        + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
+        + "{v = new Date(y, m, d, h, i);}\n"
+        + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
+        + "{v = new Date(y, m, d, h);}\n"
+        + "else if (y >= 0 && m >= 0 && d > 0)\n"
+        + "{v = new Date(y, m, d);}\n"
+        + "else if (y >= 0 && m >= 0)\n"
+        + "{v = new Date(y, m);}\n"
+        + "else if (y >= 0)\n"
+        + "{v = new Date(y);}\n"
+        + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
+        + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
+        + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
+        + ";}";
+
+    Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
+     /** eval:var:zzzzzzzzzzzzz */
+    eval(code);
+};
+
+// private
+Date.formatCodeToRegex = function(character, currentGroup) {
+    switch (character) {
+    case "D":
+        return {g:0,
+        c:null,
+        s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
+    case "j":
+        return {g:1,
+            c:"d = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{1,2})"}; // day of month without leading zeroes
+    case "d":
+        return {g:1,
+            c:"d = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"}; // day of month with leading zeroes
+    case "l":
+        return {g:0,
+            c:null,
+            s:"(?:" + Date.dayNames.join("|") + ")"};
+    case "S":
+        return {g:0,
+            c:null,
+            s:"(?:st|nd|rd|th)"};
+    case "w":
+        return {g:0,
+            c:null,
+            s:"\\d"};
+    case "z":
+        return {g:0,
+            c:null,
+            s:"(?:\\d{1,3})"};
+    case "W":
+        return {g:0,
+            c:null,
+            s:"(?:\\d{2})"};
+    case "F":
+        return {g:1,
+            c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
+            s:"(" + Date.monthNames.join("|") + ")"};
+    case "M":
+        return {g:1,
+            c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
+            s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
+    case "n":
+        return {g:1,
+            c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
+            s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
+    case "m":
+        return {g:1,
+            c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
+            s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
+    case "t":
+        return {g:0,
+            c:null,
+            s:"\\d{1,2}"};
+    case "L":
+        return {g:0,
+            c:null,
+            s:"(?:1|0)"};
+    case "Y":
+        return {g:1,
+            c:"y = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{4})"};
+    case "y":
+        return {g:1,
+            c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
+                + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
+            s:"(\\d{1,2})"};
+    case "a":
+        return {g:1,
+            c:"if (results[" + currentGroup + "] == 'am') {\n"
+                + "if (h == 12) { h = 0; }\n"
+                + "} else { if (h < 12) { h += 12; }}",
+            s:"(am|pm)"};
+    case "A":
+        return {g:1,
+            c:"if (results[" + currentGroup + "] == 'AM') {\n"
+                + "if (h == 12) { h = 0; }\n"
+                + "} else { if (h < 12) { h += 12; }}",
+            s:"(AM|PM)"};
+    case "g":
+    case "G":
+        return {g:1,
+            c:"h = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
+    case "h":
+    case "H":
+        return {g:1,
+            c:"h = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
+    case "i":
+        return {g:1,
+            c:"i = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"};
+    case "s":
+        return {g:1,
+            c:"s = parseInt(results[" + currentGroup + "], 10);\n",
+            s:"(\\d{2})"};
+    case "O":
+        return {g:1,
+            c:[
+                "o = results[", currentGroup, "];\n",
+                "var sn = o.substring(0,1);\n", // get + / - sign
+                "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
+                "var mn = o.substring(3,5) % 60;\n", // get minutes
+                "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
+                "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
+            ].join(""),
+            s:"([+\-]\\d{4})"};
+    case "T":
+        return {g:0,
+            c:null,
+            s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
+    case "Z":
+        return {g:1,
+            c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
+                  + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
+            s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
+    default:
+        return {g:0,
+            c:null,
+            s:String.escape(character)};
+    }
+};
+
+/**
+ * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
+ * @return {String} The abbreviated timezone name (e.g. 'CST')
+ */
+Date.prototype.getTimezone = function() {
+    return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
+};
+
+/**
+ * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
+ * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
+ */
+Date.prototype.getGMTOffset = function() {
+    return (this.getTimezoneOffset() > 0 ? "-" : "+")
+        + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
+        + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
+};
+
+/**
+ * Get the numeric day number of the year, adjusted for leap year.
+ * @return {Number} 0 through 364 (365 in leap years)
+ */
+Date.prototype.getDayOfYear = function() {
+    var num = 0;
+    Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
+    for (var i = 0; i < this.getMonth(); ++i) {
+        num += Date.daysInMonth[i];
+    }
+    return num + this.getDate() - 1;
+};
+
+/**
+ * Get the string representation of the numeric week number of the year
+ * (equivalent to the format specifier 'W').
+ * @return {String} '00' through '52'
+ */
+Date.prototype.getWeekOfYear = function() {
+    // Skip to Thursday of this week
+    var now = this.getDayOfYear() + (4 - this.getDay());
+    // Find the first Thursday of the year
+    var jan1 = new Date(this.getFullYear(), 0, 1);
+    var then = (7 - jan1.getDay() + 4);
+    return String.leftPad(((now - then) / 7) + 1, 2, "0");
+};
+
+/**
+ * Whether or not the current date is in a leap year.
+ * @return {Boolean} True if the current date is in a leap year, else false
+ */
+Date.prototype.isLeapYear = function() {
+    var year = this.getFullYear();
+    return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
+};
+
+/**
+ * Get the first day of the current month, adjusted for leap year.  The returned value
+ * is the numeric day index within the week (0-6) which can be used in conjunction with
+ * the {@link #monthNames} array to retrieve the textual day name.
+ * Example:
+ *<pre><code>
+var dt = new Date('1/10/2007');
+document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
+</code></pre>
+ * @return {Number} The day number (0-6)
+ */
+Date.prototype.getFirstDayOfMonth = function() {
+    var day = (this.getDay() - (this.getDate() - 1)) % 7;
+    return (day < 0) ? (day + 7) : day;
+};
+
+/**
+ * Get the last day of the current month, adjusted for leap year.  The returned value
+ * is the numeric day index within the week (0-6) which can be used in conjunction with
+ * the {@link #monthNames} array to retrieve the textual day name.
+ * Example:
+ *<pre><code>
+var dt = new Date('1/10/2007');
+document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
+</code></pre>
+ * @return {Number} The day number (0-6)
+ */
+Date.prototype.getLastDayOfMonth = function() {
+    var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
+    return (day < 0) ? (day + 7) : day;
+};
+
+
+/**
+ * Get the first date of this date's month
+ * @return {Date}
+ */
+Date.prototype.getFirstDateOfMonth = function() {
+    return new Date(this.getFullYear(), this.getMonth(), 1);
+};
+
+/**
+ * Get the last date of this date's month
+ * @return {Date}
+ */
+Date.prototype.getLastDateOfMonth = function() {
+    return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
+};
+/**
+ * Get the number of days in the current month, adjusted for leap year.
+ * @return {Number} The number of days in the month
+ */
+Date.prototype.getDaysInMonth = function() {
+    Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
+    return Date.daysInMonth[this.getMonth()];
+};
+
+/**
+ * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
+ * @return {String} 'st, 'nd', 'rd' or 'th'
+ */
+Date.prototype.getSuffix = function() {
+    switch (this.getDate()) {
+        case 1:
+        case 21:
+        case 31:
+            return "st";
+        case 2:
+        case 22:
+            return "nd";
+        case 3:
+        case 23:
+            return "rd";
+        default:
+            return "th";
+    }
+};
+
+// private
+Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
+
+/**
+ * An array of textual month names.
+ * Override these values for international dates, for example...
+ * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
+ * @type Array
+ * @static
+ */
+Date.monthNames =
+   ["January",
+    "February",
+    "March",
+    "April",
+    "May",
+    "June",
+    "July",
+    "August",
+    "September",
+    "October",
+    "November",
+    "December"];
+
+/**
+ * An array of textual day names.
+ * Override these values for international dates, for example...
+ * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
+ * @type Array
+ * @static
+ */
+Date.dayNames =
+   ["Sunday",
+    "Monday",
+    "Tuesday",
+    "Wednesday",
+    "Thursday",
+    "Friday",
+    "Saturday"];
+
+// private
+Date.y2kYear = 50;
+// private
+Date.monthNumbers = {
+    Jan:0,
+    Feb:1,
+    Mar:2,
+    Apr:3,
+    May:4,
+    Jun:5,
+    Jul:6,
+    Aug:7,
+    Sep:8,
+    Oct:9,
+    Nov:10,
+    Dec:11};
+
+/**
+ * Creates and returns a new Date instance with the exact same date value as the called instance.
+ * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
+ * variable will also be changed.  When the intention is to create a new variable that will not
+ * modify the original instance, you should create a clone.
+ *
+ * Example of correctly cloning a date:
+ * <pre><code>
+//wrong way:
+var orig = new Date('10/1/2006');
+var copy = orig;
+copy.setDate(5);
+document.write(orig);  //returns 'Thu Oct 05 2006'!
+
+//correct way:
+var orig = new Date('10/1/2006');
+var copy = orig.clone();
+copy.setDate(5);
+document.write(orig);  //returns 'Thu Oct 01 2006'
+</code></pre>
+ * @return {Date} The new Date instance
+ */
+Date.prototype.clone = function() {
+       return new Date(this.getTime());
+};
+
+/**
+ * Clears any time information from this date
+ @param {Boolean} clone true to create a clone of this date, clear the time and return it
+ @return {Date} this or the clone
+ */
+Date.prototype.clearTime = function(clone){
+    if(clone){
+        return this.clone().clearTime();
+    }
+    this.setHours(0);
+    this.setMinutes(0);
+    this.setSeconds(0);
+    this.setMilliseconds(0);
+    return this;
+};
+
+// private
+// safari setMonth is broken
+if(Roo.isSafari){
+    Date.brokenSetMonth = Date.prototype.setMonth;
+       Date.prototype.setMonth = function(num){
+               if(num <= -1){
+                       var n = Math.ceil(-num);
+                       var back_year = Math.ceil(n/12);
+                       var month = (n % 12) ? 12 - n % 12 : 0 ;
+                       this.setFullYear(this.getFullYear() - back_year);
+                       return Date.brokenSetMonth.call(this, month);
+               } else {
+                       return Date.brokenSetMonth.apply(this, arguments);
+               }
+       };
+}
+
+/** Date interval constant 
+* @static 
+* @type String */
+Date.MILLI = "ms";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.SECOND = "s";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.MINUTE = "mi";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.HOUR = "h";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.DAY = "d";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.MONTH = "mo";
+/** Date interval constant 
+* @static 
+* @type String */
+Date.YEAR = "y";
+
+/**
+ * Provides a convenient method of performing basic date arithmetic.  This method
+ * does not modify the Date instance being called - it creates and returns
+ * a new Date instance containing the resulting date value.
+ *
+ * Examples:
+ * <pre><code>
+//Basic usage:
+var dt = new Date('10/29/2006').add(Date.DAY, 5);
+document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
+
+//Negative values will subtract correctly:
+var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
+document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
+
+//You can even chain several calls together in one line!
+var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
+document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
+ </code></pre>
+ *
+ * @param {String} interval   A valid date interval enum value
+ * @param {Number} value      The amount to add to the current date
+ * @return {Date} The new Date instance
+ */
+Date.prototype.add = function(interval, value){
+  var d = this.clone();
+  if (!interval || value === 0) return d;
+  switch(interval.toLowerCase()){
+    case Date.MILLI:
+      d.setMilliseconds(this.getMilliseconds() + value);
+      break;
+    case Date.SECOND:
+      d.setSeconds(this.getSeconds() + value);
+      break;
+    case Date.MINUTE:
+      d.setMinutes(this.getMinutes() + value);
+      break;
+    case Date.HOUR:
+      d.setHours(this.getHours() + value);
+      break;
+    case Date.DAY:
+      d.setDate(this.getDate() + value);
+      break;
+    case Date.MONTH:
+      var day = this.getDate();
+      if(day > 28){
+          day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
+      }
+      d.setDate(day);
+      d.setMonth(this.getMonth() + value);
+      break;
+    case Date.YEAR:
+      d.setFullYear(this.getFullYear() + value);
+      break;
+  }
+  return d;
+};/*
+ * 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.lib.Dom = {
+    getViewWidth : function(full) {
+        return full ? this.getDocumentWidth() : this.getViewportWidth();
+    },
+
+    getViewHeight : function(full) {
+        return full ? this.getDocumentHeight() : this.getViewportHeight();
+    },
+
+    getDocumentHeight: function() {
+        var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
+        return Math.max(scrollHeight, this.getViewportHeight());
+    },
+
+    getDocumentWidth: function() {
+        var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
+        return Math.max(scrollWidth, this.getViewportWidth());
+    },
+
+    getViewportHeight: function() {
+        var height = self.innerHeight;
+        var mode = document.compatMode;
+
+        if ((mode || Roo.isIE) && !Roo.isOpera) {
+            height = (mode == "CSS1Compat") ?
+                     document.documentElement.clientHeight :
+                     document.body.clientHeight;
+        }
+
+        return height;
+    },
+
+    getViewportWidth: function() {
+        var width = self.innerWidth;
+        var mode = document.compatMode;
+
+        if (mode || Roo.isIE) {
+            width = (mode == "CSS1Compat") ?
+                    document.documentElement.clientWidth :
+                    document.body.clientWidth;
+        }
+        return width;
+    },
+
+    isAncestor : function(p, c) {
+        p = Roo.getDom(p);
+        c = Roo.getDom(c);
+        if (!p || !c) {
+            return false;
+        }
+
+        if (p.contains && !Roo.isSafari) {
+            return p.contains(c);
+        } else if (p.compareDocumentPosition) {
+            return !!(p.compareDocumentPosition(c) & 16);
+        } else {
+            var parent = c.parentNode;
+            while (parent) {
+                if (parent == p) {
+                    return true;
+                }
+                else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
+                    return false;
+                }
+                parent = parent.parentNode;
+            }
+            return false;
+        }
+    },
+
+    getRegion : function(el) {
+        return Roo.lib.Region.getRegion(el);
+    },
+
+    getY : function(el) {
+        return this.getXY(el)[1];
+    },
+
+    getX : function(el) {
+        return this.getXY(el)[0];
+    },
+
+    getXY : function(el) {
+        var p, pe, b, scroll, bd = document.body;
+        el = Roo.getDom(el);
+        var fly = Roo.lib.AnimBase.fly;
+        if (el.getBoundingClientRect) {
+            b = el.getBoundingClientRect();
+            scroll = fly(document).getScroll();
+            return [b.left + scroll.left, b.top + scroll.top];
+        }
+        var x = 0, y = 0;
+
+        p = el;
+
+        var hasAbsolute = fly(el).getStyle("position") == "absolute";
+
+        while (p) {
+
+            x += p.offsetLeft;
+            y += p.offsetTop;
+
+            if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
+                hasAbsolute = true;
+            }
+
+            if (Roo.isGecko) {
+                pe = fly(p);
+
+                var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
+                var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
+
+
+                x += bl;
+                y += bt;
+
+
+                if (p != el && pe.getStyle('overflow') != 'visible') {
+                    x += bl;
+                    y += bt;
+                }
+            }
+            p = p.offsetParent;
+        }
+
+        if (Roo.isSafari && hasAbsolute) {
+            x -= bd.offsetLeft;
+            y -= bd.offsetTop;
+        }
+
+        if (Roo.isGecko && !hasAbsolute) {
+            var dbd = fly(bd);
+            x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
+            y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
+        }
+
+        p = el.parentNode;
+        while (p && p != bd) {
+            if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
+                x -= p.scrollLeft;
+                y -= p.scrollTop;
+            }
+            p = p.parentNode;
+        }
+        return [x, y];
+    },
+  
+
+
+    setXY : function(el, xy) {
+        el = Roo.fly(el, '_setXY');
+        el.position();
+        var pts = el.translatePoints(xy);
+        if (xy[0] !== false) {
+            el.dom.style.left = pts.left + "px";
+        }
+        if (xy[1] !== false) {
+            el.dom.style.top = pts.top + "px";
+        }
+    },
+
+    setX : function(el, x) {
+        this.setXY(el, [x, false]);
+    },
+
+    setY : function(el, y) {
+        this.setXY(el, [false, y]);
+    }
+};
+/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+
+Roo.lib.Event = function() {
+    var loadComplete = false;
+    var listeners = [];
+    var unloadListeners = [];
+    var retryCount = 0;
+    var onAvailStack = [];
+    var counter = 0;
+    var lastError = null;
+
+    return {
+        POLL_RETRYS: 200,
+        POLL_INTERVAL: 20,
+        EL: 0,
+        TYPE: 1,
+        FN: 2,
+        WFN: 3,
+        OBJ: 3,
+        ADJ_SCOPE: 4,
+        _interval: null,
+
+        startInterval: function() {
+            if (!this._interval) {
+                var self = this;
+                var callback = function() {
+                    self._tryPreloadAttach();
+                };
+                this._interval = setInterval(callback, this.POLL_INTERVAL);
+
+            }
+        },
+
+        onAvailable: function(p_id, p_fn, p_obj, p_override) {
+            onAvailStack.push({ id:         p_id,
+                fn:         p_fn,
+                obj:        p_obj,
+                override:   p_override,
+                checkReady: false    });
+
+            retryCount = this.POLL_RETRYS;
+            this.startInterval();
+        },
+
+
+        addListener: function(el, eventName, fn) {
+            el = Roo.getDom(el);
+            if (!el || !fn) {
+                return false;
+            }
+
+            if ("unload" == eventName) {
+                unloadListeners[unloadListeners.length] =
+                [el, eventName, fn];
+                return true;
+            }
+
+            var wrappedFn = function(e) {
+                return fn(Roo.lib.Event.getEvent(e));
+            };
+
+            var li = [el, eventName, fn, wrappedFn];
+
+            var index = listeners.length;
+            listeners[index] = li;
+
+            this.doAdd(el, eventName, wrappedFn, false);
+            return true;
+
+        },
+
+
+        removeListener: function(el, eventName, fn) {
+            var i, len;
+
+            el = Roo.getDom(el);
+
+            if(!fn) {
+                return this.purgeElement(el, false, eventName);
+            }
+
+
+            if ("unload" == eventName) {
+
+                for (i = 0,len = unloadListeners.length; i < len; i++) {
+                    var li = unloadListeners[i];
+                    if (li &&
+                        li[0] == el &&
+                        li[1] == eventName &&
+                        li[2] == fn) {
+                        unloadListeners.splice(i, 1);
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            var cacheItem = null;
+
+
+            var index = arguments[3];
+
+            if ("undefined" == typeof index) {
+                index = this._getCacheIndex(el, eventName, fn);
+            }
+
+            if (index >= 0) {
+                cacheItem = listeners[index];
+            }
+
+            if (!el || !cacheItem) {
+                return false;
+            }
+
+            this.doRemove(el, eventName, cacheItem[this.WFN], false);
+
+            delete listeners[index][this.WFN];
+            delete listeners[index][this.FN];
+            listeners.splice(index, 1);
+
+            return true;
+
+        },
+
+
+        getTarget: function(ev, resolveTextNode) {
+            ev = ev.browserEvent || ev;
+            var t = ev.target || ev.srcElement;
+            return this.resolveTextNode(t);
+        },
+
+
+        resolveTextNode: function(node) {
+            if (Roo.isSafari && node && 3 == node.nodeType) {
+                return node.parentNode;
+            } else {
+                return node;
+            }
+        },
+
+
+        getPageX: function(ev) {
+            ev = ev.browserEvent || ev;
+            var x = ev.pageX;
+            if (!x && 0 !== x) {
+                x = ev.clientX || 0;
+
+                if (Roo.isIE) {
+                    x += this.getScroll()[1];
+                }
+            }
+
+            return x;
+        },
+
+
+        getPageY: function(ev) {
+            ev = ev.browserEvent || ev;
+            var y = ev.pageY;
+            if (!y && 0 !== y) {
+                y = ev.clientY || 0;
+
+                if (Roo.isIE) {
+                    y += this.getScroll()[0];
+                }
+            }
+
+
+            return y;
+        },
+
+
+        getXY: function(ev) {
+            ev = ev.browserEvent || ev;
+            return [this.getPageX(ev), this.getPageY(ev)];
+        },
+
+
+        getRelatedTarget: function(ev) {
+            ev = ev.browserEvent || ev;
+            var t = ev.relatedTarget;
+            if (!t) {
+                if (ev.type == "mouseout") {
+                    t = ev.toElement;
+                } else if (ev.type == "mouseover") {
+                    t = ev.fromElement;
+                }
+            }
+
+            return this.resolveTextNode(t);
+        },
+
+
+        getTime: function(ev) {
+            ev = ev.browserEvent || ev;
+            if (!ev.time) {
+                var t = new Date().getTime();
+                try {
+                    ev.time = t;
+                } catch(ex) {
+                    this.lastError = ex;
+                    return t;
+                }
+            }
+
+            return ev.time;
+        },
+
+
+        stopEvent: function(ev) {
+            this.stopPropagation(ev);
+            this.preventDefault(ev);
+        },
+
+
+        stopPropagation: function(ev) {
+            ev = ev.browserEvent || ev;
+            if (ev.stopPropagation) {
+                ev.stopPropagation();
+            } else {
+                ev.cancelBubble = true;
+            }
+        },
+
+
+        preventDefault: function(ev) {
+            ev = ev.browserEvent || ev;
+            if(ev.preventDefault) {
+                ev.preventDefault();
+            } else {
+                ev.returnValue = false;
+            }
+        },
+
+
+        getEvent: function(e) {
+            var ev = e || window.event;
+            if (!ev) {
+                var c = this.getEvent.caller;
+                while (c) {
+                    ev = c.arguments[0];
+                    if (ev && Event == ev.constructor) {
+                        break;
+                    }
+                    c = c.caller;
+                }
+            }
+            return ev;
+        },
+
+
+        getCharCode: function(ev) {
+            ev = ev.browserEvent || ev;
+            return ev.charCode || ev.keyCode || 0;
+        },
+
+
+        _getCacheIndex: function(el, eventName, fn) {
+            for (var i = 0,len = listeners.length; i < len; ++i) {
+                var li = listeners[i];
+                if (li &&
+                    li[this.FN] == fn &&
+                    li[this.EL] == el &&
+                    li[this.TYPE] == eventName) {
+                    return i;
+                }
+            }
+
+            return -1;
+        },
+
+
+        elCache: {},
+
+
+        getEl: function(id) {
+            return document.getElementById(id);
+        },
+
+
+        clearCache: function() {
+        },
+
+
+        _load: function(e) {
+            loadComplete = true;
+            var EU = Roo.lib.Event;
+
+
+            if (Roo.isIE) {
+                EU.doRemove(window, "load", EU._load);
+            }
+        },
+
+
+        _tryPreloadAttach: function() {
+
+            if (this.locked) {
+                return false;
+            }
+
+            this.locked = true;
+
+
+            var tryAgain = !loadComplete;
+            if (!tryAgain) {
+                tryAgain = (retryCount > 0);
+            }
+
+
+            var notAvail = [];
+            for (var i = 0,len = onAvailStack.length; i < len; ++i) {
+                var item = onAvailStack[i];
+                if (item) {
+                    var el = this.getEl(item.id);
+
+                    if (el) {
+                        if (!item.checkReady ||
+                            loadComplete ||
+                            el.nextSibling ||
+                            (document && document.body)) {
+
+                            var scope = el;
+                            if (item.override) {
+                                if (item.override === true) {
+                                    scope = item.obj;
+                                } else {
+                                    scope = item.override;
+                                }
+                            }
+                            item.fn.call(scope, item.obj);
+                            onAvailStack[i] = null;
+                        }
+                    } else {
+                        notAvail.push(item);
+                    }
+                }
+            }
+
+            retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
+
+            if (tryAgain) {
+
+                this.startInterval();
+            } else {
+                clearInterval(this._interval);
+                this._interval = null;
+            }
+
+            this.locked = false;
+
+            return true;
+
+        },
+
+
+        purgeElement: function(el, recurse, eventName) {
+            var elListeners = this.getListeners(el, eventName);
+            if (elListeners) {
+                for (var i = 0,len = elListeners.length; i < len; ++i) {
+                    var l = elListeners[i];
+                    this.removeListener(el, l.type, l.fn);
+                }
+            }
+
+            if (recurse && el && el.childNodes) {
+                for (i = 0,len = el.childNodes.length; i < len; ++i) {
+                    this.purgeElement(el.childNodes[i], recurse, eventName);
+                }
+            }
+        },
+
+
+        getListeners: function(el, eventName) {
+            var results = [], searchLists;
+            if (!eventName) {
+                searchLists = [listeners, unloadListeners];
+            } else if (eventName == "unload") {
+                searchLists = [unloadListeners];
+            } else {
+                searchLists = [listeners];
+            }
+
+            for (var j = 0; j < searchLists.length; ++j) {
+                var searchList = searchLists[j];
+                if (searchList && searchList.length > 0) {
+                    for (var i = 0,len = searchList.length; i < len; ++i) {
+                        var l = searchList[i];
+                        if (l && l[this.EL] === el &&
+                            (!eventName || eventName === l[this.TYPE])) {
+                            results.push({
+                                type:   l[this.TYPE],
+                                fn:     l[this.FN],
+                                obj:    l[this.OBJ],
+                                adjust: l[this.ADJ_SCOPE],
+                                index:  i
+                            });
+                        }
+                    }
+                }
+            }
+
+            return (results.length) ? results : null;
+        },
+
+
+        _unload: function(e) {
+
+            var EU = Roo.lib.Event, i, j, l, len, index;
+
+            for (i = 0,len = unloadListeners.length; i < len; ++i) {
+                l = unloadListeners[i];
+                if (l) {
+                    var scope = window;
+                    if (l[EU.ADJ_SCOPE]) {
+                        if (l[EU.ADJ_SCOPE] === true) {
+                            scope = l[EU.OBJ];
+                        } else {
+                            scope = l[EU.ADJ_SCOPE];
+                        }
+                    }
+                    l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
+                    unloadListeners[i] = null;
+                    l = null;
+                    scope = null;
+                }
+            }
+
+            unloadListeners = null;
+
+            if (listeners && listeners.length > 0) {
+                j = listeners.length;
+                while (j) {
+                    index = j - 1;
+                    l = listeners[index];
+                    if (l) {
+                        EU.removeListener(l[EU.EL], l[EU.TYPE],
+                                l[EU.FN], index);
+                    }
+                    j = j - 1;
+                }
+                l = null;
+
+                EU.clearCache();
+            }
+
+            EU.doRemove(window, "unload", EU._unload);
+
+        },
+
+
+        getScroll: function() {
+            var dd = document.documentElement, db = document.body;
+            if (dd && (dd.scrollTop || dd.scrollLeft)) {
+                return [dd.scrollTop, dd.scrollLeft];
+            } else if (db) {
+                return [db.scrollTop, db.scrollLeft];
+            } else {
+                return [0, 0];
+            }
+        },
+
+
+        doAdd: function () {
+            if (window.addEventListener) {
+                return function(el, eventName, fn, capture) {
+                    el.addEventListener(eventName, fn, (capture));
+                };
+            } else if (window.attachEvent) {
+                return function(el, eventName, fn, capture) {
+                    el.attachEvent("on" + eventName, fn);
+                };
+            } else {
+                return function() {
+                };
+            }
+        }(),
+
+
+        doRemove: function() {
+            if (window.removeEventListener) {
+                return function (el, eventName, fn, capture) {
+                    el.removeEventListener(eventName, fn, (capture));
+                };
+            } else if (window.detachEvent) {
+                return function (el, eventName, fn) {
+                    el.detachEvent("on" + eventName, fn);
+                };
+            } else {
+                return function() {
+                };
+            }
+        }()
+    };
+    
+}();
+(function() {     
+   
+    var E = Roo.lib.Event;
+    E.on = E.addListener;
+    E.un = E.removeListener;
+
+    if (document && document.body) {
+        E._load();
+    } else {
+        E.doAdd(window, "load", E._load);
+    }
+    E.doAdd(window, "unload", E._unload);
+    E._tryPreloadAttach();
+})();
+
+/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+
+(function() {
+    
+    Roo.lib.Ajax = {
+        request : function(method, uri, cb, data, options) {
+            if(options){
+                var hs = options.headers;
+                if(hs){
+                    for(var h in hs){
+                        if(hs.hasOwnProperty(h)){
+                            this.initHeader(h, hs[h], false);
+                        }
+                    }
+                }
+                if(options.xmlData){
+                    this.initHeader('Content-Type', 'text/xml', false);
+                    method = 'POST';
+                    data = options.xmlData;
+                }
+            }
+
+            return this.asyncRequest(method, uri, cb, data);
+        },
+
+        serializeForm : function(form) {
+            if(typeof form == 'string') {
+                form = (document.getElementById(form) || document.forms[form]);
+            }
+
+            var el, name, val, disabled, data = '', hasSubmit = false;
+            for (var i = 0; i < form.elements.length; i++) {
+                el = form.elements[i];
+                disabled = form.elements[i].disabled;
+                name = form.elements[i].name;
+                val = form.elements[i].value;
+
+                if (!disabled && name){
+                    switch (el.type)
+                            {
+                        case 'select-one':
+                        case 'select-multiple':
+                            for (var j = 0; j < el.options.length; j++) {
+                                if (el.options[j].selected) {
+                                    if (Roo.isIE) {
+                                        data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
+                                    }
+                                    else {
+                                        data += encodeURIComponent(name) + '=' + encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
+                                    }
+                                }
+                            }
+                            break;
+                        case 'radio':
+                        case 'checkbox':
+                            if (el.checked) {
+                                data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
+                            }
+                            break;
+                        case 'file':
+
+                        case undefined:
+
+                        case 'reset':
+
+                        case 'button':
+
+                            break;
+                        case 'submit':
+                            if(hasSubmit == false) {
+                                data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
+                                hasSubmit = true;
+                            }
+                            break;
+                        default:
+                            data += encodeURIComponent(name) + '=' + encodeURIComponent(val) + '&';
+                            break;
+                    }
+                }
+            }
+            data = data.substr(0, data.length - 1);
+            return data;
+        },
+
+        headers:{},
+
+        hasHeaders:false,
+
+        useDefaultHeader:true,
+
+        defaultPostHeader:'application/x-www-form-urlencoded',
+
+        useDefaultXhrHeader:true,
+
+        defaultXhrHeader:'XMLHttpRequest',
+
+        hasDefaultHeaders:true,
+
+        defaultHeaders:{},
+
+        poll:{},
+
+        timeout:{},
+
+        pollInterval:50,
+
+        transactionId:0,
+
+        setProgId:function(id)
+        {
+            this.activeX.unshift(id);
+        },
+
+        setDefaultPostHeader:function(b)
+        {
+            this.useDefaultHeader = b;
+        },
+
+        setDefaultXhrHeader:function(b)
+        {
+            this.useDefaultXhrHeader = b;
+        },
+
+        setPollingInterval:function(i)
+        {
+            if (typeof i == 'number' && isFinite(i)) {
+                this.pollInterval = i;
+            }
+        },
+
+        createXhrObject:function(transactionId)
+        {
+            var obj,http;
+            try
+            {
+
+                http = new XMLHttpRequest();
+
+                obj = { conn:http, tId:transactionId };
+            }
+            catch(e)
+            {
+                for (var i = 0; i < this.activeX.length; ++i) {
+                    try
+                    {
+
+                        http = new ActiveXObject(this.activeX[i]);
+
+                        obj = { conn:http, tId:transactionId };
+                        break;
+                    }
+                    catch(e) {
+                    }
+                }
+            }
+            finally
+            {
+                return obj;
+            }
+        },
+
+        getConnectionObject:function()
+        {
+            var o;
+            var tId = this.transactionId;
+
+            try
+            {
+                o = this.createXhrObject(tId);
+                if (o) {
+                    this.transactionId++;
+                }
+            }
+            catch(e) {
+            }
+            finally
+            {
+                return o;
+            }
+        },
+
+        asyncRequest:function(method, uri, callback, postData)
+        {
+            var o = this.getConnectionObject();
+
+            if (!o) {
+                return null;
+            }
+            else {
+                o.conn.open(method, uri, true);
+
+                if (this.useDefaultXhrHeader) {
+                    if (!this.defaultHeaders['X-Requested-With']) {
+                        this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
+                    }
+                }
+
+                if(postData && this.useDefaultHeader){
+                    this.initHeader('Content-Type', this.defaultPostHeader);
+                }
+
+                 if (this.hasDefaultHeaders || this.hasHeaders) {
+                    this.setHeader(o);
+                }
+
+                this.handleReadyState(o, callback);
+                o.conn.send(postData || null);
+
+                return o;
+            }
+        },
+
+        handleReadyState:function(o, callback)
+        {
+            var oConn = this;
+
+            if (callback && callback.timeout) {
+                this.timeout[o.tId] = window.setTimeout(function() {
+                    oConn.abort(o, callback, true);
+                }, callback.timeout);
+            }
+
+            this.poll[o.tId] = window.setInterval(
+                    function() {
+                        if (o.conn && o.conn.readyState == 4) {
+                            window.clearInterval(oConn.poll[o.tId]);
+                            delete oConn.poll[o.tId];
+
+                            if(callback && callback.timeout) {
+                                window.clearTimeout(oConn.timeout[o.tId]);
+                                delete oConn.timeout[o.tId];
+                            }
+
+                            oConn.handleTransactionResponse(o, callback);
+                        }
+                    }
+                    , this.pollInterval);
+        },
+
+        handleTransactionResponse:function(o, callback, isAbort)
+        {
+
+            if (!callback) {
+                this.releaseObject(o);
+                return;
+            }
+
+            var httpStatus, responseObject;
+
+            try
+            {
+                if (o.conn.status !== undefined && o.conn.status != 0) {
+                    httpStatus = o.conn.status;
+                }
+                else {
+                    httpStatus = 13030;
+                }
+            }
+            catch(e) {
+
+
+                httpStatus = 13030;
+            }
+
+            if (httpStatus >= 200 && httpStatus < 300) {
+                responseObject = this.createResponseObject(o, callback.argument);
+                if (callback.success) {
+                    if (!callback.scope) {
+                        callback.success(responseObject);
+                    }
+                    else {
+
+
+                        callback.success.apply(callback.scope, [responseObject]);
+                    }
+                }
+            }
+            else {
+                switch (httpStatus) {
+
+                    case 12002:
+                    case 12029:
+                    case 12030:
+                    case 12031:
+                    case 12152:
+                    case 13030:
+                        responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
+                        if (callback.failure) {
+                            if (!callback.scope) {
+                                callback.failure(responseObject);
+                            }
+                            else {
+                                callback.failure.apply(callback.scope, [responseObject]);
+                            }
+                        }
+                        break;
+                    default:
+                        responseObject = this.createResponseObject(o, callback.argument);
+                        if (callback.failure) {
+                            if (!callback.scope) {
+                                callback.failure(responseObject);
+                            }
+                            else {
+                                callback.failure.apply(callback.scope, [responseObject]);
+                            }
+                        }
+                }
+            }
+
+            this.releaseObject(o);
+            responseObject = null;
+        },
+
+        createResponseObject:function(o, callbackArg)
+        {
+            var obj = {};
+            var headerObj = {};
+
+            try
+            {
+                var headerStr = o.conn.getAllResponseHeaders();
+                var header = headerStr.split('\n');
+                for (var i = 0; i < header.length; i++) {
+                    var delimitPos = header[i].indexOf(':');
+                    if (delimitPos != -1) {
+                        headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
+                    }
+                }
+            }
+            catch(e) {
+            }
+
+            obj.tId = o.tId;
+            obj.status = o.conn.status;
+            obj.statusText = o.conn.statusText;
+            obj.getResponseHeader = headerObj;
+            obj.getAllResponseHeaders = headerStr;
+            obj.responseText = o.conn.responseText;
+            obj.responseXML = o.conn.responseXML;
+
+            if (typeof callbackArg !== undefined) {
+                obj.argument = callbackArg;
+            }
+
+            return obj;
+        },
+
+        createExceptionObject:function(tId, callbackArg, isAbort)
+        {
+            var COMM_CODE = 0;
+            var COMM_ERROR = 'communication failure';
+            var ABORT_CODE = -1;
+            var ABORT_ERROR = 'transaction aborted';
+
+            var obj = {};
+
+            obj.tId = tId;
+            if (isAbort) {
+                obj.status = ABORT_CODE;
+                obj.statusText = ABORT_ERROR;
+            }
+            else {
+                obj.status = COMM_CODE;
+                obj.statusText = COMM_ERROR;
+            }
+
+            if (callbackArg) {
+                obj.argument = callbackArg;
+            }
+
+            return obj;
+        },
+
+        initHeader:function(label, value, isDefault)
+        {
+            var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
+
+            if (headerObj[label] === undefined) {
+                headerObj[label] = value;
+            }
+            else {
+
+
+                headerObj[label] = value + "," + headerObj[label];
+            }
+
+            if (isDefault) {
+                this.hasDefaultHeaders = true;
+            }
+            else {
+                this.hasHeaders = true;
+            }
+        },
+
+
+        setHeader:function(o)
+        {
+            if (this.hasDefaultHeaders) {
+                for (var prop in this.defaultHeaders) {
+                    if (this.defaultHeaders.hasOwnProperty(prop)) {
+                        o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
+                    }
+                }
+            }
+
+            if (this.hasHeaders) {
+                for (var prop in this.headers) {
+                    if (this.headers.hasOwnProperty(prop)) {
+                        o.conn.setRequestHeader(prop, this.headers[prop]);
+                    }
+                }
+                this.headers = {};
+                this.hasHeaders = false;
+            }
+        },
+
+        resetDefaultHeaders:function() {
+            delete this.defaultHeaders;
+            this.defaultHeaders = {};
+            this.hasDefaultHeaders = false;
+        },
+
+        abort:function(o, callback, isTimeout)
+        {
+            if(this.isCallInProgress(o)) {
+                o.conn.abort();
+                window.clearInterval(this.poll[o.tId]);
+                delete this.poll[o.tId];
+                if (isTimeout) {
+                    delete this.timeout[o.tId];
+                }
+
+                this.handleTransactionResponse(o, callback, true);
+
+                return true;
+            }
+            else {
+                return false;
+            }
+        },
+
+
+        isCallInProgress:function(o)
+        {
+            if (o && o.conn) {
+                return o.conn.readyState != 4 && o.conn.readyState != 0;
+            }
+            else {
+
+                return false;
+            }
+        },
+
+
+        releaseObject:function(o)
+        {
+
+            o.conn = null;
+
+            o = null;
+        },
+
+        activeX:[
+        'MSXML2.XMLHTTP.3.0',
+        'MSXML2.XMLHTTP',
+        'Microsoft.XMLHTTP'
+        ]
+
+
+    };
+})();/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+
+Roo.lib.Region = function(t, r, b, l) {
+    this.top = t;
+    this[1] = t;
+    this.right = r;
+    this.bottom = b;
+    this.left = l;
+    this[0] = l;
+};
+
+
+Roo.lib.Region.prototype = {
+    contains : function(region) {
+        return ( region.left >= this.left &&
+                 region.right <= this.right &&
+                 region.top >= this.top &&
+                 region.bottom <= this.bottom    );
+
+    },
+
+    getArea : function() {
+        return ( (this.bottom - this.top) * (this.right - this.left) );
+    },
+
+    intersect : function(region) {
+        var t = Math.max(this.top, region.top);
+        var r = Math.min(this.right, region.right);
+        var b = Math.min(this.bottom, region.bottom);
+        var l = Math.max(this.left, region.left);
+
+        if (b >= t && r >= l) {
+            return new Roo.lib.Region(t, r, b, l);
+        } else {
+            return null;
+        }
+    },
+    union : function(region) {
+        var t = Math.min(this.top, region.top);
+        var r = Math.max(this.right, region.right);
+        var b = Math.max(this.bottom, region.bottom);
+        var l = Math.min(this.left, region.left);
+
+        return new Roo.lib.Region(t, r, b, l);
+    },
+
+    adjust : function(t, l, b, r) {
+        this.top += t;
+        this.left += l;
+        this.right += r;
+        this.bottom += b;
+        return this;
+    }
+};
+
+Roo.lib.Region.getRegion = function(el) {
+    var p = Roo.lib.Dom.getXY(el);
+
+    var t = p[1];
+    var r = p[0] + el.offsetWidth;
+    var b = p[1] + el.offsetHeight;
+    var l = p[0];
+
+    return new Roo.lib.Region(t, r, b, l);
+};
+/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+//@@dep Roo.lib.Region
+
+
+Roo.lib.Point = function(x, y) {
+    if (x instanceof Array) {
+        y = x[1];
+        x = x[0];
+    }
+    this.x = this.right = this.left = this[0] = x;
+    this.y = this.top = this.bottom = this[1] = y;
+};
+
+Roo.lib.Point.prototype = new Roo.lib.Region();
+/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+(function() {   
+
+    Roo.lib.Anim = {
+        scroll : function(el, args, duration, easing, cb, scope) {
+            this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
+        },
+
+        motion : function(el, args, duration, easing, cb, scope) {
+            this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
+        },
+
+        color : function(el, args, duration, easing, cb, scope) {
+            this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
+        },
+
+        run : function(el, args, duration, easing, cb, scope, type) {
+            type = type || Roo.lib.AnimBase;
+            if (typeof easing == "string") {
+                easing = Roo.lib.Easing[easing];
+            }
+            var anim = new type(el, args, duration, easing);
+            anim.animateX(function() {
+                Roo.callback(cb, scope);
+            });
+            return anim;
+        }
+    };
+})();/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+
+(function() {    
+    var libFlyweight;
+    
+    function fly(el) {
+        if (!libFlyweight) {
+            libFlyweight = new Roo.Element.Flyweight();
+        }
+        libFlyweight.dom = el;
+        return libFlyweight;
+    }
+
+    // since this uses fly! - it cant be in DOM (which does not have fly yet..)
+    
+   
+    
+    Roo.lib.AnimBase = function(el, attributes, duration, method) {
+        if (el) {
+            this.init(el, attributes, duration, method);
+        }
+    };
+
+    Roo.lib.AnimBase.fly = fly;
+    
+    
+    
+    Roo.lib.AnimBase.prototype = {
+
+        toString: function() {
+            var el = this.getEl();
+            var id = el.id || el.tagName;
+            return ("Anim " + id);
+        },
+
+        patterns: {
+            noNegatives:        /width|height|opacity|padding/i,
+            offsetAttribute:  /^((width|height)|(top|left))$/,
+            defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
+            offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
+        },
+
+
+        doMethod: function(attr, start, end) {
+            return this.method(this.currentFrame, start, end - start, this.totalFrames);
+        },
+
+
+        setAttribute: function(attr, val, unit) {
+            if (this.patterns.noNegatives.test(attr)) {
+                val = (val > 0) ? val : 0;
+            }
+
+            Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
+        },
+
+
+        getAttribute: function(attr) {
+            var el = this.getEl();
+            var val = fly(el).getStyle(attr);
+
+            if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
+                return parseFloat(val);
+            }
+
+            var a = this.patterns.offsetAttribute.exec(attr) || [];
+            var pos = !!( a[3] );
+            var box = !!( a[2] );
+
+
+            if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
+                val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
+            } else {
+                val = 0;
+            }
+
+            return val;
+        },
+
+
+        getDefaultUnit: function(attr) {
+            if (this.patterns.defaultUnit.test(attr)) {
+                return 'px';
+            }
+
+            return '';
+        },
+
+        animateX : function(callback, scope) {
+            var f = function() {
+                this.onComplete.removeListener(f);
+                if (typeof callback == "function") {
+                    callback.call(scope || this, this);
+                }
+            };
+            this.onComplete.addListener(f, this);
+            this.animate();
+        },
+
+
+        setRuntimeAttribute: function(attr) {
+            var start;
+            var end;
+            var attributes = this.attributes;
+
+            this.runtimeAttributes[attr] = {};
+
+            var isset = function(prop) {
+                return (typeof prop !== 'undefined');
+            };
+
+            if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
+                return false;
+            }
+
+            start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
+
+
+            if (isset(attributes[attr]['to'])) {
+                end = attributes[attr]['to'];
+            } else if (isset(attributes[attr]['by'])) {
+                if (start.constructor == Array) {
+                    end = [];
+                    for (var i = 0, len = start.length; i < len; ++i) {
+                        end[i] = start[i] + attributes[attr]['by'][i];
+                    }
+                } else {
+                    end = start + attributes[attr]['by'];
+                }
+            }
+
+            this.runtimeAttributes[attr].start = start;
+            this.runtimeAttributes[attr].end = end;
+
+
+            this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
+        },
+
+
+        init: function(el, attributes, duration, method) {
+
+            var isAnimated = false;
+
+
+            var startTime = null;
+
+
+            var actualFrames = 0;
+
+
+            el = Roo.getDom(el);
+
+
+            this.attributes = attributes || {};
+
+
+            this.duration = duration || 1;
+
+
+            this.method = method || Roo.lib.Easing.easeNone;
+
+
+            this.useSeconds = true;
+
+
+            this.currentFrame = 0;
+
+
+            this.totalFrames = Roo.lib.AnimMgr.fps;
+
+
+            this.getEl = function() {
+                return el;
+            };
+
+
+            this.isAnimated = function() {
+                return isAnimated;
+            };
+
+
+            this.getStartTime = function() {
+                return startTime;
+            };
+
+            this.runtimeAttributes = {};
+
+
+            this.animate = function() {
+                if (this.isAnimated()) {
+                    return false;
+                }
+
+                this.currentFrame = 0;
+
+                this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
+
+                Roo.lib.AnimMgr.registerElement(this);
+            };
+
+
+            this.stop = function(finish) {
+                if (finish) {
+                    this.currentFrame = this.totalFrames;
+                    this._onTween.fire();
+                }
+                Roo.lib.AnimMgr.stop(this);
+            };
+
+            var onStart = function() {
+                this.onStart.fire();
+
+                this.runtimeAttributes = {};
+                for (var attr in this.attributes) {
+                    this.setRuntimeAttribute(attr);
+                }
+
+                isAnimated = true;
+                actualFrames = 0;
+                startTime = new Date();
+            };
+
+
+            var onTween = function() {
+                var data = {
+                    duration: new Date() - this.getStartTime(),
+                    currentFrame: this.currentFrame
+                };
+
+                data.toString = function() {
+                    return (
+                            'duration: ' + data.duration +
+                            ', currentFrame: ' + data.currentFrame
+                            );
+                };
+
+                this.onTween.fire(data);
+
+                var runtimeAttributes = this.runtimeAttributes;
+
+                for (var attr in runtimeAttributes) {
+                    this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
+                }
+
+                actualFrames += 1;
+            };
+
+            var onComplete = function() {
+                var actual_duration = (new Date() - startTime) / 1000 ;
+
+                var data = {
+                    duration: actual_duration,
+                    frames: actualFrames,
+                    fps: actualFrames / actual_duration
+                };
+
+                data.toString = function() {
+                    return (
+                            'duration: ' + data.duration +
+                            ', frames: ' + data.frames +
+                            ', fps: ' + data.fps
+                            );
+                };
+
+                isAnimated = false;
+                actualFrames = 0;
+                this.onComplete.fire(data);
+            };
+
+
+            this._onStart = new Roo.util.Event(this);
+            this.onStart = new Roo.util.Event(this);
+            this.onTween = new Roo.util.Event(this);
+            this._onTween = new Roo.util.Event(this);
+            this.onComplete = new Roo.util.Event(this);
+            this._onComplete = new Roo.util.Event(this);
+            this._onStart.addListener(onStart);
+            this._onTween.addListener(onTween);
+            this._onComplete.addListener(onComplete);
+        }
+    };
+})();
+/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+
+Roo.lib.AnimMgr = new function() {
+
+        var thread = null;
+
+
+        var queue = [];
+
+
+        var tweenCount = 0;
+
+
+        this.fps = 1000;
+
+
+        this.delay = 1;
+
+
+        this.registerElement = function(tween) {
+            queue[queue.length] = tween;
+            tweenCount += 1;
+            tween._onStart.fire();
+            this.start();
+        };
+
+
+        this.unRegister = function(tween, index) {
+            tween._onComplete.fire();
+            index = index || getIndex(tween);
+            if (index != -1) {
+                queue.splice(index, 1);
+            }
+
+            tweenCount -= 1;
+            if (tweenCount <= 0) {
+                this.stop();
+            }
+        };
+
+
+        this.start = function() {
+            if (thread === null) {
+                thread = setInterval(this.run, this.delay);
+            }
+        };
+
+
+        this.stop = function(tween) {
+            if (!tween) {
+                clearInterval(thread);
+
+                for (var i = 0, len = queue.length; i < len; ++i) {
+                    if (queue[0].isAnimated()) {
+                        this.unRegister(queue[0], 0);
+                    }
+                }
+
+                queue = [];
+                thread = null;
+                tweenCount = 0;
+            }
+            else {
+                this.unRegister(tween);
+            }
+        };
+
+
+        this.run = function() {
+            for (var i = 0, len = queue.length; i < len; ++i) {
+                var tween = queue[i];
+                if (!tween || !tween.isAnimated()) {
+                    continue;
+                }
+
+                if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
+                {
+                    tween.currentFrame += 1;
+
+                    if (tween.useSeconds) {
+                        correctFrame(tween);
+                    }
+                    tween._onTween.fire();
+                }
+                else {
+                    Roo.lib.AnimMgr.stop(tween, i);
+                }
+            }
+        };
+
+        var getIndex = function(anim) {
+            for (var i = 0, len = queue.length; i < len; ++i) {
+                if (queue[i] == anim) {
+                    return i;
+                }
+            }
+            return -1;
+        };
+
+
+        var correctFrame = function(tween) {
+            var frames = tween.totalFrames;
+            var frame = tween.currentFrame;
+            var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
+            var elapsed = (new Date() - tween.getStartTime());
+            var tweak = 0;
+
+            if (elapsed < tween.duration * 1000) {
+                tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
+            } else {
+                tweak = frames - (frame + 1);
+            }
+            if (tweak > 0 && isFinite(tweak)) {
+                if (tween.currentFrame + tweak >= frames) {
+                    tweak = frames - (frame + 1);
+                }
+
+                tween.currentFrame += tweak;
+            }
+        };
+    };/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+Roo.lib.Bezier = new function() {
+
+        this.getPosition = function(points, t) {
+            var n = points.length;
+            var tmp = [];
+
+            for (var i = 0; i < n; ++i) {
+                tmp[i] = [points[i][0], points[i][1]];
+            }
+
+            for (var j = 1; j < n; ++j) {
+                for (i = 0; i < n - j; ++i) {
+                    tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
+                    tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
+                }
+            }
+
+            return [ tmp[0][0], tmp[0][1] ];
+
+        };
+    };/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+(function() {
+
+    Roo.lib.ColorAnim = function(el, attributes, duration, method) {
+        Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
+    };
+
+    Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
+
+    var fly = Roo.lib.AnimBase.fly;
+    var Y = Roo.lib;
+    var superclass = Y.ColorAnim.superclass;
+    var proto = Y.ColorAnim.prototype;
+
+    proto.toString = function() {
+        var el = this.getEl();
+        var id = el.id || el.tagName;
+        return ("ColorAnim " + id);
+    };
+
+    proto.patterns.color = /color$/i;
+    proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
+    proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
+    proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
+    proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
+
+
+    proto.parseColor = function(s) {
+        if (s.length == 3) {
+            return s;
+        }
+
+        var c = this.patterns.hex.exec(s);
+        if (c && c.length == 4) {
+            return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
+        }
+
+        c = this.patterns.rgb.exec(s);
+        if (c && c.length == 4) {
+            return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
+        }
+
+        c = this.patterns.hex3.exec(s);
+        if (c && c.length == 4) {
+            return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
+        }
+
+        return null;
+    };
+    // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
+    proto.getAttribute = function(attr) {
+        var el = this.getEl();
+        if (this.patterns.color.test(attr)) {
+            var val = fly(el).getStyle(attr);
+
+            if (this.patterns.transparent.test(val)) {
+                var parent = el.parentNode;
+                val = fly(parent).getStyle(attr);
+
+                while (parent && this.patterns.transparent.test(val)) {
+                    parent = parent.parentNode;
+                    val = fly(parent).getStyle(attr);
+                    if (parent.tagName.toUpperCase() == 'HTML') {
+                        val = '#fff';
+                    }
+                }
+            }
+        } else {
+            val = superclass.getAttribute.call(this, attr);
+        }
+
+        return val;
+    };
+    proto.getAttribute = function(attr) {
+        var el = this.getEl();
+        if (this.patterns.color.test(attr)) {
+            var val = fly(el).getStyle(attr);
+
+            if (this.patterns.transparent.test(val)) {
+                var parent = el.parentNode;
+                val = fly(parent).getStyle(attr);
+
+                while (parent && this.patterns.transparent.test(val)) {
+                    parent = parent.parentNode;
+                    val = fly(parent).getStyle(attr);
+                    if (parent.tagName.toUpperCase() == 'HTML') {
+                        val = '#fff';
+                    }
+                }
+            }
+        } else {
+            val = superclass.getAttribute.call(this, attr);
+        }
+
+        return val;
+    };
+
+    proto.doMethod = function(attr, start, end) {
+        var val;
+
+        if (this.patterns.color.test(attr)) {
+            val = [];
+            for (var i = 0, len = start.length; i < len; ++i) {
+                val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
+            }
+
+            val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
+        }
+        else {
+            val = superclass.doMethod.call(this, attr, start, end);
+        }
+
+        return val;
+    };
+
+    proto.setRuntimeAttribute = function(attr) {
+        superclass.setRuntimeAttribute.call(this, attr);
+
+        if (this.patterns.color.test(attr)) {
+            var attributes = this.attributes;
+            var start = this.parseColor(this.runtimeAttributes[attr].start);
+            var end = this.parseColor(this.runtimeAttributes[attr].end);
+
+            if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
+                end = this.parseColor(attributes[attr].by);
+
+                for (var i = 0, len = start.length; i < len; ++i) {
+                    end[i] = start[i] + end[i];
+                }
+            }
+
+            this.runtimeAttributes[attr].start = start;
+            this.runtimeAttributes[attr].end = end;
+        }
+    };
+})();
+
+/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+Roo.lib.Easing = {
+
+
+    easeNone: function (t, b, c, d) {
+        return c * t / d + b;
+    },
+
+
+    easeIn: function (t, b, c, d) {
+        return c * (t /= d) * t + b;
+    },
+
+
+    easeOut: function (t, b, c, d) {
+        return -c * (t /= d) * (t - 2) + b;
+    },
+
+
+    easeBoth: function (t, b, c, d) {
+        if ((t /= d / 2) < 1) {
+            return c / 2 * t * t + b;
+        }
+
+        return -c / 2 * ((--t) * (t - 2) - 1) + b;
+    },
+
+
+    easeInStrong: function (t, b, c, d) {
+        return c * (t /= d) * t * t * t + b;
+    },
+
+
+    easeOutStrong: function (t, b, c, d) {
+        return -c * ((t = t / d - 1) * t * t * t - 1) + b;
+    },
+
+
+    easeBothStrong: function (t, b, c, d) {
+        if ((t /= d / 2) < 1) {
+            return c / 2 * t * t * t * t + b;
+        }
+
+        return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
+    },
+
+
+
+    elasticIn: function (t, b, c, d, a, p) {
+        if (t == 0) {
+            return b;
+        }
+        if ((t /= d) == 1) {
+            return b + c;
+        }
+        if (!p) {
+            p = d * .3;
+        }
+
+        if (!a || a < Math.abs(c)) {
+            a = c;
+            var s = p / 4;
+        }
+        else {
+            var s = p / (2 * Math.PI) * Math.asin(c / a);
+        }
+
+        return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
+    },
+
+
+    elasticOut: function (t, b, c, d, a, p) {
+        if (t == 0) {
+            return b;
+        }
+        if ((t /= d) == 1) {
+            return b + c;
+        }
+        if (!p) {
+            p = d * .3;
+        }
+
+        if (!a || a < Math.abs(c)) {
+            a = c;
+            var s = p / 4;
+        }
+        else {
+            var s = p / (2 * Math.PI) * Math.asin(c / a);
+        }
+
+        return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
+    },
+
+
+    elasticBoth: function (t, b, c, d, a, p) {
+        if (t == 0) {
+            return b;
+        }
+
+        if ((t /= d / 2) == 2) {
+            return b + c;
+        }
+
+        if (!p) {
+            p = d * (.3 * 1.5);
+        }
+
+        if (!a || a < Math.abs(c)) {
+            a = c;
+            var s = p / 4;
+        }
+        else {
+            var s = p / (2 * Math.PI) * Math.asin(c / a);
+        }
+
+        if (t < 1) {
+            return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
+                          Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
+        }
+        return a * Math.pow(2, -10 * (t -= 1)) *
+               Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
+    },
+
+
+
+    backIn: function (t, b, c, d, s) {
+        if (typeof s == 'undefined') {
+            s = 1.70158;
+        }
+        return c * (t /= d) * t * ((s + 1) * t - s) + b;
+    },
+
+
+    backOut: function (t, b, c, d, s) {
+        if (typeof s == 'undefined') {
+            s = 1.70158;
+        }
+        return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
+    },
+
+
+    backBoth: function (t, b, c, d, s) {
+        if (typeof s == 'undefined') {
+            s = 1.70158;
+        }
+
+        if ((t /= d / 2 ) < 1) {
+            return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
+        }
+        return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
+    },
+
+
+    bounceIn: function (t, b, c, d) {
+        return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
+    },
+
+
+    bounceOut: function (t, b, c, d) {
+        if ((t /= d) < (1 / 2.75)) {
+            return c * (7.5625 * t * t) + b;
+        } else if (t < (2 / 2.75)) {
+            return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
+        } else if (t < (2.5 / 2.75)) {
+            return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
+        }
+        return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
+    },
+
+
+    bounceBoth: function (t, b, c, d) {
+        if (t < d / 2) {
+            return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
+        }
+        return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
+    }
+};/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+    (function() {
+        Roo.lib.Motion = function(el, attributes, duration, method) {
+            if (el) {
+                Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
+            }
+        };
+
+        Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
+
+
+        var Y = Roo.lib;
+        var superclass = Y.Motion.superclass;
+        var proto = Y.Motion.prototype;
+
+        proto.toString = function() {
+            var el = this.getEl();
+            var id = el.id || el.tagName;
+            return ("Motion " + id);
+        };
+
+        proto.patterns.points = /^points$/i;
+
+        proto.setAttribute = function(attr, val, unit) {
+            if (this.patterns.points.test(attr)) {
+                unit = unit || 'px';
+                superclass.setAttribute.call(this, 'left', val[0], unit);
+                superclass.setAttribute.call(this, 'top', val[1], unit);
+            } else {
+                superclass.setAttribute.call(this, attr, val, unit);
+            }
+        };
+
+        proto.getAttribute = function(attr) {
+            if (this.patterns.points.test(attr)) {
+                var val = [
+                        superclass.getAttribute.call(this, 'left'),
+                        superclass.getAttribute.call(this, 'top')
+                        ];
+            } else {
+                val = superclass.getAttribute.call(this, attr);
+            }
+
+            return val;
+        };
+
+        proto.doMethod = function(attr, start, end) {
+            var val = null;
+
+            if (this.patterns.points.test(attr)) {
+                var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
+                val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
+            } else {
+                val = superclass.doMethod.call(this, attr, start, end);
+            }
+            return val;
+        };
+
+        proto.setRuntimeAttribute = function(attr) {
+            if (this.patterns.points.test(attr)) {
+                var el = this.getEl();
+                var attributes = this.attributes;
+                var start;
+                var control = attributes['points']['control'] || [];
+                var end;
+                var i, len;
+
+                if (control.length > 0 && !(control[0] instanceof Array)) {
+                    control = [control];
+                } else {
+                    var tmp = [];
+                    for (i = 0,len = control.length; i < len; ++i) {
+                        tmp[i] = control[i];
+                    }
+                    control = tmp;
+                }
+
+                Roo.fly(el).position();
+
+                if (isset(attributes['points']['from'])) {
+                    Roo.lib.Dom.setXY(el, attributes['points']['from']);
+                }
+                else {
+                    Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
+                }
+
+                start = this.getAttribute('points');
+
+
+                if (isset(attributes['points']['to'])) {
+                    end = translateValues.call(this, attributes['points']['to'], start);
+
+                    var pageXY = Roo.lib.Dom.getXY(this.getEl());
+                    for (i = 0,len = control.length; i < len; ++i) {
+                        control[i] = translateValues.call(this, control[i], start);
+                    }
+
+
+                } else if (isset(attributes['points']['by'])) {
+                    end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
+
+                    for (i = 0,len = control.length; i < len; ++i) {
+                        control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
+                    }
+                }
+
+                this.runtimeAttributes[attr] = [start];
+
+                if (control.length > 0) {
+                    this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
+                }
+
+                this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
+            }
+            else {
+                superclass.setRuntimeAttribute.call(this, attr);
+            }
+        };
+
+        var translateValues = function(val, start) {
+            var pageXY = Roo.lib.Dom.getXY(this.getEl());
+            val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
+
+            return val;
+        };
+
+        var isset = function(prop) {
+            return (typeof prop !== 'undefined');
+        };
+    })();
+/*
+ * Portions of this file are based on pieces of Yahoo User Interface Library
+ * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+ * YUI licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ * <script type="text/javascript">
+ *
+ */
+    (function() {
+        Roo.lib.Scroll = function(el, attributes, duration, method) {
+            if (el) {
+                Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
+            }
+        };
+
+        Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
+
+
+        var Y = Roo.lib;
+        var superclass = Y.Scroll.superclass;
+        var proto = Y.Scroll.prototype;
+
+        proto.toString = function() {
+            var el = this.getEl();
+            var id = el.id || el.tagName;
+            return ("Scroll " + id);
+        };
+
+        proto.doMethod = function(attr, start, end) {
+            var val = null;
+
+            if (attr == 'scroll') {
+                val = [
+                        this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
+                        this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
+                        ];
+
+            } else {
+                val = superclass.doMethod.call(this, attr, start, end);
+            }
+            return val;
+        };
+
+        proto.getAttribute = function(attr) {
+            var val = null;
+            var el = this.getEl();
+
+            if (attr == 'scroll') {
+                val = [ el.scrollLeft, el.scrollTop ];
+            } else {
+                val = superclass.getAttribute.call(this, attr);
+            }
+
+            return val;
+        };
+
+        proto.setAttribute = function(attr, val, unit) {
+            var el = this.getEl();
+
+            if (attr == 'scroll') {
+                el.scrollLeft = val[0];
+                el.scrollTop = val[1];
+            } else {
+                superclass.setAttribute.call(this, attr, val, unit);
+            }
+        };
+    })();
+/*
+ * 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.DomHelper
+ * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
+ * For more information see <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
+ * @singleton
+ */
+Roo.DomHelper = function(){
+    var tempTableEl = null;
+    var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
+    var tableRe = /^table|tbody|tr|td$/i;
+    var xmlns = {};
+    // build as innerHTML where available
+    /** @ignore */
+    var createHtml = function(o){
+        if(typeof o == 'string'){
+            return o;
+        }
+        var b = "";
+        if(!o.tag){
+            o.tag = "div";
+        }
+        b += "<" + o.tag;
+        for(var attr in o){
+            if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
+            if(attr == "style"){
+                var s = o["style"];
+                if(typeof s == "function"){
+                    s = s.call();
+                }
+                if(typeof s == "string"){
+                    b += ' style="' + s + '"';
+                }else if(typeof s == "object"){
+                    b += ' style="';
+                    for(var key in s){
+                        if(typeof s[key] != "function"){
+                            b += key + ":" + s[key] + ";";
+                        }
+                    }
+                    b += '"';
+                }
+            }else{
+                if(attr == "cls"){
+                    b += ' class="' + o["cls"] + '"';
+                }else if(attr == "htmlFor"){
+                    b += ' for="' + o["htmlFor"] + '"';
+                }else{
+                    b += " " + attr + '="' + o[attr] + '"';
+                }
+            }
+        }
+        if(emptyTags.test(o.tag)){
+            b += "/>";
+        }else{
+            b += ">";
+            var cn = o.children || o.cn;
+            if(cn){
+                //http://bugs.kde.org/show_bug.cgi?id=71506
+                if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
+                    for(var i = 0, len = cn.length; i < len; i++) {
+                        b += createHtml(cn[i], b);
+                    }
+                }else{
+                    b += createHtml(cn, b);
+                }
+            }
+            if(o.html){
+                b += o.html;
+            }
+            b += "</" + o.tag + ">";
+        }
+        return b;
+    };
+
+    // build as dom
+    /** @ignore */
+    var createDom = function(o, parentNode){
+         
+        // defininition craeted..
+        var ns = false;
+        if (o.ns && o.ns != 'html') {
+               
+            if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
+                xmlns[o.ns] = o.xmlns;
+                ns = o.xmlns;
+            }
+            if (typeof(xmlns[o.ns]) == 'undefined') {
+                console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
+            }
+            ns = xmlns[o.ns];
+        }
+        
+        
+        if (typeof(o) == 'string') {
+            return parentNode.appendChild(document.createTextNode(o));
+        }
+        o.tag = o.tag || div;
+        if (o.ns && Roo.isIE) {
+            ns = false;
+            o.tag = o.ns + ':' + o.tag;
+            
+        }
+        var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
+        var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
+        for(var attr in o){
+            
+            if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
+                    attr == "style" || typeof o[attr] == "function") continue;
+                    
+            if(attr=="cls" && Roo.isIE){
+                el.className = o["cls"];
+            }else{
+                if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
+                else el[attr] = o[attr];
+            }
+        }
+        Roo.DomHelper.applyStyles(el, o.style);
+        var cn = o.children || o.cn;
+        if(cn){
+            //http://bugs.kde.org/show_bug.cgi?id=71506
+             if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
+                for(var i = 0, len = cn.length; i < len; i++) {
+                    createDom(cn[i], el);
+                }
+            }else{
+                createDom(cn, el);
+            }
+        }
+        if(o.html){
+            el.innerHTML = o.html;
+        }
+        if(parentNode){
+           parentNode.appendChild(el);
+        }
+        return el;
+    };
+
+    var ieTable = function(depth, s, h, e){
+        tempTableEl.innerHTML = [s, h, e].join('');
+        var i = -1, el = tempTableEl;
+        while(++i < depth){
+            el = el.firstChild;
+        }
+        return el;
+    };
+
+    // kill repeat to save bytes
+    var ts = '<table>',
+        te = '</table>',
+        tbs = ts+'<tbody>',
+        tbe = '</tbody>'+te,
+        trs = tbs + '<tr>',
+        tre = '</tr>'+tbe;
+
+    /**
+     * @ignore
+     * Nasty code for IE's broken table implementation
+     */
+    var insertIntoTable = function(tag, where, el, html){
+        if(!tempTableEl){
+            tempTableEl = document.createElement('div');
+        }
+        var node;
+        var before = null;
+        if(tag == 'td'){
+            if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
+                return;
+            }
+            if(where == 'beforebegin'){
+                before = el;
+                el = el.parentNode;
+            } else{
+                before = el.nextSibling;
+                el = el.parentNode;
+            }
+            node = ieTable(4, trs, html, tre);
+        }
+        else if(tag == 'tr'){
+            if(where == 'beforebegin'){
+                before = el;
+                el = el.parentNode;
+                node = ieTable(3, tbs, html, tbe);
+            } else if(where == 'afterend'){
+                before = el.nextSibling;
+                el = el.parentNode;
+                node = ieTable(3, tbs, html, tbe);
+            } else{ // INTO a TR
+                if(where == 'afterbegin'){
+                    before = el.firstChild;
+                }
+                node = ieTable(4, trs, html, tre);
+            }
+        } else if(tag == 'tbody'){
+            if(where == 'beforebegin'){
+                before = el;
+                el = el.parentNode;
+                node = ieTable(2, ts, html, te);
+            } else if(where == 'afterend'){
+                before = el.nextSibling;
+                el = el.parentNode;
+                node = ieTable(2, ts, html, te);
+            } else{
+                if(where == 'afterbegin'){
+                    before = el.firstChild;
+                }
+                node = ieTable(3, tbs, html, tbe);
+            }
+        } else{ // TABLE
+            if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
+                return;
+            }
+            if(where == 'afterbegin'){
+                before = el.firstChild;
+            }
+            node = ieTable(2, ts, html, te);
+        }
+        el.insertBefore(node, before);
+        return node;
+    };
+
+    return {
+    /** True to force the use of DOM instead of html fragments @type Boolean */
+    useDom : false,
+
+    /**
+     * Returns the markup for the passed Element(s) config
+     * @param {Object} o The Dom object spec (and children)
+     * @return {String}
+     */
+    markup : function(o){
+        return createHtml(o);
+    },
+
+    /**
+     * Applies a style specification to an element
+     * @param {String/HTMLElement} el The element to apply styles to
+     * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
+     * a function which returns such a specification.
+     */
+    applyStyles : function(el, styles){
+        if(styles){
+           el = Roo.fly(el);
+           if(typeof styles == "string"){
+               var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
+               var matches;
+               while ((matches = re.exec(styles)) != null){
+                   el.setStyle(matches[1], matches[2]);
+               }
+           }else if (typeof styles == "object"){
+               for (var style in styles){
+                  el.setStyle(style, styles[style]);
+               }
+           }else if (typeof styles == "function"){
+                Roo.DomHelper.applyStyles(el, styles.call());
+           }
+        }
+    },
+
+    /**
+     * Inserts an HTML fragment into the Dom
+     * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
+     * @param {HTMLElement} el The context element
+     * @param {String} html The HTML fragmenet
+     * @return {HTMLElement} The new node
+     */
+    insertHtml : function(where, el, html){
+        where = where.toLowerCase();
+        if(el.insertAdjacentHTML){
+            if(tableRe.test(el.tagName)){
+                var rs;
+                if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
+                    return rs;
+                }
+            }
+            switch(where){
+                case "beforebegin":
+                    el.insertAdjacentHTML('BeforeBegin', html);
+                    return el.previousSibling;
+                case "afterbegin":
+                    el.insertAdjacentHTML('AfterBegin', html);
+                    return el.firstChild;
+                case "beforeend":
+                    el.insertAdjacentHTML('BeforeEnd', html);
+                    return el.lastChild;
+                case "afterend":
+                    el.insertAdjacentHTML('AfterEnd', html);
+                    return el.nextSibling;
+            }
+            throw 'Illegal insertion point -> "' + where + '"';
+        }
+        var range = el.ownerDocument.createRange();
+        var frag;
+        switch(where){
+             case "beforebegin":
+                range.setStartBefore(el);
+                frag = range.createContextualFragment(html);
+                el.parentNode.insertBefore(frag, el);
+                return el.previousSibling;
+             case "afterbegin":
+                if(el.firstChild){
+                    range.setStartBefore(el.firstChild);
+                    frag = range.createContextualFragment(html);
+                    el.insertBefore(frag, el.firstChild);
+                    return el.firstChild;
+                }else{
+                    el.innerHTML = html;
+                    return el.firstChild;
+                }
+            case "beforeend":
+                if(el.lastChild){
+                    range.setStartAfter(el.lastChild);
+                    frag = range.createContextualFragment(html);
+                    el.appendChild(frag);
+                    return el.lastChild;
+                }else{
+                    el.innerHTML = html;
+                    return el.lastChild;
+                }
+            case "afterend":
+                range.setStartAfter(el);
+                frag = range.createContextualFragment(html);
+                el.parentNode.insertBefore(frag, el.nextSibling);
+                return el.nextSibling;
+            }
+            throw 'Illegal insertion point -> "' + where + '"';
+    },
+
+    /**
+     * Creates new Dom element(s) and inserts them before el
+     * @param {String/HTMLElement/Element} el The context element
+     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element
+     * @return {HTMLElement/Roo.Element} The new node
+     */
+    insertBefore : function(el, o, returnElement){
+        return this.doInsert(el, o, returnElement, "beforeBegin");
+    },
+
+    /**
+     * Creates new Dom element(s) and inserts them after el
+     * @param {String/HTMLElement/Element} el The context element
+     * @param {Object} o The Dom object spec (and children)
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element
+     * @return {HTMLElement/Roo.Element} The new node
+     */
+    insertAfter : function(el, o, returnElement){
+        return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
+    },
+
+    /**
+     * Creates new Dom element(s) and inserts them as the first child of el
+     * @param {String/HTMLElement/Element} el The context element
+     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element
+     * @return {HTMLElement/Roo.Element} The new node
+     */
+    insertFirst : function(el, o, returnElement){
+        return this.doInsert(el, o, returnElement, "afterBegin");
+    },
+
+    // private
+    doInsert : function(el, o, returnElement, pos, sibling){
+        el = Roo.getDom(el);
+        var newNode;
+        if(this.useDom || o.ns){
+            newNode = createDom(o, null);
+            el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
+        }else{
+            var html = createHtml(o);
+            newNode = this.insertHtml(pos, el, html);
+        }
+        return returnElement ? Roo.get(newNode, true) : newNode;
+    },
+
+    /**
+     * Creates new Dom element(s) and appends them to el
+     * @param {String/HTMLElement/Element} el The context element
+     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element
+     * @return {HTMLElement/Roo.Element} The new node
+     */
+    append : function(el, o, returnElement){
+        el = Roo.getDom(el);
+        var newNode;
+        if(this.useDom || o.ns){
+            newNode = createDom(o, null);
+            el.appendChild(newNode);
+        }else{
+            var html = createHtml(o);
+            newNode = this.insertHtml("beforeEnd", el, html);
+        }
+        return returnElement ? Roo.get(newNode, true) : newNode;
+    },
+
+    /**
+     * Creates new Dom element(s) and overwrites the contents of el with them
+     * @param {String/HTMLElement/Element} el The context element
+     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element
+     * @return {HTMLElement/Roo.Element} The new node
+     */
+    overwrite : function(el, o, returnElement){
+        el = Roo.getDom(el);
+        if (o.ns) {
+          
+            while (el.childNodes.length) {
+                el.removeChild(el.firstChild);
+            }
+            createDom(o, el);
+        } else {
+            el.innerHTML = createHtml(o);   
+        }
+        
+        return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
+    },
+
+    /**
+     * Creates a new Roo.DomHelper.Template from the Dom object spec
+     * @param {Object} o The Dom object spec (and children)
+     * @return {Roo.DomHelper.Template} The new template
+     */
+    createTemplate : function(o){
+        var html = createHtml(o);
+        return new Roo.Template(html);
+    }
+    };
+}();
+/*
+ * 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.Template
+* Represents an HTML fragment template. Templates can be precompiled for greater performance.
+* For a list of available format functions, see {@link Roo.util.Format}.<br />
+* Usage:
+<pre><code>
+var t = new Roo.Template(
+    '&lt;div name="{id}"&gt;',
+        '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
+    '&lt;/div&gt;'
+);
+t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
+</code></pre>
+* For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
+* @constructor
+* @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
+*/
+Roo.Template = function(html){
+    if(html instanceof Array){
+        html = html.join("");
+    }else if(arguments.length > 1){
+        html = Array.prototype.join.call(arguments, "");
+    }
+    /**@private*/
+    this.html = html;
+    
+};
+Roo.Template.prototype = {
+    /**
+     * Returns an HTML fragment of this template with the specified values applied.
+     * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+     * @return {String} The HTML fragment
+     */
+    applyTemplate : function(values){
+        if(this.compiled){
+            return this.compiled(values);
+        }
+        var useF = this.disableFormats !== true;
+        var fm = Roo.util.Format, tpl = this;
+        var fn = function(m, name, format, args){
+            if(format && useF){
+                if(format.substr(0, 5) == "this."){
+                    return tpl.call(format.substr(5), values[name], values);
+                }else{
+                    if(args){
+                        // quoted values are required for strings in compiled templates, 
+                        // but for non compiled we need to strip them
+                        // quoted reversed for jsmin
+                        var re = /^\s*['"](.*)["']\s*$/;
+                        args = args.split(',');
+                        for(var i = 0, len = args.length; i < len; i++){
+                            args[i] = args[i].replace(re, "$1");
+                        }
+                        args = [values[name]].concat(args);
+                    }else{
+                        args = [values[name]];
+                    }
+                    return fm[format].apply(fm, args);
+                }
+            }else{
+                return values[name] !== undefined ? values[name] : "";
+            }
+        };
+        return this.html.replace(this.re, fn);
+    },
+    
+    /**
+     * Sets the HTML used as the template and optionally compiles it.
+     * @param {String} html
+     * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
+     * @return {Roo.Template} this
+     */
+    set : function(html, compile){
+        this.html = html;
+        this.compiled = null;
+        if(compile){
+            this.compile();
+        }
+        return this;
+    },
+    
+    /**
+     * True to disable format functions (defaults to false)
+     * @type Boolean
+     */
+    disableFormats : false,
+    
+    /**
+    * The regular expression used to match template variables 
+    * @type RegExp
+    * @property 
+    */
+    re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
+    
+    /**
+     * Compiles the template into an internal function, eliminating the RegEx overhead.
+     * @return {Roo.Template} this
+     */
+    compile : function(){
+        var fm = Roo.util.Format;
+        var useF = this.disableFormats !== true;
+        var sep = Roo.isGecko ? "+" : ",";
+        var fn = function(m, name, format, args){
+            if(format && useF){
+                args = args ? ',' + args : "";
+                if(format.substr(0, 5) != "this."){
+                    format = "fm." + format + '(';
+                }else{
+                    format = 'this.call("'+ format.substr(5) + '", ';
+                    args = ", values";
+                }
+            }else{
+                args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
+            }
+            return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
+        };
+        var body;
+        // branched to use + in gecko and [].join() in others
+        if(Roo.isGecko){
+            body = "this.compiled = function(values){ return '" +
+                   this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
+                    "';};";
+        }else{
+            body = ["this.compiled = function(values){ return ['"];
+            body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
+            body.push("'].join('');};");
+            body = body.join('');
+        }
+        /**
+         * eval:var:values
+         * eval:var:fm
+         */
+        eval(body);
+        return this;
+    },
+    
+    // private function used to call members
+    call : function(fnName, value, allValues){
+        return this[fnName](value, allValues);
+    },
+    
+    /**
+     * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
+     * @param {String/HTMLElement/Roo.Element} el The context element
+     * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
+     * @return {HTMLElement/Roo.Element} The new node or Element
+     */
+    insertFirst: function(el, values, returnElement){
+        return this.doInsert('afterBegin', el, values, returnElement);
+    },
+
+    /**
+     * Applies the supplied values to the template and inserts the new node(s) before el.
+     * @param {String/HTMLElement/Roo.Element} el The context element
+     * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
+     * @return {HTMLElement/Roo.Element} The new node or Element
+     */
+    insertBefore: function(el, values, returnElement){
+        return this.doInsert('beforeBegin', el, values, returnElement);
+    },
+
+    /**
+     * Applies the supplied values to the template and inserts the new node(s) after el.
+     * @param {String/HTMLElement/Roo.Element} el The context element
+     * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
+     * @return {HTMLElement/Roo.Element} The new node or Element
+     */
+    insertAfter : function(el, values, returnElement){
+        return this.doInsert('afterEnd', el, values, returnElement);
+    },
+    
+    /**
+     * Applies the supplied values to the template and appends the new node(s) to el.
+     * @param {String/HTMLElement/Roo.Element} el The context element
+     * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
+     * @return {HTMLElement/Roo.Element} The new node or Element
+     */
+    append : function(el, values, returnElement){
+        return this.doInsert('beforeEnd', el, values, returnElement);
+    },
+
+    doInsert : function(where, el, values, returnEl){
+        el = Roo.getDom(el);
+        var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
+        return returnEl ? Roo.get(newNode, true) : newNode;
+    },
+
+    /**
+     * Applies the supplied values to the template and overwrites the content of el with the new node(s).
+     * @param {String/HTMLElement/Roo.Element} el The context element
+     * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+     * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
+     * @return {HTMLElement/Roo.Element} The new node or Element
+     */
+    overwrite : function(el, values, returnElement){
+        el = Roo.getDom(el);
+        el.innerHTML = this.applyTemplate(values);
+        return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
+    }
+};
+/**
+ * Alias for {@link #applyTemplate}
+ * @method
+ */
+Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
+
+// backwards compat
+Roo.DomHelper.Template = Roo.Template;
+
+/**
+ * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
+ * @param {String/HTMLElement} el A DOM element or its id
+ * @returns {Roo.Template} The created template
+ * @static
+ */
+Roo.Template.from = function(el){
+    el = Roo.getDom(el);
+    return new Roo.Template(el.value || el.innerHTML);
+};/*
+ * 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 is code is also distributed under MIT license for use
+ * with jQuery and prototype JavaScript libraries.
+ */
+/**
+ * @class Roo.DomQuery
+Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
+<p>
+DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
+
+<p>
+All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
+</p>
+<h4>Element Selectors:</h4>
+<ul class="list">
+    <li> <b>*</b> any element</li>
+    <li> <b>E</b> an element with the tag E</li>
+    <li> <b>E F</b> All descendent elements of E that have the tag F</li>
+    <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
+    <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
+    <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
+</ul>
+<h4>Attribute Selectors:</h4>
+<p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
+<ul class="list">
+    <li> <b>E[foo]</b> has an attribute "foo"</li>
+    <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
+    <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
+    <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
+    <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
+    <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
+    <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
+</ul>
+<h4>Pseudo Classes:</h4>
+<ul class="list">
+    <li> <b>E:first-child</b> E is the first child of its parent</li>
+    <li> <b>E:last-child</b> E is the last child of its parent</li>
+    <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
+    <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
+    <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
+    <li> <b>E:only-child</b> E is the only child of its parent</li>
+    <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
+    <li> <b>E:first</b> the first E in the resultset</li>
+    <li> <b>E:last</b> the last E in the resultset</li>
+    <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
+    <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
+    <li> <b>E:even</b> shortcut for :nth-child(even)</li>
+    <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
+    <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
+    <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
+    <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
+    <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
+    <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
+</ul>
+<h4>CSS Value Selectors:</h4>
+<ul class="list">
+    <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
+    <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
+    <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
+    <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
+    <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
+    <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
+</ul>
+ * @singleton
+ */
+Roo.DomQuery = function(){
+    var cache = {}, simpleCache = {}, valueCache = {};
+    var nonSpace = /\S/;
+    var trimRe = /^\s+|\s+$/g;
+    var tplRe = /\{(\d+)\}/g;
+    var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
+    var tagTokenRe = /^(#)?([\w-\*]+)/;
+    var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
+
+    function child(p, index){
+        var i = 0;
+        var n = p.firstChild;
+        while(n){
+            if(n.nodeType == 1){
+               if(++i == index){
+                   return n;
+               }
+            }
+            n = n.nextSibling;
+        }
+        return null;
+    };
+
+    function next(n){
+        while((n = n.nextSibling) && n.nodeType != 1);
+        return n;
+    };
+
+    function prev(n){
+        while((n = n.previousSibling) && n.nodeType != 1);
+        return n;
+    };
+
+    function children(d){
+        var n = d.firstChild, ni = -1;
+           while(n){
+               var nx = n.nextSibling;
+               if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
+                   d.removeChild(n);
+               }else{
+                   n.nodeIndex = ++ni;
+               }
+               n = nx;
+           }
+           return this;
+       };
+
+    function byClassName(c, a, v){
+        if(!v){
+            return c;
+        }
+        var r = [], ri = -1, cn;
+        for(var i = 0, ci; ci = c[i]; i++){
+            if((' '+ci.className+' ').indexOf(v) != -1){
+                r[++ri] = ci;
+            }
+        }
+        return r;
+    };
+
+    function attrValue(n, attr){
+        if(!n.tagName && typeof n.length != "undefined"){
+            n = n[0];
+        }
+        if(!n){
+            return null;
+        }
+        if(attr == "for"){
+            return n.htmlFor;
+        }
+        if(attr == "class" || attr == "className"){
+            return n.className;
+        }
+        return n.getAttribute(attr) || n[attr];
+
+    };
+
+    function getNodes(ns, mode, tagName){
+        var result = [], ri = -1, cs;
+        if(!ns){
+            return result;
+        }
+        tagName = tagName || "*";
+        if(typeof ns.getElementsByTagName != "undefined"){
+            ns = [ns];
+        }
+        if(!mode){
+            for(var i = 0, ni; ni = ns[i]; i++){
+                cs = ni.getElementsByTagName(tagName);
+                for(var j = 0, ci; ci = cs[j]; j++){
+                    result[++ri] = ci;
+                }
+            }
+        }else if(mode == "/" || mode == ">"){
+            var utag = tagName.toUpperCase();
+            for(var i = 0, ni, cn; ni = ns[i]; i++){
+                cn = ni.children || ni.childNodes;
+                for(var j = 0, cj; cj = cn[j]; j++){
+                    if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
+                        result[++ri] = cj;
+                    }
+                }
+            }
+        }else if(mode == "+"){
+            var utag = tagName.toUpperCase();
+            for(var i = 0, n; n = ns[i]; i++){
+                while((n = n.nextSibling) && n.nodeType != 1);
+                if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
+                    result[++ri] = n;
+                }
+            }
+        }else if(mode == "~"){
+            for(var i = 0, n; n = ns[i]; i++){
+                while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
+                if(n){
+                    result[++ri] = n;
+                }
+            }
+        }
+        return result;
+    };
+
+    function concat(a, b){
+        if(b.slice){
+            return a.concat(b);
+        }
+        for(var i = 0, l = b.length; i < l; i++){
+            a[a.length] = b[i];
+        }
+        return a;
+    }
+
+    function byTag(cs, tagName){
+        if(cs.tagName || cs == document){
+            cs = [cs];
+        }
+        if(!tagName){
+            return cs;
+        }
+        var r = [], ri = -1;
+        tagName = tagName.toLowerCase();
+        for(var i = 0, ci; ci = cs[i]; i++){
+            if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
+                r[++ri] = ci;
+            }
+        }
+        return r;
+    };
+
+    function byId(cs, attr, id){
+        if(cs.tagName || cs == document){
+            cs = [cs];
+        }
+        if(!id){
+            return cs;
+        }
+        var r = [], ri = -1;
+        for(var i = 0,ci; ci = cs[i]; i++){
+            if(ci && ci.id == id){
+                r[++ri] = ci;
+                return r;
+            }
+        }
+        return r;
+    };
+
+    function byAttribute(cs, attr, value, op, custom){
+        var r = [], ri = -1, st = custom=="{";
+        var f = Roo.DomQuery.operators[op];
+        for(var i = 0, ci; ci = cs[i]; i++){
+            var a;
+            if(st){
+                a = Roo.DomQuery.getStyle(ci, attr);
+            }
+            else if(attr == "class" || attr == "className"){
+                a = ci.className;
+            }else if(attr == "for"){
+                a = ci.htmlFor;
+            }else if(attr == "href"){
+                a = ci.getAttribute("href", 2);
+            }else{
+                a = ci.getAttribute(attr);
+            }
+            if((f && f(a, value)) || (!f && a)){
+                r[++ri] = ci;
+            }
+        }
+        return r;
+    };
+
+    function byPseudo(cs, name, value){
+        return Roo.DomQuery.pseudos[name](cs, value);
+    };
+
+    // This is for IE MSXML which does not support expandos.
+    // IE runs the same speed using setAttribute, however FF slows way down
+    // and Safari completely fails so they need to continue to use expandos.
+    var isIE = window.ActiveXObject ? true : false;
+
+    // this eval is stop the compressor from
+    // renaming the variable to something shorter
+    
+    /** eval:var:batch */
+    var batch = 30803; 
+
+    var key = 30803;
+
+    function nodupIEXml(cs){
+        var d = ++key;
+        cs[0].setAttribute("_nodup", d);
+        var r = [cs[0]];
+        for(var i = 1, len = cs.length; i < len; i++){
+            var c = cs[i];
+            if(!c.getAttribute("_nodup") != d){
+                c.setAttribute("_nodup", d);
+                r[r.length] = c;
+            }
+        }
+        for(var i = 0, len = cs.length; i < len; i++){
+            cs[i].removeAttribute("_nodup");
+        }
+        return r;
+    }
+
+    function nodup(cs){
+        if(!cs){
+            return [];
+        }
+        var len = cs.length, c, i, r = cs, cj, ri = -1;
+        if(!len || typeof cs.nodeType != "undefined" || len == 1){
+            return cs;
+        }
+        if(isIE && typeof cs[0].selectSingleNode != "undefined"){
+            return nodupIEXml(cs);
+        }
+        var d = ++key;
+        cs[0]._nodup = d;
+        for(i = 1; c = cs[i]; i++){
+            if(c._nodup != d){
+                c._nodup = d;
+            }else{
+                r = [];
+                for(var j = 0; j < i; j++){
+                    r[++ri] = cs[j];
+                }
+                for(j = i+1; cj = cs[j]; j++){
+                    if(cj._nodup != d){
+                        cj._nodup = d;
+                        r[++ri] = cj;
+                    }
+                }
+                return r;
+            }
+        }
+        return r;
+    }
+
+    function quickDiffIEXml(c1, c2){
+        var d = ++key;
+        for(var i = 0, len = c1.length; i < len; i++){
+            c1[i].setAttribute("_qdiff", d);
+        }
+        var r = [];
+        for(var i = 0, len = c2.length; i < len; i++){
+            if(c2[i].getAttribute("_qdiff") != d){
+                r[r.length] = c2[i];
+            }
+        }
+        for(var i = 0, len = c1.length; i < len; i++){
+           c1[i].removeAttribute("_qdiff");
+        }
+        return r;
+    }
+
+    function quickDiff(c1, c2){
+        var len1 = c1.length;
+        if(!len1){
+            return c2;
+        }
+        if(isIE && c1[0].selectSingleNode){
+            return quickDiffIEXml(c1, c2);
+        }
+        var d = ++key;
+        for(var i = 0; i < len1; i++){
+            c1[i]._qdiff = d;
+        }
+        var r = [];
+        for(var i = 0, len = c2.length; i < len; i++){
+            if(c2[i]._qdiff != d){
+                r[r.length] = c2[i];
+            }
+        }
+        return r;
+    }
+
+    function quickId(ns, mode, root, id){
+        if(ns == root){
+           var d = root.ownerDocument || root;
+           return d.getElementById(id);
+        }
+        ns = getNodes(ns, mode, "*");
+        return byId(ns, null, id);
+    }
+
+    return {
+        getStyle : function(el, name){
+            return Roo.fly(el).getStyle(name);
+        },
+        /**
+         * Compiles a selector/xpath query into a reusable function. The returned function
+         * takes one parameter "root" (optional), which is the context node from where the query should start.
+         * @param {String} selector The selector/xpath query
+         * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
+         * @return {Function}
+         */
+        compile : function(path, type){
+            type = type || "select";
+            
+            var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
+            var q = path, mode, lq;
+            var tk = Roo.DomQuery.matchers;
+            var tklen = tk.length;
+            var mm;
+
+            // accept leading mode switch
+            var lmode = q.match(modeRe);
+            if(lmode && lmode[1]){
+                fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
+                q = q.replace(lmode[1], "");
+            }
+            // strip leading slashes
+            while(path.substr(0, 1)=="/"){
+                path = path.substr(1);
+            }
+
+            while(q && lq != q){
+                lq = q;
+                var tm = q.match(tagTokenRe);
+                if(type == "select"){
+                    if(tm){
+                        if(tm[1] == "#"){
+                            fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
+                        }else{
+                            fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
+                        }
+                        q = q.replace(tm[0], "");
+                    }else if(q.substr(0, 1) != '@'){
+                        fn[fn.length] = 'n = getNodes(n, mode, "*");';
+                    }
+                }else{
+                    if(tm){
+                        if(tm[1] == "#"){
+                            fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
+                        }else{
+                            fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
+                        }
+                        q = q.replace(tm[0], "");
+                    }
+                }
+                while(!(mm = q.match(modeRe))){
+                    var matched = false;
+                    for(var j = 0; j < tklen; j++){
+                        var t = tk[j];
+                        var m = q.match(t.re);
+                        if(m){
+                            fn[fn.length] = t.select.replace(tplRe, function(x, i){
+                                                    return m[i];
+                                                });
+                            q = q.replace(m[0], "");
+                            matched = true;
+                            break;
+                        }
+                    }
+                    // prevent infinite loop on bad selector
+                    if(!matched){
+                        throw 'Error parsing selector, parsing failed at "' + q + '"';
+                    }
+                }
+                if(mm[1]){
+                    fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
+                    q = q.replace(mm[1], "");
+                }
+            }
+            fn[fn.length] = "return nodup(n);\n}";
+            
+             /** 
+              * list of variables that need from compression as they are used by eval.
+             *  eval:var:batch 
+             *  eval:var:nodup
+             *  eval:var:byTag
+             *  eval:var:ById
+             *  eval:var:getNodes
+             *  eval:var:quickId
+             *  eval:var:mode
+             *  eval:var:root
+             *  eval:var:n
+             *  eval:var:byClassName
+             *  eval:var:byPseudo
+             *  eval:var:byAttribute
+             *  eval:var:attrValue
+             * 
+             **/ 
+            eval(fn.join(""));
+            return f;
+        },
+
+        /**
+         * Selects a group of elements.
+         * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
+         * @param {Node} root (optional) The start of the query (defaults to document).
+         * @return {Array}
+         */
+        select : function(path, root, type){
+            if(!root || root == document){
+                root = document;
+            }
+            if(typeof root == "string"){
+                root = document.getElementById(root);
+            }
+            var paths = path.split(",");
+            var results = [];
+            for(var i = 0, len = paths.length; i < len; i++){
+                var p = paths[i].replace(trimRe, "");
+                if(!cache[p]){
+                    cache[p] = Roo.DomQuery.compile(p);
+                    if(!cache[p]){
+                        throw p + " is not a valid selector";
+                    }
+                }
+                var result = cache[p](root);
+                if(result && result != document){
+                    results = results.concat(result);
+                }
+            }
+            if(paths.length > 1){
+                return nodup(results);
+            }
+            return results;
+        },
+
+        /**
+         * Selects a single element.
+         * @param {String} selector The selector/xpath query
+         * @param {Node} root (optional) The start of the query (defaults to document).
+         * @return {Element}
+         */
+        selectNode : function(path, root){
+            return Roo.DomQuery.select(path, root)[0];
+        },
+
+        /**
+         * Selects the value of a node, optionally replacing null with the defaultValue.
+         * @param {String} selector The selector/xpath query
+         * @param {Node} root (optional) The start of the query (defaults to document).
+         * @param {String} defaultValue
+         */
+        selectValue : function(path, root, defaultValue){
+            path = path.replace(trimRe, "");
+            if(!valueCache[path]){
+                valueCache[path] = Roo.DomQuery.compile(path, "select");
+            }
+            var n = valueCache[path](root);
+            n = n[0] ? n[0] : n;
+            var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
+            return ((v === null||v === undefined||v==='') ? defaultValue : v);
+        },
+
+        /**
+         * Selects the value of a node, parsing integers and floats.
+         * @param {String} selector The selector/xpath query
+         * @param {Node} root (optional) The start of the query (defaults to document).
+         * @param {Number} defaultValue
+         * @return {Number}
+         */
+        selectNumber : function(path, root, defaultValue){
+            var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
+            return parseFloat(v);
+        },
+
+        /**
+         * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
+         * @param {String/HTMLElement/Array} el An element id, element or array of elements
+         * @param {String} selector The simple selector to test
+         * @return {Boolean}
+         */
+        is : function(el, ss){
+            if(typeof el == "string"){
+                el = document.getElementById(el);
+            }
+            var isArray = (el instanceof Array);
+            var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
+            return isArray ? (result.length == el.length) : (result.length > 0);
+        },
+
+        /**
+         * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
+         * @param {Array} el An array of elements to filter
+         * @param {String} selector The simple selector to test
+         * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
+         * the selector instead of the ones that match
+         * @return {Array}
+         */
+        filter : function(els, ss, nonMatches){
+            ss = ss.replace(trimRe, "");
+            if(!simpleCache[ss]){
+                simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
+            }
+            var result = simpleCache[ss](els);
+            return nonMatches ? quickDiff(result, els) : result;
+        },
+
+        /**
+         * Collection of matching regular expressions and code snippets.
+         */
+        matchers : [{
+                re: /^\.([\w-]+)/,
+                select: 'n = byClassName(n, null, " {1} ");'
+            }, {
+                re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
+                select: 'n = byPseudo(n, "{1}", "{2}");'
+            },{
+                re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
+                select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
+            }, {
+                re: /^#([\w-]+)/,
+                select: 'n = byId(n, null, "{1}");'
+            },{
+                re: /^@([\w-]+)/,
+                select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
+            }
+        ],
+
+        /**
+         * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
+         * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
+         */
+        operators : {
+            "=" : function(a, v){
+                return a == v;
+            },
+            "!=" : function(a, v){
+                return a != v;
+            },
+            "^=" : function(a, v){
+                return a && a.substr(0, v.length) == v;
+            },
+            "$=" : function(a, v){
+                return a && a.substr(a.length-v.length) == v;
+            },
+            "*=" : function(a, v){
+                return a && a.indexOf(v) !== -1;
+            },
+            "%=" : function(a, v){
+                return (a % v) == 0;
+            },
+            "|=" : function(a, v){
+                return a && (a == v || a.substr(0, v.length+1) == v+'-');
+            },
+            "~=" : function(a, v){
+                return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
+            }
+        },
+
+        /**
+         * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
+         * and the argument (if any) supplied in the selector.
+         */
+        pseudos : {
+            "first-child" : function(c){
+                var r = [], ri = -1, n;
+                for(var i = 0, ci; ci = n = c[i]; i++){
+                    while((n = n.previousSibling) && n.nodeType != 1);
+                    if(!n){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "last-child" : function(c){
+                var r = [], ri = -1, n;
+                for(var i = 0, ci; ci = n = c[i]; i++){
+                    while((n = n.nextSibling) && n.nodeType != 1);
+                    if(!n){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "nth-child" : function(c, a) {
+                var r = [], ri = -1;
+                var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
+                var f = (m[1] || 1) - 0, l = m[2] - 0;
+                for(var i = 0, n; n = c[i]; i++){
+                    var pn = n.parentNode;
+                    if (batch != pn._batch) {
+                        var j = 0;
+                        for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
+                            if(cn.nodeType == 1){
+                               cn.nodeIndex = ++j;
+                            }
+                        }
+                        pn._batch = batch;
+                    }
+                    if (f == 1) {
+                        if (l == 0 || n.nodeIndex == l){
+                            r[++ri] = n;
+                        }
+                    } else if ((n.nodeIndex + l) % f == 0){
+                        r[++ri] = n;
+                    }
+                }
+
+                return r;
+            },
+
+            "only-child" : function(c){
+                var r = [], ri = -1;;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    if(!prev(ci) && !next(ci)){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "empty" : function(c){
+                var r = [], ri = -1;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    var cns = ci.childNodes, j = 0, cn, empty = true;
+                    while(cn = cns[j]){
+                        ++j;
+                        if(cn.nodeType == 1 || cn.nodeType == 3){
+                            empty = false;
+                            break;
+                        }
+                    }
+                    if(empty){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "contains" : function(c, v){
+                var r = [], ri = -1;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "nodeValue" : function(c, v){
+                var r = [], ri = -1;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    if(ci.firstChild && ci.firstChild.nodeValue == v){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "checked" : function(c){
+                var r = [], ri = -1;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    if(ci.checked == true){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "not" : function(c, ss){
+                return Roo.DomQuery.filter(c, ss, true);
+            },
+
+            "odd" : function(c){
+                return this["nth-child"](c, "odd");
+            },
+
+            "even" : function(c){
+                return this["nth-child"](c, "even");
+            },
+
+            "nth" : function(c, a){
+                return c[a-1] || [];
+            },
+
+            "first" : function(c){
+                return c[0] || [];
+            },
+
+            "last" : function(c){
+                return c[c.length-1] || [];
+            },
+
+            "has" : function(c, ss){
+                var s = Roo.DomQuery.select;
+                var r = [], ri = -1;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    if(s(ss, ci).length > 0){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "next" : function(c, ss){
+                var is = Roo.DomQuery.is;
+                var r = [], ri = -1;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    var n = next(ci);
+                    if(n && is(n, ss)){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            },
+
+            "prev" : function(c, ss){
+                var is = Roo.DomQuery.is;
+                var r = [], ri = -1;
+                for(var i = 0, ci; ci = c[i]; i++){
+                    var n = prev(ci);
+                    if(n && is(n, ss)){
+                        r[++ri] = ci;
+                    }
+                }
+                return r;
+            }
+        }
+    };
+}();
+
+/**
+ * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
+ * @param {String} path The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @return {Array}
+ * @member Roo
+ * @method query
+ */
+Roo.query = Roo.DomQuery.select;