text: /**
   * jQuery Templates
   *
   * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
   * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
   *
   * Written by: Stan Lemon <stanlemon@mac.com>
   *
   * Based off of the Ext.Template library, available at:
   * http://www.extjs.com
   *
   * This library provides basic templating functionality, allowing for macro-based
   * templates within jQuery.
   *
   * Basic Usage:
   *
   * var t = $.template('<div id="foo">Hello ${name}, how are you ${question}?  I am ${me:substr(0,10)}</div>');
   *
   * $(selector).append( t , {
   *     name: 'Stan',
   *     question: 'feeling',
   *     me: 'doing quite well myself, thank you very much!'
   * });
   *
   * Requires: jQuery 1.2+
   *
   *
   * @todo    Add callbacks to the DOM manipulation methods, so that events can be bound
   *          to template nodes after creation.
   */
  (function ($) {
      
      /**
       * Create a New Template
       */
      $.template = function (html, options) {
          return new $.template.instance(html, options);
      };
  
      /**
       * Template constructor - Creates a new template instance.
       *
       * @param   html    The string of HTML to be used for the template.
       * @param   options An object of configurable options.  Currently
       *          you can toggle compile as a boolean value and set a custom
       *          template regular expression on the property regx by
       *          specifying the key of the regx to use from the regx object.
       */
      $.template.instance = function (html, options) {
          // If a custom regular expression has been set, grab it from the regx object
          if (options && options.regx) {
              options.regx = this.regx[options.regx];
          }
  
          this.options = $.extend({
              compile:        false,
              regx:           this.regx.standard
          }, options || {});
  
          this.html = html;
  
          if (this.options.compile) {
              this.compile();   
          }
          this.isTemplate = true;
      };
  
      /**
       * Regular Expression for Finding Variables
       *
       * The default pattern looks for variables in JSP style, the form of: ${variable}
       * There are also regular expressions available for ext-style variables and
       * jTemplate style variables.
       *
       * You can add your own regular expressions for variable ussage by doing.
       * $.extend({ $.template.re , {
       *     myvartype: /...../g
       * }
       *
       * Then when creating a template do:
       * var t = $.template("<div>...</div>", { regx: 'myvartype' });
       */
      $.template.regx = $.template.instance.prototype.regx = {
          /*jslint regexp: false */
          jsp:        /\$\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
          ext:        /\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
          jtemplates: /\{\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}\}/g
      };
      
      /**
       * Set the standard regular expression to be used.
       */
      $.template.regx.standard = $.template.regx.jsp;
      
      /**
       * Variable Helper Methods
       *
       * This is a collection of methods which can be used within the variable syntax, ie:
       * ${variable:substr(0,30)} Which would only print a substring, 30 characters in length
       * begining at the first character for the variable named "variable".
       *
       * A basic substring helper is provided as an example of how you can define helpers.
       * To add more helpers simply do:
       * $.extend( $.template.helpers , {
       *   sampleHelper: function() { ... }   
       * });
       */
      $.template.helpers = $.template.instance.prototype.helpers = {
          substr : function (value, start, length) {
              return String(value).substr(start, length);
          }
      };
  
  
      /**
       * Template Instance Methods
       */
      $.extend($.template.instance.prototype, {
          
          /**
           * Apply Values to a Template
           *
           * This is the macro-work horse of the library, it receives an object
           * and the properties of that objects are assigned to the template, where
           * the variables in the template represent keys within the object itself.
           *
           * @param   values  An object of properties mapped to template variables
           */
          apply: function (values) {
              if (this.options.compile) {
                  return this.compiled(values);
              } else {
                  var tpl = this;
                  var fm = this.helpers;
  
                  var fn = function (m, name, format, args) {
                      if (format) {
                          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.options.regx, fn);
              }
          },
  
          /**
           * Compile a template for speedier usage
           */
          compile: function () {
              var sep = $.browser.mozilla ? "+" : ",";
              var fm = this.helpers;
  
              var fn = function (m, name, format, args) {
                  if (format) {
                      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;
  
              if ($.browser.mozilla) {
                  body = "this.compiled = function(values){ return '" +
                         this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.options.regx, fn) +
                          "';};";
              } else {
                  body = ["this.compiled = function(values){ return ['"];
                  body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.options.regx, fn));
                  body.push("'].join('');};");
                  body = body.join('');
              }
              /*jslint evil: true */
              eval(body);
              return this;
          }
      });
  
  
      /**
       * Save a reference in this local scope to the original methods which we're 
       * going to overload.
       **/
      var $_old = {
          domManip: $.fn.domManip,
          text: $.fn.text,
          html: $.fn.html
      };
  
      /**
       * Overwrite the domManip method so that we can use things like append() by passing a 
       * template object and macro parameters.
       */
      $.fn.domManip = function (args, table, reverse, callback) {
          if (args[0].isTemplate) {
              // Apply the template and it's arguments...
              args[0] = args[0].apply(args[1]);
              // Get rid of the arguements, we don't want to pass them on
              delete args[1];
          }
  
          // Call the original method
          var r = $_old.domManip.apply(this, arguments);
  
          return r;
      };
  
      /**
       * Overwrite the html() method
       */
      $.fn.html = function (value, o) {
          if (value && value.isTemplate) {
              value = value.apply(o);
          }
  
          var r = $_old.html.apply(this, [value]);
  
          return r;
      };
      
      /**
       * Overwrite the text() method
       */
      $.fn.text = function (value, o) {
          if (value && value.isTemplate) {
              value = value.apply(o);
          }
  
          var r = $_old.text.apply(this, [value]);
  
          return r;
      };
  
  }(jQuery));
  