    /*!
     * Ext JS Library 3.2.1
     * Copyright(c) 2006-2010 Ext JS, Inc.
     * licensing@extjs.com
     * http://www.extjs.com/license
     */
    /**
     * @class Ext.Template
     * Represents an HTML fragment template. Templates may be {@link #compile precompiled}
     * for greater performance.
     * For example usage {@link #Template see the constructor}.
     *
     * @constructor
     * An instance of this class may be created by passing to the constructor either
     * a single argument, or multiple arguments:
     *
     * single argument : String/Array
     *
     * The single argument may be either a String or an Array:
     * String :
    var t = new Ext.Template("<div>Hello {0}.</div>");
    t.{@link #append}('some-element', ['foo']);
     *
     * Array :
     * An Array will be combined with join('').

    var t = new Ext.Template([
        '<div name="{id}">',
            '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
        '</div>',
    ]);
    t.{@link #compile}();
    t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});

     *
     * multiple arguments : String, Object, Array, ...
     *
     * Multiple arguments will be combined with join('').
     *
    var t = new Ext.Template(
        '<div name="{id}">',
            '<span class="{cls}">{name} {value}</span>',
        '</div>',
        // a configuration object:
        {
            compiled: true,      // {@link #compile} immediately
            disableFormats: true // See Notes below.
        }
    );
     *
     * Notes:
     *
     * Formatting and disableFormats are not applicable for Ext Core.
     * For a list of available format functions, see {@link Ext.util.Format}.
     * disableFormats reduces {@link #apply} time
     * when no formatting is required.
     *
     *
     *
     * @param {Mixed} config
     */
    Ext.Template = function(html){
        var me = this,
            a = arguments,
            buf = [],
            v;

        if (Ext.isArray(html)) {
            html = html.join("");
        } else if (a.length > 1) {
            for(var i = 0, len = a.length; i < len; i++){
                v = a[i];
                if(typeof v == 'object'){
                    Ext.apply(me, v);
                } else {
                    buf.push(v);
                }
            };
            html = buf.join('');
        }

        /**@private*/
        me.html = html;
        /**
         * @cfg {Boolean} compiled Specify true to compile the template
         * immediately (see {@link #compile}).
         * Defaults to false.
         */
        if (me.compiled) {
            me.compile();
        }
    };
    Ext.Template.prototype = {
        /**
         * @cfg {RegExp} re The regular expression used to match template variables.
         * Defaults to:
         * re : /\{([\w-]+)\}/g                                     // for Ext Core
         * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g      // for Ext JS
         *
         */
        re : /\{([\w-]+)\}/g,
        /**
         * See {@link #re}.
         * @type RegExp
         * @property re
         */

        /**
         * Returns an HTML fragment of this template with the specified values applied.
         * @param {Object/Array} values
         * The template values. Can be an array if the params are numeric (i.e. {0})
         * or an object (i.e. {foo: 'bar'}).
         * @return {String} The HTML fragment
         */
        applyTemplate : function(values){
            var me = this;

            return me.compiled ?
                    me.compiled(values) :
                    me.html.replace(me.re, function(m, name){
                        return values[name] !== undefined ? values[name] : "";
                    });
        },

        /**
         * Sets the HTML used as the template and optionally compiles it.
         * @param {String} html
         * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
         * @return {Ext.Template} this
         */
        set : function(html, compile){
            var me = this;
            me.html = html;
            me.compiled = null;
            return compile ? me.compile() : me;
        },

        /**
         * Compiles the template into an internal function, eliminating the RegEx overhead.
         * @return {Ext.Template} this
         */
        compile : function(){
            var me = this,
                sep = Ext.isGecko ? "+" : ",";

            function fn(m, name){
                name = "values['" + name + "']";
                return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
            }

            eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
                 me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
                 (Ext.isGecko ?  "';};" : "'].join('');};"));
            return me;
        },

        /**
         * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
         * @param {Mixed} el The context element
         * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
         * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
         * @return {HTMLElement/Ext.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 {Mixed} el The context element
         * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
         * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
         * @return {HTMLElement/Ext.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 {Mixed} el The context element
         * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
         * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
         * @return {HTMLElement/Ext.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 the specified el.
         * For example usage {@link #Template see the constructor}.
         * @param {Mixed} el The context element
         * @param {Object/Array} values
         * The template values. Can be an array if the params are numeric (i.e. {0})
         * or an object (i.e. {foo: 'bar'}).
         * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
         * @return {HTMLElement/Ext.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 = Ext.getDom(el);
            var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
            return returnEl ? Ext.get(newNode, true) : newNode;
        },

        /**
         * Applies the supplied values to the template and overwrites the content of el with the new node(s).
         * @param {Mixed} el The context element
         * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
         * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
         * @return {HTMLElement/Ext.Element} The new node or Element
         */
        overwrite : function(el, values, returnElement){
            el = Ext.getDom(el);
            el.innerHTML = this.applyTemplate(values);
            return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
        }
    };
    /**
     * Alias for {@link #applyTemplate}
     * Returns an HTML fragment of this template with the specified values applied.
     * @param {Object/Array} values
     * The template values. Can be an array if the params are numeric (i.e. {0})
     * or an object (i.e. {foo: 'bar'}).
     * @return {String} The HTML fragment
     * @member Ext.Template
     * @method apply
     */
    Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;

    /**
     * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML.
     * @param {String/HTMLElement} el A DOM element or its id
     * @param {Object} config A configuration object
     * @return {Ext.Template} The created template
     * @static
     */
    Ext.Template.from = function(el, config){
        el = Ext.getDom(el);
        return new Ext.Template(el.value || el.innerHTML, config || '');
    };