Javascript templating shootoff (extended)

JavaScript performance comparison

Revision 50 of this test case created

Info

Many engines gathered across all revisions of the original shoot off.

DO NOT LINK TO RAW.GITHUB.COM -- It will NOT work in latest firefox versions

Please:

Libraries (in no particular order):

Preparation code

<!---------------------------------------->
<!-- EXTERNAL LIBRARIES HOSTED BY A CDN -->
<!---------------------------------------->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://jashkenas.github.com/coffee-script/extras/coffee-script.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="https://github.com/downloads/wycats/handlebars.js/handlebars-1.0.0.beta.6.js"></script>
<script src="http://cdn.kendostatic.com/2011.2.804/js/kendo.all.min.js"></script>
<script src="http://twitter.github.com/hogan.js/builds/1.0.3/hogan.js"></script>
<script src="http://beebole.com/pure/wp-content/themes/BeeBole-pure/libs/pure.js"></script>
<script src="http://linkedin.github.com/dustjs/dist/dust-full-1.0.0.js"></script>
<script src="http://sstephenson.github.com/eco/dist/eco.js"></script>
<script src="http://embeddedjs.com/javascripts/ejs_production.js"></script>
<script src="https://github.com/downloads/donyantony/cdnjs/runtime.min.js"></script>
<script src="http://terrainformatica.com/kite/kite.js"></script>
<script src="http://borismoore.github.com/jsrender/jsrender.js"></script>
<script src="http://satchmorun.github.com/mote/mote.js"></script>
<script src="http://sandbox.thewikies.com/test/template.js"></script>
<script src="http://getify.github.com/grips/deploy_0.2.4-a/grips-full.min.js"></script>

<!--------------------------->
<!-- DOM TEMPLATES         -->
<!--------------------------->
<div class="pure">
        <h1 class='header'></h1>
        <h2 class='header2'></h2>
        <h3 class='header3'></h3>
        <h4 class='header4'></h4>
        <h5 class='header5'></h5>
        <h6 class='header6'></h6>
</div>

<script>
/****************************************
 MASTER TEMPLATE DATA
 ****************************************/
window.tpl = {};
window.tpl.vars = {
   header: "Header",
   header2: "Header2",
   header3: "Header3",
   header4: "Header4",
   header5: "Header5",
   header6: "Header6",
   list: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
};
window.tpl.vars2 = {
   header: "Header",
   header2: "Header2",
   header3: "Header3",
   header4: "Header4",
   header5: "Header5",
   header6: "Header6",
   list: [{i:'1'}, {i:'2'}, {i:'3'}, {i:'4'}, {i:'5'}, {i:'6'}, {i:'7'}, {i:'8'}, {i:'9'}, {i:'10'}]
};  

/****************************************
 TEMPLATE ENGINES NOT HOSTED BY A CDN (github)
 ****************************************/
//Please minify any hard included library and note the version.

//Resig Template Function (modified to support ')
function rtmpl(a){var b="var p=[];"+"with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").replace(/'(?=[^#]*#>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<#=(.+?)#>/g,"',$1,'").split("<#").join("');").split("#>").join("p.push('")+"');}return p.join('');";return new Function("obj",b)}

