Javascript templating shootoff (extended)

JavaScript performance comparison

Revision 67 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

<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="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0-rc.4/handlebars.min.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.3.3-a/grips-full.min.js"></script>
<script src="http://jlongster.github.io/nunjucks/browser/nunjucks-dev.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.tpl.nunjucks = new nunjucks.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 x in list%}<li class='item'>{{x}}</li>{% endfor %}</ul></div>", null, null, null, true);
</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)
tpl.grips( tpl.vars );
pending…
grips (direct partial, pre-compiled)

tpl.grips2( tpl.vars );
pending…
nunjucks
tpl.nunjucks.render(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