//Resig modified template function (no "with" block)
function rtmpl2(a){var b="var p=[];"+"p.push('"+a.replace(/[\r\t\n]/g," ").replace(/'(?=[^#]*#>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<#=(.+?)#>/g,"',$1,'").split("<#").join("');").split("#>").join("p.push('")+"');return p.join('');";return new Function("data",b)}

//Mustache 5.0 dev
var Mustache=(typeof module!=="undefined"&&module.exports)||{};(function(w){w.name="mustache.js";w.version="0.5.0-dev";w.tags=["{{","}}"];w.parse=m;w.compile=e;w.render=v;w.clearCache=u;w.to_html=function(A,y,z,B){var x=v(A,y,z);if(typeof B==="function"){B(x)}else{return x}};var s=Object.prototype.toString;var f=Array.isArray;var b=Array.prototype.forEach;var g=String.prototype.trim;var i;if(f){i=f}else{i=function(x){return s.call(x)==="[object Array]"}}var r;if(b){r=function(y,z,x){return b.call(y,z,x)}}else{r=function(A,B,z){for(var y=0,x=A.length;y<x;++y){B.call(z,A[y],y,A)}}}var k=/^\s*$/;function c(x){return k.test(x)}var p;if(g){p=function(x){return x==null?"":g.call(x)}}else{var n,h;if(c("\xA0")){n=/^\s+/;h=/\s+$/}else{n=/^[\s\xA0]+/;h=/[\s\xA0]+$/}p=function(x){return x==null?"":String(x).replace(n,"").replace(h,"")}}var d={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function o(x){return String(x).replace(/&(?!\w+;)|[<>"']/g,function(y){return d[y]||y})}function l(D,F,G,z){z=z||"<template>";var H=F.split("\n"),x=Math.max(G-3,0),A=Math.min(H.length,G+3),y=H.slice(x,A);var E;for(var B=0,C=y.length;B<C;++B){E=B+x+1;y[B]=(E===G?" >> ":"    ")+y[B]}D.template=F;D.line=G;D.file=z;D.message=[z+":"+G,y.join("\n"),"",D.message].join("\n");return D}function t(x,F,E){if(x==="."){return F[F.length-1]}var D=x.split(".");var B=D.length-1;var C=D[B];var G,y,A=F.length,z,H;while(A){H=F.slice(0);y=F[--A];z=0;while(z<B){y=y[D[z++]];if(y==null){break}H.push(y)}if(y&&C in y){G=y[C];break}}if(typeof G==="function"){G=G.call(H[H.length-1])}if(G==null){return E}return G}function j(A,x,E,z){var y="";var C=t(A,x);if(z){if(C==null||C===false||(i(C)&&C.length===0)){y+=E()}}else{if(i(C)){r(C,function(F){x.push(F);y+=E();x.pop()})}else{if(typeof C==="object"){x.push(C);y+=E();x.pop()}else{if(typeof C==="function"){var B=x[x.length-1];var D=function(F){return v(F,B)};y+=C.call(B,E(),D)||""}else{if(C){y+=E()}}}}}return y}function m(Z,B){B=B||{};var K=B.tags||w.tags,L=K[0],G=K[K.length-1];var y=['var buffer = "";',"\nvar line = 1;","\ntry {",'\nbuffer += "'];var F=[],aa=false,X=false;var V=function(){if(aa&&!X&&!B.space){while(F.length){y.splice(F.pop(),1)}}else{F=[]}aa=false;X=false};var S=[],P,C,M;var U=function(ab){K=p(ab).split(/\s+/);C=K[0];M=K[K.length-1]};var J=function(ab){y.push('";',P,'\nvar partial = partials["'+p(ab)+'"];',"\nif (partial) {","\n  buffer += render(partial,stack[stack.length - 1],partials);","\n}",'\nbuffer += "')};var x=function(ad,ab){var ac=p(ad);if(ac===""){throw l(new Error("Section name may not be empty"),Z,I,B.file)}S.push({name:ac,inverted:ab});y.push('";',P,'\nvar name = "'+ac+'";',"\nvar callback = (function () {","\n  return function () {",'\n    var buffer = "";','\nbuffer += "')};var E=function(ab){x(ab,true)};var T=function(ac){var ab=p(ac);var ae=S.length!=0&&S[S.length-1].name;if(!ae||ab!=ae){throw l(new Error('Section named "'+ab+'" was never opened'),Z,I,B.file)}var ad=S.pop();y.push('";',"\n    return buffer;","\n  };","\n})();");if(ad.inverted){y.push("\nbuffer += renderSection(name,stack,callback,true);")}else{y.push("\nbuffer += renderSection(name,stack,callback);")}y.push('\nbuffer += "')};var W=function(ab){y.push('";',P,'\nbuffer += lookup("'+p(ab)+'",stack,"");','\nbuffer += "')};var z=function(ab){y.push('";',P,'\nbuffer += escapeHTML(lookup("'+p(ab)+'",stack,""));','\nbuffer += "')};var I=1,Y,D;for(var Q=0,R=Z.length;Q<R;++Q){if(Z.slice(Q,Q+L.length)===L){Q+=L.length;Y=Z.substr(Q,1);P="\nline = "+I+";";C=L;M=G;aa=true;switch(Y){case"!":Q++;D=null;break;case"=":Q++;G="="+G;D=U;break;case">":Q++;D=J;break;case"#":Q++;D=x;break;case"^":Q++;D=E;break;case"/":Q++;D=T;break;case"{":G="}"+G;case"&":Q++;X=true;D=W;break;default:X=true;D=z}var A=Z.indexOf(G,Q);if(A===-1){throw l(new Error('Tag "'+L+'" was not closed properly'),Z,I,B.file)}var O=Z.substring(Q,A);if(D){D(O)}var N=0;while(~(N=O.indexOf("\n",N))){I++;N++}Q=A+G.length-1;L=C;G=M}else{Y=Z.substr(Q,1);switch(Y){case'"':case"\\":X=true;y.push("\\"+Y);break;case"\r":break;case"\n":F.push(y.length);y.push("\\n");V();I++;break;default:if(c(Y)){F.push(y.length)}else{X=true}y.push(Y)}}}if(S.length!=0){throw l(new Error('Section "'+S[S.length-1].name+'" was not closed properly'),Z,I,B.file)}V();y.push('";',"\nreturn buffer;","\n} catch (e) { throw {error: e, line: line}; }");var H=y.join("").replace(/buffer \+= "";\n/g,"");if(B.debug){if(typeof console!="undefined"&&console.log){console.log(H)}else{if(typeof print==="function"){print(H)}}}return H}function q(B,z){var y="view,partials,stack,lookup,escapeHTML,renderSection,render";var x=m(B,z);var A=new Function(y,x);return function(D,E){E=E||{};var C=[D];try{return A(D,E,C,t,o,j,v)}catch(F){throw l(F.error,B,F.line,z.file)}}}var a={};function u(){a={}}function e(y,x){x=x||{};if(x.cache!==false){if(!a[y]){a[y]=q(y,x)}return a[y]}return q(y,x)}function v(z,x,y){return e(z)(x,y)}})(Mustache);

//jQote2 (10/21/2010)
(function($){var _=false,E1="UndefinedTemplateError",E2="TemplateCompilationError",E3="TemplateExecutionError",A="[object Array]",S="[object String]",F="[object Function]",n=1,c="%",q=/^[^<]*(<[\w\W]+>)[^>]*$/,ts=Object.prototype.toString;function r(e,x){throw ($.extend(e,x),e)}function dns(f) {var a=[];if(ts.call(f)!==A)return _;for(var i=0,l=f.length;i<l;i++)a[i]=f[i].jqote_id;return a.length?a.sort().join('.').replace(/(\b\d+\b)\.(?:\1(\.|$))+/g,"$1$2"):_}function l(s,t){var f,g=[],t=t||c,x=ts.call(s);if(x===F)return s.jqote_id?[s]:_;if(x!==A)return[$.jqotec(s,t)];if(x===A)for(var i=0,l=s.length;i<l;i++)return g.length?g:_}$.fn.extend({jqote:function(x,y){var x=ts.call(x)===A?x:[x],d="";this.each(function(i){var f=$.jqotec(this,y);for(var j=0;j<x.length;j++)d+=f.call(x[j],i,j,x,f)});return d}});$.each({app:"append",pre:"prepend",sub:"html"},function(x,y){$.fn["jqote"+x]=function(e,d,t){var p,r,s=$.jqote(e,d,t),$$=!q.test(s)?function(s){return $(document.createTextNode(s))}:$;if(!!(p=dns(l(e))))r=new RegExp("(^|\\.)"+p.split(".").join("\\.(.*)?")+"(\\.|$)");return this.each(function(){var z=$$(s);$(this)[y](z);(z[0].nodeType===3?$(this):z).trigger("jqote."+x,[z,r])})}});
$.extend({jqote:function(e,d,t){var s="",t=t||c,f=l(e);if(f===_)r(new Error("Empty or undefined template passed to $.jqote"),{type:E1});d=ts.call(d)!==A?[d]:d;for(var i=0,m=f.length;i<m;i++)for(var j=0;j<d.length;j++)s+=f[i].call(d[j],i,j,d,f[i]);return s},jqotec:function(x,t){var h,e,y,t=t||c,z=ts.call(x);if(z===S&&q.test(x)){e=y=x;if(h=$.jqotecache[x])return h}else{e=z===S||x.nodeType?$(x):x instanceof jQuery?x:null;if(!e[0]||!(y=e[0].innerHTML)&&!(y=e.text()))r(new Error("Empty or undefined template passed to $.jqotec"),{type:E1});if(h=$.jqotecache[$.data(e[0],"jqote_id")])return h}var s="",i,a=y.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]/g,"").split("<"+t).join(t+">\x1b").split(t+">");for(var m=0,k=a.length;m<k;m++)s+=a[m].charAt(0)!=="\x1b"?"out+='"+a[m].replace(/(\\|["'])/g,"\\$1")+"'":(a[m].charAt(1)==="="?";out+=("+a[m].substr(2)+");":(a[m].charAt(1)==="!"?";out+=$.jqotenc(("+a[m].substr(2)+"));":";"+a[m].substr(1)));s="try{"+('var out="";'+s+";return out;").split("out+='';").join("").split('var out="";out+=').join("var out=")+'}catch(e){e.type="'+E3+'";e.args=arguments;e.template=arguments.callee.toString();throw e;}';try{var f=new Function("i, j, data, fn",s)}catch(e){r(e,{type:E2})}i=e instanceof jQuery?$.data(e[0],"jqote_id",n):e;return $.jqotecache[i]=(f.jqote_id=n++,f)},
jqotefn:function(e){var t=ts.call(e),i=t===S&&q.test(e)?e:$.data($(e)[0],"jqote_id");return $.jqotecache[i]||_},jqotetag:function(s){if(ts.call(s)===S)c=s},jqotenc:function(s){return s.toString().replace(/&(?!\w+;)/g,'&#38;').split('<').join('&#60;').split('>').join('&#62;').split('"').join('&#34;').split("'").join('&#39;')},jqotecache:{}});$.event.special.jqote={add:function(o){var n,h=o.handler,d=!o.data?[]:ts.call(o.data)!==A?[o.data]:o.data;if(!o.namespace)o.namespace="app.pre.sub";if(!d.length||!(n=dns(l(d))))return;o.handler=function(e,m,r){return !r||r.test(n)?h.apply(this,[e,m]):null}}}})(jQuery);

//dot 0.2.0
// Laura Doktorova https://github.com/olado/doT
(function(){function o(){var b={"&":"&#38;","<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","/":"&#47;"},a=/&(?!\\w+;)|<|>|"|'|\//g;return function(f){return f?f.toString().replace(a,function(g){return b[g]||g}):f}}function p(b,a,f){return(typeof a==="string"?a:a.toString()).replace(b.define||h,function(g,e,c,i){if(e.indexOf("def.")===0)e=e.substring(4);if(!(e in f))if(c===":")f[e]=i;else eval("def['"+e+"']="+i);return""}).replace(b.use||h,function(g,e){var c=eval(e);return c?p(b,c,f):c})}function l(b){return b.replace(/\\('|\\)/g,
"$1").replace(/[\r\t\n]/g," ")}var j={version:"0.2.0",templateSettings:{evaluate:/\{\{([\s\S]+?)\}\}/g,interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:true,append:true,selfcontained:false},template:undefined,compile:undefined},m=function(){return this||(0,eval)("this")}();
if(typeof module!=="undefined"&&module.exports)module.exports=j;else if(typeof define==="function"&&define.amd)define(function(){return j});else m.doT=j;m.encodeHTML=o();var q={append:{start:"'+(",end:")+'",startencode:"'+encodeHTML("},split:{start:"';out+=(",end:");out+='",startencode:"';out+=encodeHTML("}},h=/$^/;j.template=function(b,a,f){a=a||j.templateSettings;var g=a.append?q.append:q.split,e,c=0,i;if(a.use||a.define){var r=m.def;m.def=f||{};b=p(a,b,m.def);m.def=r}b=("var out='"+(a.strip?b.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,
" ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):b).replace(/'|\\/g,"\\$&").replace(a.interpolate||h,function(n,d){return g.start+l(d)+g.end}).replace(a.encode||h,function(n,d){e=true;return g.startencode+l(d)+g.end}).replace(a.conditional||h,function(n,d,k){return d?k?"';}else if("+l(k)+"){out+='":"';}else{out+='":k?"';if("+l(k)+"){out+='":"';}out+='"}).replace(a.iterate||h,function(n,d,k,s){if(!d)return"';} } out+='";c+=1;i=s||"i"+c;d=l(d);return"';var arr"+c+"="+d+";if(arr"+c+"){var "+k+","+i+"=-1,l"+
c+"=arr"+c+".length-1;while("+i+"<l"+c+"){"+k+"=arr"+c+"["+i+"+=1];out+='"}).replace(a.evaluate||h,function(n,d){return"';"+l(d)+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|}|^|{)out\+='';/g,"$1").replace(/\+''/g,"").replace(/(\s|;|}|^|{)out\+=''\+/g,"$1out+=");if(e&&a.selfcontained)b="var encodeHTML=("+o.toString()+"());"+b;try{return new Function(a.varname,b)}catch(t){typeof console!=="undefined"&&console.log("Could not create a template function: "+
b);throw t;}};j.compile=function(b,a){return j.template(b,null,a)}})();


//doT 2
(function(){var a={version:"0.1.2"};typeof module!="undefined"&&module.exports?module.exports=a:this.doU=a,a.templateSettings={begin:"{{",end:"}}",varname:"it"},a.template=function(b,c){c=c||a.templateSettings;var d="",e=c.begin,f=c.end,g,h,i=b.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g,"").split(e).join(f+"").split(f);for(g=0,h=i.length;g<h;g++)d+=i[g].charAt(0)!==""?"out+='"+i[g].replace(/(\\|["'])/g,"\\$1")+"'":i[g].charAt(1)==="="?";out+=("+i[g].substr(2)+");":i[g].charAt(1)==="!"?";out+=("+i[g].substr(2)+").toString().replace(/&(?!\\w+;)/g, '&#38;').split('<').join('&#60;').split('>').join('&#62;').split('"+'"'+"').join('&#34;').split("+'"'+"'"+'"'+").join('&#39;').split('/').join('&#x2F;');":";"+i[g].substr(1);d=('var out="";'+d+";return out;").split("out+='';").join("").split('var out="";out+=').join("var out=");try{return new Function(c.varname,d)}catch(j){throw typeof console!="undefined"&&console.log("Could not create a template function: "+d),j}}})();


//Haml (July 16 2011)
var Haml;(function(){var matchers,self_close_tags,embedder,forceXML,escaperName,escapeHtmlByDefault;function html_escape(text){return(text+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;")}function render_attribs(attribs){var key,value,result=[];for(key in attribs){if(key!=="_content"&&attribs.hasOwnProperty(key)){switch(attribs[key]){case"undefined":case"false":case"null":case'""':break;default:try{value=JSON.parse("["+attribs[key]+"]")[0];if(value===true){value=key}else{if(typeof value==="string"&&embedder.test(value)){value='" +\n'+parse_interpol(html_escape(value))+' +\n"'}else{value=html_escape(value)}}result.push(" "+key+'=\\"'+value+'\\"')}catch(e){result.push(" "+key+'=\\"" + '+escaperName+"("+attribs[key]+') + "\\"')}}}}return result.join("")}function parse_attribs(line){var attributes={},l=line.length,i,c,count=1,quote=false,skip=false,open,close,joiner,seperator,pair={start:1,middle:null,end:null};if(!(l>0&&(line.charAt(0)==="{"||line.charAt(0)==="("))){return{_content:line[0]===" "?line.substr(1,l):line}}open=line.charAt(0);close=(open==="{")?"}":")";joiner=(open==="{")?":":"=";seperator=(open==="{")?",":" ";function process_pair(){if(typeof pair.start==="number"&&typeof pair.middle==="number"&&typeof pair.end==="number"){var key=line.substr(pair.start,pair.middle-pair.start).trim(),value=line.substr(pair.middle+1,pair.end-pair.middle-1).trim();attributes[key]=value}pair={start:null,middle:null,end:null}}for(i=1;count>0;i+=1){if(i>l){throw"Malformed attribute block"}c=line.charAt(i);if(skip){skip=false}else{if(quote){if(c==="\\"){skip=true}if(c===quote){quote=false}}else{if(c==='"'||c==="'"){quote=c}if(count===1){if(c===joiner){pair.middle=i}if(c===seperator||c===close){pair.end=i;process_pair();if(c===seperator){pair.start=i+1}}}if(c===open||c==="("){count+=1}if(c===close||(count>1&&c===")")){count-=1}}}}attributes._content=line.substr(i,line.length);return attributes}function parse_interpol(value){var items=[],pos=0,next=0,match;while(true){next=value.substr(pos).search(embedder);if(next<0){if(pos<value.length){items.push(JSON.stringify(value.substr(pos)))}break}items.push(JSON.stringify(value.substr(pos,next)));pos+=next;match=value.substr(pos).match(embedder);next=match[0].length;if(next<0){break}if(match[1]==="#"){items.push(escaperName+"("+(match[2]||match[3])+")")}else{items.push(match[2]||match[3])}pos+=next}return items.filter(function(part){return part&&part.length>0}).join(" +\n")}embedder=/([#!])\{([^}]*)\}/;self_close_tags=["meta","img","link","br","hr","input","area","base"];matchers=[{name:"html tags",regexp:/^(\s*)((?:[.#%][a-z_\-][a-z0-9_:\-]*)+)(.*)$/i,process:function(){var line_beginning,tag,classes,ids,attribs,content,whitespaceSpecifier,whitespace={},output;line_beginning=this.matches[2];classes=line_beginning.match(/\.([a-z_\-][a-z0-9_\-]*)/gi);ids=line_beginning.match(/\#([a-z_\-][a-z0-9_\-]*)/gi);tag=line_beginning.match(/\%([a-z_\-][a-z0-9_:\-]*)/gi);tag=tag?tag[0].substr(1,tag[0].length):"div";attribs=this.matches[3];if(attribs){attribs=parse_attribs(attribs);if(attribs._content){var leader0=attribs._content.charAt(0),leader1=attribs._content.charAt(1),leaderLength=0;if(leader0=="<"){leaderLength++;whitespace.inside=true;if(leader1==">"){leaderLength++;whitespace.around=true}}else{if(leader0==">"){leaderLength++;whitespace.around=true;if(leader1=="<"){leaderLength++;whitespace.inside=true}}}attribs._content=attribs._content.substr(leaderLength);this.contents.unshift(attribs._content.trim());delete (attribs._content)}}else{attribs={}}if(classes){classes=classes.map(function(klass){return klass.substr(1,klass.length)}).join(" ");if(attribs["class"]){try{attribs["class"]=JSON.stringify(classes+" "+JSON.parse(attribs["class"]))}catch(e){attribs["class"]=JSON.stringify(classes+" ")+" + "+attribs["class"]}}else{attribs["class"]=JSON.stringify(classes)}}if(ids){ids=ids.map(function(id){return id.substr(1,id.length)}).join(" ");if(attribs.id){attribs.id=JSON.stringify(ids+" ")+attribs.id}else{attribs.id=JSON.stringify(ids)}}attribs=render_attribs(attribs);content=this.render_contents();if(content==='""'){content=""}if(whitespace.inside){if(content.length==0){content='"  "'}else{try{content='" '+JSON.parse(content)+' "'}catch(e){content='" "+\n'+content+'+\n" "'}}}if(forceXML?content.length>0:self_close_tags.indexOf(tag)==-1){output='"<'+tag+attribs+'>"'+(content.length>0?" + \n"+content:"")+' + \n"</'+tag+'>"'}else{output='"<'+tag+attribs+' />"'}if(whitespace.around){output='" '+output.substr(1,output.length-2)+' "'}return output}},{name:"each loop",regexp:/^(\s*)(?::for|:each)\s+(?:([a-z_][a-z_\-]*),\s*)?([a-z_][a-z_\-]*)\s+in\s+(.*)(\s*)$/i,process:function(){var ivar=this.matches[2]||"__key__",vvar=this.matches[3],avar=this.matches[4],rvar="__result__";if(this.matches[5]){this.contents.unshift(this.matches[5])}return"(function () { var "+rvar+" = [], "+ivar+", "+vvar+"; for ("+ivar+" in "+avar+") { if ("+avar+".hasOwnProperty("+ivar+")) { "+vvar+" = "+avar+"["+ivar+"]; "+rvar+".push(\n"+(this.render_contents()||"''")+"\n); } } return "+rvar+'.join(""); }).call(this)'}},{name:"if",regexp:/^(\s*):if\s+(.*)\s*$/i,process:function(){var condition=this.matches[2];return"(function () { if ("+condition+") { return (\n"+(this.render_contents()||"")+'\n);} else { return ""; } }).call(this)'}},{name:"silent-comments",regexp:/^(\s*)-#\s*(.*)\s*$/i,process:function(){return'""'}},{name:"silent-comments",regexp:/^(\s*)\/\s*(.*)\s*$/i,process:function(){this.contents.unshift(this.matches[2]);return'"<!--'+this.contents.join("\\n")+'-->"'}},{name:"rawjs",regexp:/^(\s*)-\s*(.*)\s*$/i,process:function(){this.contents.unshift(this.matches[2]);return'"";'+this.contents.join("\n")+"; _$output = _$output "}},{name:"pre",regexp:/^(\s*):pre(\s+(.*)|$)/i,process:function(){this.contents.unshift(this.matches[2]);return'"<pre>"+\n'+JSON.stringify(this.contents.join("\n"))+'+\n"</pre>"'}},{name:"doctype",regexp:/^()!!!(?:\s*(.*))\s*$/,process:function(){var line="";switch((this.matches[2]||"").toLowerCase()){case"":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';break;case"strict":case"1.0":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';break;case"frameset":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';break;case"5":line="<!DOCTYPE html>";break;case"1.1":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';break;case"basic":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">';break;case"mobile":line='<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">';break;case"xml":line="<?xml version='1.0' encoding='utf-8' ?>";break;case"xml iso-8859-1":line="<?xml version='1.0' encoding='iso-8859-1' ?>";break}return JSON.stringify(line+"\n")}},{name:"markdown",regexp:/^(\s*):markdown\s*$/i,process:function(){return parse_interpol(exports.Markdown.encode(this.contents.join("\n")))}},{name:"script",regexp:/^(\s*):(?:java)?script\s*$/,process:function(){return parse_interpol('\n<script type="text/javascript">\n//<![CDATA[\n'+this.contents.join("\n")+"\n//]]>\n<\/script>\n")}},{name:"css",regexp:/^(\s*):css\s*$/,process:function(){return JSON.stringify('<style type="text/css">\n'+this.contents.join("\n")+"\n</style>")}}];function compile(lines){var block=false,output=[];if(typeof lines==="string"){lines=lines.trim().replace(/\n\r|\r/g,"\n").split("\n")}lines.forEach(function(line){var match,found=false;if(block){match=block.check_indent.exec(line);if(match){block.contents.push(match[1]||"");return}else{output.push(block.process());block=false}}matchers.forEach(function(matcher){if(!found){match=matcher.regexp.exec(line);if(match){block={contents:[],indent_level:(match[1]),matches:match,check_indent:new RegExp("^(?:\\s*|"+match[1]+"  (.*))$"),process:matcher.process,render_contents:function(){return compile(this.contents)}};found=true}}});if(!found){output.push(function(){if(line[0]==="\\"){return parse_interpol(line.substr(1,line.length))}function escapedLine(){try{return escaperName+"("+JSON.stringify(JSON.parse(line))+")"}catch(e2){return escaperName+"("+line+")"}}function unescapedLine(){try{return parse_interpol(JSON.parse(line))}catch(e){return line}}if((line.substr(0,2)==="&=")){line=line.substr(2,line.length).trim();return escapedLine()}if((line.substr(0,2)==="!=")){line=line.substr(2,line.length).trim();return unescapedLine()}if((line[0]==="=")){line=line.substr(1,line.length).trim();if(escapeHtmlByDefault){return escapedLine()}else{return unescapedLine()}}return parse_interpol(line)}())}});if(block){output.push(block.process())}var txt=output.filter(function(part){return part&&part.length>0}).join(" +\n");if(txt.length==0){txt='""'}return txt}function optimize(js){var new_js=[],buffer=[],part,end;function flush(){if(buffer.length>0){new_js.push(JSON.stringify(buffer.join(""))+end);buffer=[]}}js.replace(/\n\r|\r/g,"\n").split("\n").forEach(function(line){part=line.match(/^(\".*\")(\s*\+\s*)?$/);if(!part){flush();new_js.push(line);return}end=part[2]||"";part=part[1];try{buffer.push(JSON.parse(part))}catch(e){flush();new_js.push(line)}});flush();return new_js.join("\n")}function render(text,options){options=options||{};text=text||"";var js=compile(text,options);if(options.optimize){js=Haml.optimize(js)}return execute(js,options.context||Haml,options.locals)}function execute(js,self,locals){return(function(){with(locals||{}){try{var _$output;eval("_$output ="+js);return _$output}catch(e){return"\n<pre class='error'>"+html_escape(e.stack)+"</pre>\n"}}}).call(self)}Haml=function Haml(haml,config){if(typeof(config)!="object"){forceXML=config;config={}}var escaper;if(config.customEscape){escaper="";escaperName=config.customEscape}else{escaper=html_escape.toString()+"\n";escaperName="html_escape"}escapeHtmlByDefault=(config.escapeHtmlByDefault||config.escapeHTML||config.escape_html);var js=optimize(compile(haml));var str="with(locals || {}) {\n  try {\n   var _$output="+js+";\n return _$output;  } catch (e) {\n    return \"\\n<pre class='error'>\" + "+escaperName+'(e.stack) + "</pre>\\n";\n  }\n}';try{var f=new Function("locals",escaper+str);return f}catch(e){console.error(str);throw e}};Haml.compile=compile;Haml.optimize=optimize;Haml.render=render;Haml.execute=execute;Haml.html_escape=html_escape}());if(typeof module!=="undefined"){module.exports=Haml};

//blueimp 1.0.2
(function(e){var a=function(b,d){var c=!/[^\-\w]/.test(b)?a.cache[b]=a.cache[b]||a(a.load(b)):new Function(a.arg,("var _s=''"+a.helper+";_s+='"+b.replace(a.regexp,a.func)+"';return _s;").split("_s+='';").join(""));c.tmpl=c.tmpl||a;return d?c(d):c};a.cache={};a.load=function(a){return document.getElementById(a).innerHTML};a.regexp=/(\s+)|('|\\)(?![^%]*%\})|(?:\{%(=|#)(.+?)%\})|(\{%)|(%\})/g;a.func=function(a,d,c,f,g,e,i,h,j){if(d)return h&&h+a.length!==j.length?" ":"";if(c)return"\\"+a;if(f)return"="===
f?"'+_e("+g+")+'":"'+("+g+"||'')+'";if(e)return"';";if(i)return"_s+='"};a.encReg=/[<>&"\x00]/g;a.encMap={"<":"&lt;",">":"&gt;","&":"&amp;",'"':"&quot;","\x00":""};a.encode=function(b){return(""+(b||"")).replace(a.encReg,function(b){return a.encMap[b]})};a.arg="o";a.helper=",_t=arguments.callee.tmpl,_e=_t.encode,print=function(s,e){_s+=e&&(s||'')||_e(s);},include=function(s,d){_s+=_t(s,d);}";"function"===typeof define&&define.amd?define("tmpl",function(){return a}):e.tmpl=a})(this);

// vash v0.4.4-931, 05-01-2012
(function(a){typeof define=="function"&&define.amd?define(a):typeof module=="object"&&module.exports?module.exports=a:window.vash=a})(function(a){function R(a,b){this.ast=a,this.originalMarkup=b||""}function M(a,b){this.options=b||{},this.tokens=a,this.ast=L(N),this.prevTokens=[]}function K(a){this.input=this.originalInput=a.replace(/\r\n|\r/g,"\n"),this.lineno=1,this.charno=0}var b=a;a.version="0.4.4-931",a.config={useWith:!1,modelName:"model",htmlEscape:!0,debug:!1,debugParser:!1,debugCompiler:!1};var c="AT",d="ASSIGN_OPERATOR",e="AT_COLON",f="AT_STAR_CLOSE",g="AT_STAR_OPEN",h="BACKSLASH",i="BRACE_CLOSE",j="BRACE_OPEN",k="CONTENT",l="DOUBLE_QUOTE",m="EMAIL",n="FAT_ARROW",o="FUNCTION",p="HARD_PAREN_CLOSE",q="HARD_PAREN_OPEN",r="HTML_RAW",s="HTML_TAG_CLOSE",t="HTML_TAG_OPEN",u="HTML_TAG_SELFCLOSE",v="IDENTIFIER",w="KEYWORD",x="LOGICAL",y="NEWLINE",z="NUMERIC_CONTENT",A="OPERATOR",B="PAREN_CLOSE",C="PAREN_OPEN",D="PERIOD",E="SINGLE_QUOTE",F="TEXT_TAG_CLOSE",G="TEXT_TAG_OPEN",H="WHITESPACE",I={};I[g]=f,I[j]=i,I[l]=l,I[q]=p,I[C]=B,I[E]=E;var J=[m,/^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})\b/,g,/^(@\*)/,f,/^(\*@)/,e,/^@\:/,c,/^(@)/,n,/^(\(.*?\)?\s*?=>)/,C,/^(\()/,B,/^(\))/,q,/^(\[)/,p,/^(\])/,j,/^(\{)/,i,/^(\})/,G,/^(<text>)/,F,/^(<\/text>)/,u,function(){return this.scan(/^(<[^@>]+?\/>)/,u)},t,function(){return this.spewIf(this.scan(/^(<[^\/ >]+?[^>]*?>)/,t),"@")},s,function(){return this.scan(/^(<\/[^>@\b]+?>)/,s)},D,/^(\.)/,y,function(){var a=this.scan(/^(\n)/,y);a&&(this.lineno++,this.charno=0);return a},H,/^(\s)/,o,/^(function)(?![\d\w])/,w,/^(case|catch|do|else|finally|for|function|goto|if|instanceof|return|switch|try|typeof|var|while|with)(?![\d\w])/,r,/^(vash\.raw)(?![\d\w])/,v,/^([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)/,A,/^(===|!==|==|!==|>>>|<<|>>|>=|<=|>|<|\+|-|\/|\*|\^|%|\:|\?)/,d,/^(\|=|\^=|&=|>>>=|>>=|<<=|-=|\+=|%=|\/=|\*=|=)/,x,/^(&&|\|\||&|\||\^)/,h,/^(\\)/,l,/^(\")/,E,/^(\')/,z,/^([0-9]+)/,k,/^([^\s})@.]+?)/];K.prototype={tok:function(a,b){return{type:a,line:this.lineno,chr:this.charno,val:b,toString:function(){return"["+this.type+" ("+this.line+","+this.chr+"): "+this.val+"]"}}},scan:function(a,b){var c,d;if(c=a.exec(this.input)){this.input=this.input.substr(c[0].length),d=this.tok(b,c[1]),this.charno+=c[0].length;return d}},spewIf:function(a,b){var c,d;a&&(c=a.val.split(b),c.length>1&&(a.val=c.shift(),d=b+c.join(b),this.input=d+this.input,this.charno-=d.length));return a},advance:function(){var a,b,c,d;for(a=0;a<J.length;a+=2){c=J[a+1],c.displayName=J[a],typeof c=="function"&&(d=c.call(this)),typeof c.exec=="function"&&(d=this.scan(c,J[a]));if(d)return d}}};var L=function(a){return new L.fn.init(a)};L.prototype.init=function(a){typeof a=="string"&&(this.mode=a),this.maxCheck()},L.fn=L.prototype.init.prototype=L.prototype,L.fn.vquery="yep",L.fn.constructor=L,L.fn.length=0,L.fn.parent=null,L.fn.mode=null,L.fn.tagName=null,L.fn.beget=function(a,b){var c=L(a);c.parent=this,this.push(c),b&&(c.tagName=b),this.maxCheck();return c},L.fn.closest=function(a,b){var c=this;while(c)if(c.tagName!==b&&c.parent)c=c.parent;else break;return c},L.fn.pushFlatten=function(a){var b=a,c,d;while(b.length===1&&b[0].vquery)b=b[0];if(b.mode!==N)this.push(b);else for(c=0;c<b.length;c++)this.push(b[c]);this.maxCheck();return this},L.fn.push=function(a){L.isArray(a)?(a.vquery&&a.forEach(function(a){a.parent=this},this),Array.prototype.push.apply(this,a)):(a.vquery&&(a.parent=this),Array.prototype.push.call(this,a)),this.maxCheck();return this.length},L.fn.root=function(){var a=this;while(a&&a.parent&&(a=a.parent));return a},L.fn.toTreeString=function(){function c(d){var e,f;a.push(Array(b).join(" |")+" +"+d.mode+" "+(d.tagName||"")),b+=1,e=d.slice();while(f=e.shift())f.vquery===L.fn.vquery?c(f):a.push(Array(b).join(" |")+" "+(f?f.toString():"[empty]"));b-=1}var a=[],b=1;c(this);return a.join("\n")},L.fn.maxCheck=function(){if(this.length>=L.maxSize){var a=new Error;a.message="Maximum number of elements exceeded",a.name="vQueryDepthException";throw a}},L.maxSize=1e3,L.isArray=function(a){return Object.prototype.toString.call(a)=="[object Array]"},L.copyObj=function(a){var b={};for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b},L.takeMethodsFromArray=function(){var a=["pop","push","reverse","shift","sort","splice","unshift","concat","join","slice","indexOf","lastIndexOf","filter","forEach","every","map","some","reduce","reduceRight"],b=[],c;for(var d=0;d<a.length;d++){c=a[d];if(typeof b[c]=="function")L.fn[c]||function(a){var c=Array.prototype.slice;L.fn[a]=function(){return b[a].apply(this,c.call(arguments,0))}}(c);else throw new Error("Vash requires ES5 array iteration methods, missing: "+c)}},L.takeMethodsFromArray();var N="PROGRAM",O="MARKUP",P="BLOCK",Q="EXPRESSION";M.prototype={parse:function(){var a,b,c,d;while(this.prevTokens.push(a),a=this.tokens.pop()){this.options.debugParser&&console.log(this.ast&&this.ast.mode,a.type,a,a.val);if(this.ast.mode===N||this.ast.mode===null)this.ast=this.ast.beget(this.options.initialMode||O),this.options.initialMode===Q&&(this.ast=this.ast.beget(Q));if(this.ast.mode===O){this.handleMKP(a);continue}if(this.ast.mode===P){this.handleBLK(a);continue}if(this.ast.mode===Q){this.handleEXP(a);continue}}this.ast=this.ast.root(),this.options.debugParser&&!this.options.initialMode&&(console.log(this.ast),console.log(this.ast.toTreeString()));return this.ast},exceptionFactory:function(a,b,c){b=="UNMATCHED"&&(a.name="UnmatchedCharacterError",this.ast=this.ast.root(),c&&(a.message="Unmatched "+c.type+" at line "+c.line+", character "+c.chr+". Value: "+c.val+"\n "+this.ast.toTreeString(),a.lineNumber=c.line));return a},advanceUntilNot:function(a){var b,c,d=[];while(c=this.tokens[this.tokens.length-1])if(c.type===a)b=this.tokens.pop(),d.push(b);else break;return d},advanceUntilMatched:function(a,b,c,d,e){var f=a,g=null,h=0,i=0,j=[];while(f){f.type===b?g&&g.type!==escape&&b!==c||!g?h++:b===c&&i++:f.type===c&&(i++,g&&g.type===e&&i--),j.push(f);if(h===i)break;g=f,f=this.tokens.pop();if(!f)throw this.exceptionFactory(new Error,"UNMATCHED",a)}return j.reverse()},subParse:function(a,b){var d,e,f,g=L.copyObj(this.options);g.initialMode=b,d=this.advanceUntilMatched(a,a.type,I[a.type],null,c),d.pop(),e=d.shift(),this.ast.push(a),f=new M(d,g),f.parse(),this.ast.pushFlatten(f.ast),this.ast.push(e)},handleMKP:function(a){var b=this.tokens[this.tokens.length-1],d=this.tokens[this.tokens.length-2],e=null,h;switch(a.type){case g:this.advanceUntilMatched(a,g,f,c,c);break;case c:if(b)switch(b.type){case C:case v:case r:this.ast.length===0&&(this.ast=this.ast.parent,this.ast.pop()),this.ast=this.ast.beget(Q);break;case w:case o:case j:this.ast.length===0&&(this.ast=this.ast.parent,this.ast.pop()),this.ast=this.ast.beget(P);break;default:this.ast.push(this.tokens.pop())}break;case j:this.ast=this.ast.beget(P),this.tokens.push(a);break;case i:this.ast=this.ast.parent,this.tokens.push(a);break;case G:case t:e=a.val.match(/^<([^\/ >]+)/i),e===null&&b&&b.type===c&&d&&(e=d.val.match(/(.*)/)),this.ast.tagName?this.ast=this.ast.beget(O,e[1]):this.ast.tagName=e[1],t===a.type&&this.ast.push(a);break;case F:case s:e=a.val.match(/^<\/([^>]+)/i),e===null&&b&&b.type===c&&d&&(e=d.val.match(/(.*)/)),h=this.ast.closest(O,e[1]),h!==null&&h.tagName===e[1]&&(this.ast=h),s===a.type&&this.ast.push(a),this.ast.parent&&this.ast.parent.mode===P&&(b.type===H||b.type===y)&&(this.ast=this.ast.parent);break;case u:this.ast.push(a),this.ast.parent&&this.ast.parent.mode===P&&(b.type===H||b.type===y)&&(this.ast=this.ast.parent);break;default:this.ast.push(a)}},handleBLK:function(a){var b=this.tokens[this.tokens.length-1],d,f,g,h,i,k;switch(a.type){case c:b.type!==c&&(this.tokens.push(a),this.ast=this.ast.beget(O));break;case e:this.ast=this.ast.beget(O);break;case G:case F:case u:case t:case s:this.ast=this.ast.beget(O),this.tokens.push(a);break;case n:this.ast=this.ast.beget(P);break;case j:case C:this.subParse(a,P),g=this.advanceUntilNot(H),b=this.tokens[this.tokens.length-1],b&&b.type!==w&&b.type!==o&&b.type!==j&&a.type!==C?(this.tokens.push.apply(this.tokens,g.reverse()),this.ast=this.ast.parent):this.ast.push(g);break;case H:this.ast.push(a),this.advanceUntilNot(H);break;default:this.ast.push(a)}},handleEXP:function(a){var b=null,e,f,g,i,k,m,p;switch(a.type){case w:case o:this.ast=this.ast.beget(P),this.tokens.push(a);break;case H:case x:case d:case A:case z:this.ast.parent&&this.ast.parent.mode===Q?this.ast.push(a):(this.ast=this.ast.parent,this.tokens.push(a));break;case v:case r:this.ast.push(a);break;case E:case l:this.ast.parent&&this.ast.parent.mode===Q?(k=this.advanceUntilMatched(a,a.type,I[a.type],h,h),this.ast.pushFlatten(k.reverse())):(this.ast=this.ast.parent,this.tokens.push(a));break;case q:case C:m=this.prevTokens[this.prevTokens.length-1],this.subParse(a,Q),b=this.tokens[this.tokens.length-1];if(m&&m.type===c||b&&b.type===v)this.ast=this.ast.parent;break;case j:this.tokens.push(a),this.ast=this.ast.beget(P);break;case n:this.tokens.push(a),this.ast=this.ast.beget(P);break;case D:b=this.tokens[this.tokens.length-1],!b||b.type!==v&&b.type!==w&&b.type!==o&&b.type!==D?(this.ast=this.ast.parent,this.tokens.push(a)):this.ast.push(a);break;default:this.ast.parent&&this.ast.parent.mode!==Q?(this.ast=this.ast.parent,this.tokens.push(a)):this.ast.push(a)}}};var S=R.prototype;S.assemble=function(a){function n(a){return a.vquery&&a.mode===Q?a.filter(n).length>0:a.vquery&&a.mode!==Q?!0:!1}function m(a){var b,c=a.slice(0),d,e,f;a.mode===Q&&a.parent&&a.parent.mode!==Q&&(d=a.filter(n).length);for(e=0;e<c.length;e++)f=c[e],f.vquery?m(f):a.mode===O?j(f,a,e):a.mode===P?k(f,a,e):a.mode===Q&&l(f,a,e,d>0?!1:!0)}function l(f,g,h,j){var k="",l="",m=g.parent&&g.parent.mode!==Q;a.htmlEscape!==!1&&(f.type===r&&c.push(!0),m&&h===0&&j&&c.length===0&&(k+="( typeof (__vt = "),m&&h===g.length-1&&j&&(c.length>0?c.pop():l+=") !== 'undefined' ? __vt : '' ).toString()\n.replace(/&(?!\\w+;)/g, '&amp;')\n.replace(/</g, '&lt;')\n.replace(/>/g, '&gt;')\n.replace(/\"/g, '&quot;') \n")),m&&(h===0||h===1&&g[0].type===r)&&(i(f),k="__vo.push("+k),m&&(h===g.length-1||h===g.length-2&&g[g.length-1].type===r)&&(l+="); \n"),f.type!==r&&b.push(k+f.val.replace(d,'"').replace(e,'"')+l),m&&h===g.length-1&&i(f)}function k(a,c,e){b.push(a.val.replace(d,'"'))}function j(a,c,e){i(a),b.push("__vo.push('"+a.val.replace(d,'"').replace(f,"\\n")+"'); \n")}function i(c){a.debug&&(b.push("__vl = "+c.line+", "),b.push("__vc = "+c.chr+"; \n"))}a=a||{};var b=[],c=[],d=/["']/gi,e=/(\\?)(["'])/gi,f=/[\n\r]/gi,g,h;b.push("var __vo = [], __vt; \n"),a.debug&&b.push("var __vl = 0, __vc = 0; \n"),m(this.ast),a.useWith===!0&&(b.unshift("with("+a.modelName+" || {}){ \n"),b.push("}")),a.debug&&(b.unshift("try { \n"),b.push("} catch(e){ (",S.reportError.toString(),")(e, __vl, __vc, ",'"'+this.originalMarkup.replace(f,"!LB!").replace(e,"\\$2")+'"',") } \n")),b.push("return __vo.join('');"),g=b.join(""),a.debugCompiler&&console.log(g);try{h=new Function(a.modelName,g)}catch(o){o.message+=" -> "+g;throw o}return h},S.reportError=function(a,b,c,d){var e=d.split("!LB!"),f=3,g=Math.max(0,b-f),h=Math.min(e.length,b+f),i=e.slice(g,h).map(function(a,c,d){var e=c+g+1;return(e===b?"  > ":"    ")+e+" | "+a}).join("\n");a.message="Problem while rendering template at line "+b+", character "+c+".\nOriginal message: "+a.message+"."+"\nContext: \n\n"+i+"\n\n";throw a},a.VLexer=K,a.VParser=M,a.VCompiler=R,a.compile=function(b,c){if(b===""||typeof b!="string")throw new Error("Empty or non-string cannot be compiled");var d,e,f=[],g,h,i,j;c=c||{};for(j in a.config)a.config.hasOwnProperty(j)&&typeof c[j]=="undefined"&&(c[j]=a.config[j]);d=new K(b);while(e=d.advance())f.push(e);f.reverse(),g=new M(f,c),g.parse(),h=new R(g.ast,b),i=h.assemble(c),i.displayName="render";return i};return a}({}));

/********************************
  PRE-COMPILED TEMPLATES
 ********************************/

// Underscore
window.tpl.underscore = _.template("<div><h1 class='header'><%= header %></h1><h2 class='header2'><%= header2 %></h2><h3 class='header3'><%= header3 %></h3><h4 class='header4'><%= header4 %></h4><h5 class='header5'><%= header5 %></h5><h6 class='header6'><%= header6 %></h6><ul class='list'><% for (var i = 0, l = list.length; i < l; i++) { %><li class='item'><%= list[i] %></li><% } %></ul></div>");

// Underscore - no with
window.tpl.underscoreNoWith = _.template("<div><h1 class='header'><%= data.header %></h1><h2 class='header2'><%= data.header2 %></h2><h3 class='header3'><%= data.header3 %></h3><h4 class='header4'><%= data.header4 %></h4><h5 class='header5'><%= data.header5 %></h5><h6 class='header6'><%= data.header6 %></h6><ul class='list'><% for (var i = 0, l = data.list.length; i < l; i++) { %><li class='item'><%= data.list[i] %></li><% } %></ul></div>", null, {variable: 'data'});

// Mustache
window.tpl.mustache = Mustache.compile("<div><h1 class='header'>{{{header}}}</h1><h2 class='header2'>{{{header2}}}</h2><h3 class='header3'>{{{header3}}}</h3><h4 class='header4'>{{{header4}}}</h4><h5 class='header5'>{{{header5}}}</h5><h6 class='header6'>{{{header6}}}</h6><ul class='list'>{{#list}}<li class='item'>{{{.}}}</li>{{/list}}</ul></div>");

// Handlebars
window.tpl.handlebars = Handlebars.compile("<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#each list}}<li class='item'>{{this}}</li>{{/each}}</ul></div>");

// Kendo
window.tpl.kendo = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:true});
 
window.tpl.kendo2 = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:false});

//John Resig's approach
window.tpl.resig = rtmpl("<div><h1 class='header'><#= header #></h1><h2 class='header2'><#= header2 #></h2><h3 class='header3'><#= header3 #></h3><h4 class='header4'><#= header4 #></h4><h5 class='header5'><#= header5 #></h5><h6 class='header6'><#= header6 #></h6><ul class='list'><# for (var i = 0, l = list.length; i < l; i++) { #><li class='item'><#= list[i] #></li><# } #></ul></div>");

window.tpl.resig2 = rtmpl2("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>");

//jqote2
window.tpl.jqote = $.jqotec("<div><h1 class='header'><%= this.header %></h1><h2 class='header2'><%= this.header2 %></h2><h3 class='header3'><%= this.header3 %></h3><h4 class='header4'><%= this.header4 %></h4><h5 class='header5'><%= this.header5 %></h5><h6 class='header6'><%= this.header6 %></h6><ul class='list'><% for (var n = 0, l = this.list.length; n < l; n++) { %><li class='item'><%= this.list[n] %></li><% } %></ul></div>");

//Dot
window.tpl.dot = doT.template("<div><h1 class='header'>{{= it.header }}</h1><h2 class='header2'>{{= it.header2 }}</h2><h3 class='header3'>{{= it.header3 }}</h3><h4 class='header4'>{{= it.header4 }}</h4><h5 class='header5'>{{= it.header5 }}</h5><h6 class='header6'>{{= it.header6 }}</h6><ul class='list'>{{ for (var i = 0, l = it.list.length; i < l; i++) { }}<li class='item'>{{= it.list[i] }}</li>{{ } }}</ul></div>");

//doU
window.tpl.doU = doU.template("<div><h1 class='header'>{{= it.header }}</h1><h2 class='header2'>{{= it.header2 }}</h2><h3 class='header3'>{{= it.header3 }}</h3><h4 class='header4'>{{= it.header4 }}</h4><h5 class='header5'>{{= it.header5 }}</h5><h6 class='header6'>{{= it.header6 }}</h6><ul class='list'>{{ for (var i = 0, l = it.list.length; i < l; i++) { }}<li class='item'>{{= it.list[i] }}</li>{{ } }}</ul></div>");


//hogan
window.tpl.hogan = Hogan.compile("<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#list}}<li class='item'>{{.}}</li>{{/list}}</ul></div>");

//haml
try {
window.tpl.haml = Haml("%div\n  %h1.header= header\n  %h2.header2= header2\n  %h3.header3= header3\n  %h4.header4= header4\n  %h5.header5= header5\n  %h6.header6= header6\n");
} catch(ex) {
$(".user-output").append("WARNING: HAML could not be compiled on this browser!<br/>");
}

//pure
window.tpl.pure = $p('div.pure').compile({
  h1: 'header',
  h2: 'header2',
  h3: 'header3',
  h4: 'header4',
  h5: 'header5',
  h6: 'header6'
});

//dust
(function(){dust.register("dusttmp",body_0);function body_0(chk,ctx){return chk.write("<h1 class='header'>").reference(ctx.get("header"),ctx,"h").write("</h1><h2 class='header2'>").reference(ctx.get("header2"),ctx,"h").write("</h2><h3 class='header3'>").reference(ctx.get("header3"),ctx,"h").write("</h3><h4 class='header4'>").reference(ctx.get("header4"),ctx,"h").write("</h4><h5 class='header5'>").reference(ctx.get("header5"),ctx,"h").write("</h5><h6 class='header6'>").reference(ctx.get("header6"),ctx,"h").write("</h6>");}return body_0;})();

//blueimp
window.tpl.blueimp = tmpl("<div><h1 class='header'>{%=o.header%}</h1><h2 class='header2'>{%=o.header2%}</h2><h3 class='header3'>{%=o.header3%}</h3><h4 class='header4'>{%=o.header4%}</h4><h5 class='header5'>{%=o.header5%}</h5><h6 class='header6'>{%=o.header6%}</h6></div>");

//eco
window.tpl.eco = eco("<div><h1 class='header'><%- @header %></h1><h2 class='header2'><%- @header2 %></h2><h3 class='header3'><%- @header3 %></h3><h4 class='header4'><%- @header4 %></h4><h5 class='header5'><%- @header5 %></h5><h6 class='header6'><%- @header6 %></h6></div>");

//Ejs
window.tpl.ejs = new EJS({text: "<div><h1 class='header'><%= header %></h1><h2 class='header2'><%= header2 %></h2><h3 class='header3'><%= header3 %></h3><h4 class='header4'><%= header4 %></h4><h5 class='header5'><%= header5 %></h5><h6 class='header6'><%= header6 %></h6></div>"});

//Jade JavaScript output of jade template compiled using node
window.tpl.jadeCmpld=function anonymous(locals,attrs,escape,rethrow){var attrs=jade.attrs,escape=jade.escape,rethrow=jade.rethrow;var buf=[];with(locals||{}){var interp;buf.push("<div><h1");buf.push(attrs({"class":("header")}));buf.push(">");var __val__=header;buf.push(escape(null==__val__?"":__val__));buf.push("</h1><h2");buf.push(attrs({"class":("header2")}));buf.push(">");var __val__=header2;buf.push(escape(null==__val__?"":__val__));buf.push("</h2><h3");buf.push(attrs({"class":("header3")}));buf.push(">");var __val__=header3;buf.push(escape(null==__val__?"":__val__));buf.push("</h3><h4");buf.push(attrs({"class":("header4")}));buf.push(">");var __val__=header4;buf.push(escape(null==__val__?"":__val__));buf.push("</h4><h5");buf.push(attrs({"class":("header5")}));buf.push(">");var __val__=header5;buf.push(escape(null==__val__?"":__val__));buf.push("</h5><h6");buf.push(attrs({"class":("header6")}));buf.push(">");var __val__=header6;buf.push(escape(null==__val__?"":__val__));buf.push("</h6></div><ul>");for(var item in list){buf.push("<li>");var __val__=item;buf.push(escape(null==__val__?"":__val__));buf.push("</li>")}buf.push("</ul>")}return buf.join("")};

//KiTe
window.tpl.kite = kite("<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#list}}<li class='item'>{{.}}</li>{{/list}}</ul></div>");

//jsRender
$.templates({ jsr: "<div><h1 class='header'>{{:header}}</h1><h2 class='header'>{{:header2}}</h2><h3 class='header'>{{:header3}}</h3><h4 class='header'>{{:header4}}</h4><h5 class='header'>{{:header5}}</h5><h6 class='header'>{{:header6}}</h6><ul class='list'>{{for list}}<li class='item'>{{:#data}}</li>{{/for}}</ul></div>" });

// Mote
window.tpl.mote = mote.compile("<div><h1 class='header'>{{{header}}}</h1><h2 class='header2'>{{{header2}}}</h2><h3 class='header3'>{{{header3}}}</h3><h4 class='header4'>{{{header4}}}</h4><h5 class='header5'>{{{header5}}}</h5><h6 class='header6'>{{{header6}}}</h6><ul class='list'>{{#list}}<li class='item'>{{{.}}}</li>{{/list}}</ul></div>");

// Template
window.tpl.template = new Template('<div><h1 class="header"><%= header %></h1><h2 class="header2"><%= header2 %></h2><h3 class="header3"><%= header3 %></h3><h4 class="header4"><%= header4 %></h4><h5 class="header5"><%= header5 %></h5><h6 class="header6"><%= header6 %></h6><ul class="list"><% for (var i = 0, l = list.length; i < l; i++) { %><li class="item"><%= list[i] %></li><% } %></ul></div>');

// vash
window.tpl.vash1 = vash.compile("<div><h1 class='header'>@model.header</h1><h2 class='header2'>@model.header2</h2><h3 class='header3'>@model.header3</h3><h4 class='header4'>@model.header4</h4><h5 class='header5'>@model.header5</h5><h6 class='header6'>@model.header6</h6><ul class='list'>@for (var i = 0, l = model.list.length; i < l; i++) { <li class='item'>@model.list[i]</li> } </ul></div>");

// vash without html escaping
window.tpl.vash2 = vash.compile("<div><h1 class='header'>@model.header</h1><h2 class='header2'>@model.header2</h2><h3 class='header3'>@model.header3</h3><h4 class='header4'>@model.header4</h4><h5 class='header5'>@model.header5</h5><h6 class='header6'>@model.header6</h6><ul class='list'>@for (var i = 0, l = model.list.length; i < l; i++) { <li class='item'>@model.list[i]</li> } </ul></div>", { htmlEscape: false });

window.grips.compile({grips:"{$: '#main' }<div><h1 class='header'>{$= $.header $}</h1><h2 class='header2'>{$= $.header2 $}</h2><h3 class='header3'>{$= $.header3 $}</h3><h4 class='header4'>{$= $.header4 $}</h4><h5 class='header5'>{$= $.header5 $}</h5><h6 class='header6'>{$= $.header6 $}</h6><ul class='list'>{$* $.list }<li class='item'>{$= _.value $}</li>{$}</ul></div>{$}"},true);

// NOTE: this variation of the previous grips template is only present to get around this performance "bug" in FF, otherwise the previous compile() call would have been sufficient.
// http://jsperf.com/functions-created-globally-or-via-new-function

(function(G){function __sort_fn__(a,b){ return a-b; }var partial = G.definePartial, clone = G.cloneObj, extend = G.extend, esc = G.strEscapes,unerr = new Error("Unknown error"),RLH = G.RangeLiteralHash,cID = "grips2";partial(function($,$$){$$ = clone($$) || {};var i, ret = "", ret2, _;ret += "<div><h1 class='header'>";ret += $.header;ret += "</h1><h2 class='header2'>";ret += $.header2;ret += "</h2><h3 class='header3'>";ret += $.header3;ret += "</h3><h4 class='header4'>";ret += $.header4;ret += "</h4><h5 class='header5'>";ret += $.header5;ret += "</h5><h6 class='header6'>";ret += $.header6;ret += "</h6><ul class='list'>";ret2 = (function(){function __iter__($,$$,value,key,index){var i, ret = "", ret2, _;if (value == null) return ret;$$ = clone($$);_ = {value: value,key: key,index: index,even: (index % 2) === 0,odd: (index % 2) === 1,first: (index === 0),last: (index === len - 1)};ret += "<li class='item'>";ret += _.value;ret += "</li>";return ret;}var i, j = 0, len, ret = "", it, tmp;it = $.list;if (it == null) {return "";}if (Array.isArray(it)) {len = it.length;for (i=0; i<len; i++) {ret2 = __iter__($,$$,it[i],""+i,i);ret += ret2;}} else if (typeof it === "object") {tmp = Object.keys(it);len = tmp.length;if (it instanceof RLH) {tmp.sort(__sort_fn__);}for (i=0; i<len; i++) {ret2 = __iter__($,$$,it[tmp[i]],tmp[i],i);ret += ret2;}} else {return unerr;}return ret;})();ret += ret2;ret += "</ul></div>";return ret;},"grips2#main");})(window.grips);

// use the partials directly from the cache (as most others do!)
window.tpl.grips = window.grips.collections["grips"].partials["#main"];
window.tpl.grips2 = window.grips.collections["grips2"].partials["#main"];

</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Mustache 0.5.0 DEV (compiled)
tpl.mustache(tpl.vars);
pending…
Kendo UI
tpl.kendo(tpl.vars);
pending…
Kendo UI (no "with" block)
tpl.kendo2(tpl.vars);
pending…
Handlebars
tpl.handlebars(tpl.vars)
pending…
Underscore
tpl.underscore(tpl.vars);
pending…
Resig Micro Templates
tpl.resig(tpl.vars)
pending…
Resig Micro Templates (No "with" block)
tpl.resig2(tpl.vars)
pending…
jqote2 (10/21/2010)
$.jqote(tpl.jqote, tpl.vars);
pending…
dot 0.2.0
tpl.dot(tpl.vars);
pending…
Hogan 1.0.3
tpl.hogan.render(tpl.vars)
pending…
Haml (7/16/11) (DOT2)
//WARNING: Compilation of the template fails in IE7!
tpl.doU(tpl.vars);
pending…
Pure
tpl.pure(tpl.vars);
pending…
Linked-in Dust
dust.render('dusttmp', tpl.vars, function() {});
pending…
Blueimp 1.0.2
window.tpl.blueimp(tpl.vars);
pending…
eco
tpl.eco(tpl.vars);
pending…
ejs
tpl.ejs.render(tpl.vars);
pending…
Jade
tpl.jadeCmpld(tpl.vars);
pending…
KiTE
tpl.kite(tpl.vars);
pending…
jsRender (jQuery Templates)
$.render.jsr(tpl.vars);
pending…
Mote
tpl.mote(tpl.vars);
pending…
Template
// Template has an internal cache!
tpl.template.data.compiled.call(tpl.vars, tpl.vars);
//tpl.template.render(tpl.vars);
pending…
Underscore - (no "with" block)
tpl.underscoreNoWith(tpl.vars);
pending…
Vash
tpl.vash1( tpl.vars ); 
pending…
Vash without html escaping
tpl.vash2( tpl.vars );
pending…
grips (direct partial, compiled)
// NOTE: this variation of the grips test is currently subject to a performance "bug" in FF.
// http://jsperf.com/functions-created-globally-or-via-new-function

tpl.grips( tpl.vars );
pending…
grips (direct partial, pre-compiled)
// NOTE: this variation of the previous grips test is only present to get around this performance "bug" in FF, otherwise the "compiled" test for grips would have been sufficient.
// http://jsperf.com/functions-created-globally-or-via-new-function

tpl.grips2( tpl.vars );
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment