jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
A brief comparison of some JavaScript templating engines on a short template: 6 header tags, and 10 list items.
Note: When adding a new test, please ensure that your test returns the same HTML string (or equivalent DOM fragment) as the others.
Double note: many scripts have been embedded due to MIME type issues in some browsers. Sorry if the Preparation code is hard to navigate as a result.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.min.js"></script>
<script src="https://rawgithub.com/visionmedia/jade/master/jade.js"></script>
<!-- Milk.js -->
<script>
(function() {
var Expand, Find, Milk, Parse, TemplateCache, key;
var __slice = Array.prototype.slice;
TemplateCache = {};
Find = function(name, stack, value) {
var ctx, i, part, parts, _i, _len, _ref, _ref2, _ref3;
if (value == null) {
value = null;
}
if (name === '.') {
return stack[stack.length - 1];
}
_ref = name.split(/\./), name = _ref[0], parts = 2 <= _ref.length ? __slice.call(_ref, 1) : [];
for (i = _ref2 = stack.length - 1, _ref3 = -1; (_ref2 <= _ref3 ? i < _ref3 : i > _ref3); (_ref2 <= _ref3 ? i += 1 : i -= 1)) {
if (stack[i] == null) {
continue;
}
if (!(typeof stack[i] === 'object' && name in (ctx = stack[i]))) {
continue;
}
value = ctx[name];
break;
}
for (_i = 0, _len = parts.length; _i < _len; _i++) {
part = parts[_i];
value = Find(part, [value]);
}
if (value instanceof Function) {
value = (function(value) {
return function() {
var val;
val = value.apply(ctx, arguments);
return (val instanceof Function) && val.apply(null, arguments) || val;
};
})(value);
}
return value;
};
Expand = function() {
var args, f, obj, tmpl;
obj = arguments[0], tmpl = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
return ((function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = tmpl.length; _i < _len; _i++) {
f = tmpl[_i];
_results.push(f.call.apply(f, [obj].concat(__slice.call(args))));
}
return _results;
})()).join('');
};
Parse = function(template, delimiters, section) {
var BuildRegex, buffer, buildInterpolationTag, buildInvertedSectionTag, buildPartialTag, buildSectionTag, cache, content, contentEnd, d, error, escape, isStandalone, match, name, parseError, pos, sectionInfo, tag, tagPattern, tmpl, type, whitespace, _name, _ref, _ref2, _ref3;
if (delimiters == null) {
delimiters = ['{{', '}}'];
}
if (section == null) {
section = null;
}
cache = (TemplateCache[_name = delimiters.join(' ')] || (TemplateCache[_name] = {}));
if (template in cache) {
return cache[template];
}
buffer = [];
BuildRegex = function() {
var tagClose, tagOpen;
tagOpen = delimiters[0], tagClose = delimiters[1];
return RegExp("([\\s\\S]*?)([" + ' ' + "\\t]*)(?:" + tagOpen + "\\s*(?:(!)\\s*([\\s\\S]+?)|(=)\\s*([\\s\\S]+?)\\s*=|({)\\s*(\\w[\\S]*?)\\s*}|([^0-9a-zA-Z._!={]?)\\s*([\\w.][\\S]*?))\\s*" + tagClose + ")", "gm");
};
tagPattern = BuildRegex();
tagPattern.lastIndex = pos = (section || {
start: 0
}).start;
parseError = function(pos, msg) {
var carets, e, endOfLine, error, indent, key, lastLine, lastTag, lineNo, parsedLines, tagStart;
(endOfLine = /$/gm).lastIndex = pos;
endOfLine.exec(template);
parsedLines = template.substr(0, pos).split('\n');
lineNo = parsedLines.length;
lastLine = parsedLines[lineNo - 1];
tagStart = contentEnd + whitespace.length;
lastTag = template.substr(tagStart + 1, pos - tagStart - 1);
indent = new Array(lastLine.length - lastTag.length + 1).join(' ');
carets = new Array(lastTag.length + 1).join('^');
lastLine = lastLine + template.substr(pos, endOfLine.lastIndex - pos);
error = new Error();
for (key in e = {
"message": "" + msg + "\n\nLine " + lineNo + ":\n" + lastLine + "\n" + indent + carets,
"error": msg,
"line": lineNo,
"char": indent.length,
"tag": lastTag
}) {
error[key] = e[key];
}
return error;
};
while (match = tagPattern.exec(template)) {
_ref = match.slice(1, 3), content = _ref[0], whitespace = _ref[1];
type = match[3] || match[5] || match[7] || match[9];
tag = match[4] || match[6] || match[8] || match[10];
contentEnd = (pos + content.length) - 1;
pos = tagPattern.lastIndex;
isStandalone = (contentEnd === -1 || template.charAt(contentEnd) === '\n') && ((_ref2 = template.charAt(pos)) === void 0 || _ref2 === '' || _ref2 === '\r' || _ref2 === '\n');
if (content) {
buffer.push((function(content) {
return function() {
return content;
};
})(content));
}
if (isStandalone && (type !== '' && type !== '&' && type !== '{')) {
if (template.charAt(pos) === '\r') {
pos += 1;
}
if (template.charAt(pos) === '\n') {
pos += 1;
}
} else if (whitespace) {
buffer.push((function(whitespace) {
return function() {
return whitespace;
};
})(whitespace));
contentEnd += whitespace.length;
whitespace = '';
}
switch (type) {
case '!':
break;
case '':
case '&':
case '{':
buildInterpolationTag = function(name, is_unescaped) {
return function(context) {
var value, _ref;
if ((value = (_ref = Find(name, context)) != null ? _ref : '') instanceof Function) {
value = Expand.apply(null, [this, Parse("" + (value()))].concat(__slice.call(arguments)));
}
if (!is_unescaped) {
value = this.escape("" + value);
}
return "" + value;
};
};
buffer.push(buildInterpolationTag(tag, type));
break;
case '>':
buildPartialTag = function(name, indentation) {
return function(context, partials) {
var partial;
partial = partials(name).toString();
if (indentation) {
partial = partial.replace(/^(?=.)/gm, indentation);
}
return Expand.apply(null, [this, Parse(partial)].concat(__slice.call(arguments)));
};
};
buffer.push(buildPartialTag(tag, whitespace));
break;
case '#':
case '^':
sectionInfo = {
name: tag,
start: pos,
error: parseError(tagPattern.lastIndex, "Unclosed section '" + tag + "'!")
};
_ref3 = Parse(template, delimiters, sectionInfo), tmpl = _ref3[0], pos = _ref3[1];
sectionInfo['#'] = buildSectionTag = function(name, delims, raw) {
return function(context) {
var parsed, result, v, value;
value = Find(name, context) || [];
tmpl = value instanceof Function ? value(raw) : raw;
if (!(value instanceof Array)) {
value = [value];
}
parsed = Parse(tmpl || '', delims);
context.push(value);
result = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = value.length; _i < _len; _i++) {
v = value[_i];
context[context.length - 1] = v;
_results.push(Expand.apply(null, [this, parsed].concat(__slice.call(arguments))));
}
return _results;
}).apply(this, arguments);
context.pop();
return result.join('');
};
};
sectionInfo['^'] = buildInvertedSectionTag = function(name, delims, raw) {
return function(context) {
var value;
value = Find(name, context) || [];
if (!(value instanceof Array)) {
value = [1];
}
value = value.length === 0 ? Parse(raw, delims) : [];
return Expand.apply(null, [this, value].concat(__slice.call(arguments)));
};
};
buffer.push(sectionInfo[type](tag, delimiters, tmpl));
break;
case '/':
if (section == null) {
error = "End Section tag '" + tag + "' found, but not in section!";
} else if (tag !== (name = section.name)) {
error = "End Section tag closes '" + tag + "'; expected '" + name + "'!";
}
if (error) {
throw parseError(tagPattern.lastIndex, error);
}
template = template.slice(section.start, (contentEnd + 1) || 9e9);
cache[template] = buffer;
return [template, pos];
case '=':
if ((delimiters = tag.split(/\s+/)).length !== 2) {
error = "Set Delimiters tags should have two and only two values!";
}
if (error) {
throw parseError(tagPattern.lastIndex, error);
}
escape = /[-[\]{}()*+?.,\\^$|#]/g;
delimiters = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = delimiters.length; _i < _len; _i++) {
d = delimiters[_i];
_results.push(d.replace(escape, "\\$&"));
}
return _results;
})();
tagPattern = BuildRegex();
break;
default:
throw parseError(tagPattern.lastIndex, "Unknown tag type -- " + type);
}
tagPattern.lastIndex = pos != null ? pos : template.length;
}
if (section != null) {
throw section.error;
}
if (template.length !== pos) {
buffer.push(function() {
return template.slice(pos);
});
}
return cache[template] = buffer;
};
Milk = {
VERSION: '1.2.0',
helpers: [],
partials: null,
escape: function(value) {
var entities;
entities = {
'&': 'amp',
'"': 'quot',
'<': 'lt',
'>': 'gt'
};
return value.replace(/[&"<>]/g, function(ch) {
return "&" + entities[ch] + ";";
});
},
render: function(template, data, partials) {
var context;
if (partials == null) {
partials = null;
}
if (!((partials || (partials = this.partials || {})) instanceof Function)) {
partials = (function(partials) {
return function(name) {
if (!(name in partials)) {
throw "Unknown partial '" + name + "'!";
}
return Find(name, [partials]);
};
})(partials);
}
context = this.helpers instanceof Array ? this.helpers : [this.helpers];
return Expand(this, Parse(template), context.concat([data]), partials);
}
};
if (typeof exports != "undefined" && exports !== null) {
for (key in Milk) {
exports[key] = Milk[key];
}
} else {
this.Milk = Milk;
}
}).call(this);
</script>
<script src="http://terrainformatica.com/kite/kite.js"></script>
<script src="http://github.com/downloads/wycats/handlebars.js/handlebars-0.9.0.pre.4.js"></script>
<!-- https://gist.githubusercontent.com/jashkenas/550881/raw/29bb186167079c0b33ab6e9d50d779f37860cfa4/micro.js -->
<script>
(function() {
var cache = {};
this.tmpl = function tmpl(str, data) {
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +
// Introduce the data as local variables using with(){}
"with(obj){p.push('" +
// Convert the template into pure JavaScript
str.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('');");
// Provide some basic currying to the user
return data ? fn(data) : fn;
};
})();
</script>
<!-- https://gist.githubusercontent.com/akorchev/860205/raw/8444586913ab249c619671b8f5054fc92dddf643/micro2.js -->
<script>
(function() {
var cache = {};
this.tmpl2 = function tmpl(str, data) {
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("data",
"var p=[];" +
// Introduce the data as local variables using with(){}
"p.push('" +
// Convert the template into pure JavaScript
str.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('');");
// Provide some basic currying to the user
return data ? fn(data) : fn;
};
})();
</script>
<!-- https://gist.githubusercontent.com/akorchev/860240/raw/cd98cacbdeee7eb2cfb2ca3ca76638dae2a5b1af/micro3.js -->
<script>
(function() {
this.tmpl3 = function tmpl(str, data) {
var value = "var out = ''; out+=" + "'" +
str.replace(/[\r\t\n]/g, " ")
.replace(/'(?=[^%]*%>)/g,"\t")
.split("'").join("\\'")
.split("\t").join("'")
.replace(/<%=(.+?)%>/g, "'; out += $1; out += '")
.split("<%").join("';")
.split("%>").join("out+='")
+ "'; return out;";
return new Function("data", value);
}
})();
</script>
<!-- http://github.com/creationix/haml-js/raw/master/lib/haml.js -->
<script>
// <![CDATA[
var Haml;
(function () {
var matchers, self_close_tags, embedder, forceXML, escaperName, escapeHtmlByDefault;
function html_escape(text) {
return (text + "").
replace(/&/g, "&").
replace(/</g, "<").
replace(/>/g, ">").
replace(/\"/g, """);
}
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("");
}
// Parse the attribute block using a state machine
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 we reach the end of the line, then there is a problem
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;
}
// Split interpolated strings into an array of literals and code fragments.
function parse_interpol(value) {
var items = [],
pos = 0,
next = 0,
match;
while (true) {
// Match up to embedded string
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 embedded string
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{
//unsafe!!!
items.push(match[2] || match[3]);
}
pos += next;
}
return items.filter(function (part) { return part && part.length > 0}).join(" +\n");
}
// Used to find embedded code in interpolated strings.
embedder = /([#!])\{([^}]*)\}/;
self_close_tags = ["meta", "img", "link", "br", "hr", "input", "area", "base"];
// All matchers' regexps should capture leading whitespace in first capture
// and trailing content in last capture
matchers = [
// html tags
{
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);
// Default to <div> tag
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);
//once we've identified the tag and its attributes, the rest is content.
// this is currently trimmed for neatness.
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{ //remove quotes if they are there
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 now contains '"<b>hello</b>"'
//we need to crack it open to insert whitespace.
output = '" '+output.substr(1, output.length - 2)+' "';
}
return output;
}
},
// each loops
{
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__', // index
vvar = this.matches[3], // value
avar = this.matches[4], // array
rvar = '__result__'; // results
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)';
}
},
// if statements
{
name: "if",
regexp: /^(\s*):if\s+(.*)\s*$/i,
process: function () {
var condition = this.matches[2];
this.pushIfCondition([condition]);
return '(function () { ' +
'if (' + condition + ') { ' +
'return (\n' + (this.render_contents() || '') + '\n);' +
'} else { return ""; } }).call(this)';
}
},
// else if statements
{
name: "else if",
regexp: /^(\s*):else if\s+(.*)\s*$/i,
process: function () {
var condition = this.matches[2],
conditionsArray = this.getIfConditions()[this.getIfConditions().length - 1],
ifArray = [],
ifStatement;
for (var i=0, l=conditionsArray.length; i<l; i++) {
ifArray.push('! (' + conditionsArray[i]+')');
}
conditionsArray.push(condition);
ifArray.push(condition);
ifStatement = 'if (' + ifArray.join(' && ') + ') { ';
return '(function () { ' +
ifStatement +
'return (\n' + (this.render_contents() || '') + '\n);' +
'} else { return ""; } }).call(this)';
}
},
// else statements
{
name: "else",
regexp: /^(\s*):else\s*$/i,
process: function () {
var conditionsArray = this.popIfCondition(),
ifArray = [],
ifStatement;
for (var i=0, l=conditionsArray.length; i<l; i++) {
ifArray.push('! (' + conditionsArray[i]+')');
}
ifStatement = 'if (' + ifArray.join(' && ') + ') { ';
return '(function () { ' +
ifStatement +
'return (\n' + (this.render_contents() || '') + '\n);' +
'} else { return ""; } }).call(this)';
}
},
// silent-comments
{
name: "silent-comments",
regexp: /^(\s*)-#\s*(.*)\s*$/i,
process: function () {
return '""';
}
},
//html-comments
{
name: "silent-comments",
regexp: /^(\s*)\/\s*(.*)\s*$/i,
process: function () {
this.contents.unshift(this.matches[2]);
return '"<!--'+this.contents.join('\\n').replace(/\"/g, '\\"')+'-->"';
}
},
// raw js
{
name: "rawjs",
regexp: /^(\s*)-\s*(.*)\s*$/i,
process: function () {
this.contents.unshift(this.matches[2]);
return '"";' + this.contents.join("\n")+"; _$output = _$output ";
}
},
// raw js
{
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>"';
}
},
// declarations
{
name: "doctype",
regexp: /^()!!!(?:\s*(.*))\s*$/,
process: function () {
var line = '';
switch ((this.matches[2] || '').toLowerCase()) {
case '':
// XHTML 1.0 Transitional
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':
// XHTML 1.0 Strict
line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
break;
case 'frameset':
// XHTML 1.0 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':
// XHTML 5
line = '<!DOCTYPE html>';
break;
case '1.1':
// XHTML 1.1
line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
break;
case 'basic':
// XHTML Basic 1.1
line = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">';
break;
case 'mobile':
// XHTML Mobile 1.2
line = '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">';
break;
case 'xml':
// XML
line = "<?xml version='1.0' encoding='utf-8' ?>";
break;
case 'xml iso-8859-1':
// XML iso-8859-1
line = "<?xml version='1.0' encoding='iso-8859-1' ?>";
break;
}
return JSON.stringify(line + "\n");
}
},
// Embedded markdown. Needs to be added to exports externally.
{
name: "markdown",
regexp: /^(\s*):markdown\s*$/i,
process: function () {
return parse_interpol(exports.Markdown.encode(this.contents.join("\n")));
}
},
// script blocks
{
name: "script",
regexp: /^(\s*):(?:java)?script\s*$/,
process: function () {
return parse_interpol('\n<script>\n' +
'//<![CDATA[\n' +
this.contents.join("\n") +
"\n//]]>\n<\/script>\n");
}
},
// css blocks
{
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 = [],
ifConditions = [];
// If lines is a string, turn it into an array
if (typeof lines === 'string') {
lines = lines.trim().replace(/\n\r|\r/g, '\n').split('\n');
}
lines.forEach(function(line) {
var match, found = false;
// Collect all text as raw until outdent
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,
getIfConditions: function() {
return ifConditions;
},
pushIfCondition: function(condition) {
ifConditions.push(condition);
},
popIfCondition: function() {
return ifConditions.pop();
},
render_contents: function () {
return compile(this.contents);
}
};
found = true;
}
}
});
// Match plain text
if (!found) {
output.push(function () {
// Escaped plain text
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;
}
}
// always escaped
if((line.substr(0, 2) === "&=")) {
line = line.substr(2, line.length).trim();
return escapedLine();
}
//never escaped
if((line.substr(0, 2) === "!=")) {
line = line.substr(2, line.length).trim();
return unescapedLine();
}
// sometimes escaped
if ( (line[0] === '=')) {
line = line.substr(1, line.length).trim();
if(escapeHtmlByDefault){
return escapedLine();
}else{
return unescapedLine();
}
}
// Plain text
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; //set in eval
} 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){
if ( typeof(console) !== 'undefined' ) { console.error(str); }
throw e;
}
}
Haml.compile = compile;
Haml.optimize = optimize;
Haml.render = render;
Haml.execute = execute;
Haml.html_escape = html_escape;
}());
// Hook into module system
if (typeof module !== 'undefined') {
module.exports = Haml;
}
//]]>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/coffee-script/1.7.1/coffee-script.min.js"></script>
<!-- http://sstephenson.github.com/eco/dist/eco.js -->
<script>
/**
* Eco Compiler v1.1.0-pre
* http://github.com/sstephenson/eco
*
* Copyright (c) 2010 Sam Stephenson
* Released under the MIT License
*/
this.eco=function(j){return function g(h){var b,c={id:h,exports:{}};if(b=j[h]){b(c,g,c.exports);return c.exports}else throw"Cannot find module '"+h+"'";}}({eco:function(j,g){g("coffee-script");j.exports=g("eco/compiler")},"eco/compiler":function(j,g){(function(){var h,b,c,d,f;h=g("coffee-script");d=g("eco/util").indent;j.exports=c=function(a){(new Function("module",b(a)))(a={});return a.exports};c.preprocess=f=g("eco/preprocessor").preprocess;c.compile=b=function(a,e){var i,k;k=typeof(i=typeof e===
"undefined"||e===null?undefined:e.identifier)!=="undefined"&&i!==null?i:"module.exports";k.match(/\./)||(k="var "+k);i=h.compile(f(a),{noWrap:true});return""+k+" = function(__obj) {\n if (!__obj) __obj = {};\n var __out = [], __capture = function(callback) {\n var out = __out, result;\n __out = [];\n callback.call(this);\n result = __out.join('');\n __out = out;\n return __safe(result);\n }, __sanitize = function(value) {\n if (value && value.ecoSafe) {\n return value;\n } else if (typeof value !== 'undefined' && value != null) {\n return __escape(value);\n } else {\n return '';\n }\n }, __safe, __objSafe = __obj.safe, __escape = __obj.escape;\n __safe = __obj.safe = function(value) {\n if (value && value.ecoSafe) {\n return value;\n } else {\n if (!(typeof value !== 'undefined' && value != null)) value = '';\n var result = new String(value);\n result.ecoSafe = true;\n return result;\n }\n };\n if (!__escape) {\n __escape = __obj.escape = function(value) {\n return ('' + value)\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n };\n }\n (function() {\n"+
d(i,4)+"\n }).call(__obj);\n __obj.safe = __objSafe, __obj.escape = __escape;\n return __out.join('');\n};"};c.render=function(a,e){return c(a)(e)};if(g.extensions)g.extensions[".eco"]=function(a,e){var i;i=g("fs").readFileSync(e,"utf-8");return a._compile(b(i),e)};else g.registerExtension&&g.registerExtension(".eco",b)}).call(this)},"eco/preprocessor":function(j,g,h){(function(){var b,c,d,f=function(a,e){return function(){return a.apply(e,arguments)}};c=g("eco/scanner").Scanner;d=g("eco/util");
h.preprocess=function(a){return(new b(a)).preprocess()};h.Preprocessor=function(){b=function(a){this.scanner=new c(a);this.output="";this.level=0;this.options={};this.captures=[];return this};b.prototype.preprocess=function(){for(;!this.scanner.done;)this.scanner.scan(f(function(a){return this[a[0]].apply(this,a.slice(1))},this));return this.output};b.prototype.record=function(a){this.output+=d.repeat(" ",this.level);return this.output+=a+"\n"};b.prototype.printString=function(a){return a.length?
this.record("__out.push "+d.inspectString(a)):null};b.prototype.beginCode=function(a){return this.options=a};b.prototype.recordCode=function(a){return a!=="end"?this.options.print?this.options.safe?this.record("__out.push "+a):this.record("__out.push __sanitize "+a):this.record(a):null};b.prototype.indent=function(a){this.level++;if(a){this.record("__capture "+a);this.captures.unshift(this.level);return this.indent()}};b.prototype.dedent=function(){this.level--;this.level<0&&this.fail("unexpected dedent");
if(this.captures[0]===this.level){this.captures.shift();return this.dedent()}};b.prototype.fail=function(a){throw"Parse error on line "+this.scanner.lineNo+": "+a;};return b}()}).call(this)},"eco/scanner":function(j,g,h){(function(){var b,c,d,f;d=g("strscan");c=d.StringScanner;d=g("eco/util");f=d.trim;h.scan=function(a){var e;e=[];for(a=new b(a);!a.done;)a.scan(function(i){return e.push(i)});return e};h.Scanner=function(){b=function(a){this.source=a.replace(/\r\n?/g,"\n");this.scanner=new c(this.source);
this.mode="data";this.buffer="";this.lineNo=1;this.done=false;return this};b.modePatterns={data:/(.*?)(<%(([=-])?)|\n|$)/,code:/(.*?)(((:|(->|=>))\s*)?%>|\n|$)/};b.dedentablePattern=/^(end|when|else|catch|finally)(?:\W|$)/;b.prototype.scan=function(a){if(this.done)return a();else if(this.scanner.hasTerminated()){this.done=true;switch(this.mode){case "data":return a(["printString",this.flush()]);case "code":return a(["fail","unexpected end of template"])}}else{this.advance();switch(this.mode){case "data":return this.scanData(a);
case "code":return this.scanCode(a)}}};b.prototype.advance=function(){this.scanner.scanUntil(b.modePatterns[this.mode]);this.buffer+=this.scanner.getCapture(0);this.tail=this.scanner.getCapture(1);this.directive=this.scanner.getCapture(3);return this.arrow=this.scanner.getCapture(4)};b.prototype.scanData=function(a){var e;if(this.tail==="\n"){this.buffer+=this.tail;this.lineNo++;return this.scan(a)}else if(this.tail){this.mode="code";a(["printString",this.flush()]);return a(["beginCode",{print:typeof(e=
this.directive)!=="undefined"&&e!==null,safe:this.directive==="-"}])}};b.prototype.scanCode=function(a){var e;if(this.tail==="\n")return a(["fail","unexpected newline in code block"]);else if(this.tail){this.mode="data";e=f(this.flush());if(this.arrow)e+=" "+this.arrow;this.isDedentable(e)&&a(["dedent"]);a(["recordCode",e]);if(this.directive)return a(["indent",this.arrow])}};b.prototype.flush=function(){var a;a=this.buffer;this.buffer="";return a};b.prototype.isDedentable=function(a){return a.match(b.dedentablePattern)};
return b}.call(this)}).call(this)},"eco/util":function(j,g,h){(function(){var b,c;h.repeat=b=function(d,f){return Array(f+1).join(d)};h.indent=function(d,f){var a,e,i,k,l,m;m=b(" ",f);k=[];i=d.split("\n");a=0;for(e=i.length;a<e;a++){l=i[a];k.push(m+l)}return k.join("\n")};h.trim=function(d){return d.replace(/^\s+/,"").replace(/\s+$/,"")};c={"\\":"\\\\","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t"};h.inspectString=function(d){return"'"+d.replace(/[\x00-\x1f\\]/g,function(f){if(f in
c)return c[f];else{f=f.charCodeAt(0).toString(16);if(f.length===1)f="0"+f;return"\\u00"+f}}).replace(/'/g,"\\'")+"'"}}).call(this)},strscan:function(j,g,h){(function(){var b;(typeof h!=="undefined"&&h!==null?h:this).StringScanner=function(){b=function(c){this.source=c.toString();this.reset();return this};b.prototype.scan=function(c){var d;return(d=c.exec(this.getRemainder()))&&d.index===0?this.setState(d,{head:this.head+d[0].length,last:this.head}):this.setState([])};b.prototype.scanUntil=function(c){if(c=
c.exec(this.getRemainder())){this.setState(c,{head:this.head+c.index+c[0].length,last:this.head});return this.source.slice(this.last,this.head)}else return this.setState([])};b.prototype.scanChar=function(){return this.scan(/./)};b.prototype.skip=function(c){if(this.scan(c))return this.match.length};b.prototype.skipUntil=function(c){if(this.scanUntil(c))return this.head-this.last};b.prototype.check=function(c){var d;return(d=c.exec(this.getRemainder()))&&d.index===0?this.setState(d):this.setState([])};
b.prototype.checkUntil=function(c){if(c=c.exec(this.getRemainder())){this.setState(c);return this.source.slice(this.head,this.head+c.index+c[0].length)}else return this.setState([])};b.prototype.peek=function(c){return this.source.substr(this.head,typeof c!=="undefined"&&c!==null?c:1)};b.prototype.getSource=function(){return this.source};b.prototype.getRemainder=function(){return this.source.slice(this.head)};b.prototype.getPosition=function(){return this.head};b.prototype.hasTerminated=function(){return this.head===
this.source.length};b.prototype.getPreMatch=function(){if(this.match)return this.source.slice(0,this.head-this.match.length)};b.prototype.getMatch=function(){return this.match};b.prototype.getPostMatch=function(){if(this.match)return this.source.slice(this.head)};b.prototype.getCapture=function(c){return this.captures[c]};b.prototype.reset=function(){return this.setState([],{head:0,last:0})};b.prototype.terminate=function(){return this.setState([],{head:this.source.length,last:this.head})};b.prototype.concat=
function(c){return this.source+=c};b.prototype.unscan=function(){if(this.match)return this.setState([],{head:this.last,last:0});else throw"nothing to unscan";};b.prototype.setState=function(c,d){var f,a;this.head=typeof(f=typeof d==="undefined"||d===null?undefined:d.head)!=="undefined"&&f!==null?f:this.head;this.last=typeof(a=typeof d==="undefined"||d===null?undefined:d.last)!=="undefined"&&a!==null?a:this.last;this.captures=c.slice(1);return this.match=c[0]};return b}()})()},"coffee-script":function(j){if(typeof CoffeeScript!==
"undefined"&&CoffeeScript!=null)j.exports=CoffeeScript;else throw"Cannot require '"+j.id+"': CoffeeScript not found";}})("eco");
</script>
<!-- https://raw.github.com/BorisMoore/jquery-tmpl/master/jquery.tmpl.min.js -->
<script>
/*
* jQuery Templates Plugin 1.0.0pre
* http://github.com/jquery/jquery-tmpl
* Requires jQuery 1.4.2
*
* Copyright 2011, Software Freedom Conservancy, Inc.
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
(function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h<m;h++){c=h;k=(h>0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i<j&&!(f=a.data(h[i++],"tmplItem")));if(f&&c)g[2]=function(b){a.tmpl.afterManip(this,b,k)};r.apply(this,g)}else r.apply(this,arguments);c=0;!e&&a.tmpl.complete(b);return this}});a.extend({tmpl:function(d,h,e,c){var i,k=!c;if(k){c=p;d=a.template[d]||a.template(null,d);f={}}else if(!d){d=c.tmpl;b[c.key]=c;c.nodes=[];c.wrapped&&n(c,c.wrapped);return a(j(c,null,c.tmpl(a,c)))}if(!d)return[];if(typeof h==="function")h=h.call(c||{});e&&e.wrapped&&n(e,e.wrapped);i=a.isArray(h)?a.map(h,function(a){return a?g(e,c,d,a):null}):[g(e,c,d,h)];return k?a(j(c,null,i)):i},tmplItem:function(b){var c;if(b instanceof a)b=b[0];while(b&&b.nodeType===1&&!(c=a.data(b,"tmplItem"))&&(b=b.parentNode));return c||p},template:function(c,b){if(b){if(typeof b==="string")b=o(b);else if(b instanceof a)b=b[0]||{};if(b.nodeType)b=a.data(b,"tmpl")||a.data(b,"tmpl",o(b.innerHTML));return typeof c==="string"?(a.template[c]=b):b}return c?typeof c!=="string"?a.template(null,c):a.template[c]||a.template(null,q.test(c)?c:a(c)):null},encode:function(a){return(""+a).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(__,$1,$2);__=[];",close:"call=$item.calls();__=call._.concat($item.wrap(call,__));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else f=e=i.$1||"null";g=h(g);return"');"+j[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(f).split("$1").join(e).split("$2").join(g||i.$2||"")+"__.push('"})+"');}return __;")}function n(c,b){c._wrap=j(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function h(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,h;for(e=0,p=o.length;e<p;e++){if((k=o[e]).nodeType!==1)continue;j=k.getElementsByTagName("*");for(h=j.length-1;h>=0;h--)m(j[h]);m(k)}function m(j){var p,h=j,k,e,m;if(m=j.getAttribute(d)){while(h.parentNode&&(h=h.parentNode).nodeType===1&&!(p=h.getAttribute(d)));if(p!==m){h=h.parentNode?h.nodeType===11?0:h.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[h]||f[h]);e.key=++i;b[i]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;h=a.data(j.parentNode,"tmplItem");h=h?h.key:0}if(e){k=e;while(k&&k.key!=h){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery);
</script>
<!-- https://github.com/olado/doT/raw/master/doT.js -->
<script>
// doT.js
// 2011, Laura Doktorova, https://github.com/olado/doT
// Licensed under the MIT license.
(function() {
"use strict";
var doT = {
version: '1.0.1',
templateSettings: {
evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
interpolate: /\{\{=([\s\S]+?)\}\}/g,
encode: /\{\{!([\s\S]+?)\}\}/g,
use: /\{\{#([\s\S]+?)\}\}/g,
useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
defineParams:/^\s*([\w$]+):([\s\S]+)/,
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, //fn, compile template
compile: undefined //fn, for express
}, global;
if (typeof module !== 'undefined' && module.exports) {
module.exports = doT;
} else if (typeof define === 'function' && define.amd) {
define(function(){return doT;});
} else {
global = (function(){ return this || (0,eval)('this'); }());
global.doT = doT;
}
function encodeHTMLSource() {
var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' },
matchHTML = /&(?!#?\w+;)|<|>|"|'|\//g;
return function() {
return this ? this.replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : this;
};
}
String.prototype.encodeHTML = encodeHTMLSource();
var startend = {
append: { start: "'+(", end: ")+'", endencode: "||'').toString().encodeHTML()+'" },
split: { start: "';out+=(", end: ");out+='", endencode: "||'').toString().encodeHTML();out+='"}
}, skip = /$^/;
function resolveDefs(c, block, def) {
return ((typeof block === 'string') ? block : block.toString())
.replace(c.define || skip, function(m, code, assign, value) {
if (code.indexOf('def.') === 0) {
code = code.substring(4);
}
if (!(code in def)) {
if (assign === ':') {
if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
def[code] = {arg: param, text: v};
});
if (!(code in def)) def[code]= value;
} else {
new Function("def", "def['"+code+"']=" + value)(def);
}
}
return '';
})
.replace(c.use || skip, function(m, code) {
if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
if (def[d] && def[d].arg && param) {
var rw = (d+":"+param).replace(/'|\\/g, '_');
def.__exp = def.__exp || {};
def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
return s + "def.__exp['"+rw+"']";
}
});
var v = new Function("def", "return " + code)(def);
return v ? resolveDefs(c, v, def) : v;
});
}
function unescape(code) {
return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, ' ');
}
doT.template = function(tmpl, c, def) {
c = c || doT.templateSettings;
var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,' ')
.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,''): str)
.replace(/'|\\/g, '\\$&')
.replace(c.interpolate || skip, function(m, code) {
return cse.start + unescape(code) + cse.end;
})
.replace(c.encode || skip, function(m, code) {
needhtmlencode = true;
return cse.start + unescape(code) + cse.endencode;
})
.replace(c.conditional || skip, function(m, elsecase, code) {
return elsecase ?
(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
})
.replace(c.iterate || skip, function(m, iterate, vname, iname) {
if (!iterate) return "';} } out+='";
sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
+vname+"=arr"+sid+"["+indv+"+=1];out+='";
})
.replace(c.evaluate || skip, function(m, code) {
return "';" + unescape(code) + "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 (needhtmlencode && c.selfcontained) {
str = "String.prototype.encodeHTML=(" + encodeHTMLSource.toString() + "());" + str;
}
try {
return new Function(c.varname, str);
} catch (e) {
if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
throw e;
}
};
doT.compile = function(tmpl, def) {
return doT.template(tmpl, null, def);
};
}());
</script>
<!-- https://github.com/olado/doT/raw/master/doU.js -->
<script>
// doU.js
// (c) 2011, Laura Doktorova
// https://github.com/olado/doT
//
// doU is an extraction and slight modification of an excellent
// templating function from jQote2.js (jQuery plugin) by aefxx
// (http://aefxx.com/jquery-plugins/jqote2/).
//
// Modifications:
// 1. nodejs support
// 2. allow for custom template markers
// 3. only allow direct invocation of the compiled function
//
// Licensed under the MIT license.
(function() {
var doU = { version : '0.1.2' };
if (typeof module !== 'undefined' && module.exports) {
module.exports = doU;
} else {
this.doU = doU;
}
doU.templateSettings = {
begin : '{{',
end : '}}',
varname : 'it'
};
doU.template = function(tmpl, conf) {
conf = conf || doU.templateSettings;
var str = '', tb = conf.begin, te = conf.end, m, l,
arr = tmpl.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g, '')
.split(tb).join(te +'\x1b')
.split(te);
for (m=0,l=arr.length; m < l; m++) {
str += arr[m].charAt(0) !== '\x1b' ?
"out+='" + arr[m].replace(/(\\|["'])/g, '\\$1') + "'" : (arr[m].charAt(1) === '=' ?
';out+=(' + arr[m].substr(2) + ');' : (arr[m].charAt(1) === '!' ?
';out+=(' + arr[m].substr(2) + ").toString().replace(/&(?!\\w+;)/g, '&').split('<').join('<').split('>').join('>').split('" + '"' + "').join('"').split(" + '"' + "'" + '"' + ").join(''').split('/').join('/');" : ';' + arr[m].substr(1)));
}
str = ('var out="";'+str+';return out;')
.split("out+='';").join('')
.split('var out="";out+=').join('var out=');
try {
return new Function(conf.varname, str);
} catch (e) {
if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
throw e;
}
};
}());
</script>
<!-- http://github.com/aefxx/jQote2/raw/69b2053a13f5f180e696de9b3dba856a3c00678c/jquery.jqote2.js -->
<script>
/*
* jQote2 - client-side Javascript templating engine
* Copyright (C) 2010, aefxx
* http://aefxx.com/
*
* Dual licensed under the WTFPL v2 or MIT (X11) licenses
* WTFPL v2 Copyright (C) 2004, Sam Hocevar
*
* Date: Thu, Oct 21st, 2010
* Version: 0.9.7
*/
(function($) {
var JQOTE2_TMPL_UNDEF_ERROR = 'UndefinedTemplateError',
JQOTE2_TMPL_COMP_ERROR = 'TemplateCompilationError',
JQOTE2_TMPL_EXEC_ERROR = 'TemplateExecutionError';
var ARR = '[object Array]',
STR = '[object String]',
FUNC = '[object Function]';
var n = 1, tag = '%',
qreg = /^[^<]*(<[\w\W]+>)[^>]*$/,
type_of = Object.prototype.toString;
function raise(error, ext) {
throw ($.extend(error, ext), error);
}
function dotted_ns(fn) {
var ns = [];
if ( type_of.call(fn) !== ARR ) return false;
for ( var i=0,l=fn.length; i < l; i++ )
ns[i] = fn[i].jqote_id;
return ns.length ?
ns.sort().join('.').replace(/(\b\d+\b)\.(?:\1(\.|$))+/g, '$1$2') : false;
}
function lambda(tmpl, t) {
var f, fn = [], t = t || tag,
type = type_of.call(tmpl);
if ( type === FUNC )
return tmpl.jqote_id ? [tmpl] : false;
if ( type !== ARR )
return [$.jqotec(tmpl, t)];
if ( type === ARR )
for ( var i=0,l=tmpl.length; i < l; i++ )
if ( f = lambda(tmpl[i], t) ) fn.push(f[0]);
return fn.length ? fn : false;
}
$.fn.extend({
jqote: function(data, t) {
var data = type_of.call(data) === ARR ? data : [data],
dom = '';
this.each(function(i) {
var fn = $.jqotec(this, t);
for ( var j=0; j < data.length; j++ )
dom += fn.call(data[j], i, j, data, fn);
});
return dom;
}
});
$.each({app: 'append', pre: 'prepend', sub: 'html'}, function(name, method) {
$.fn['jqote'+name] = function(elem, data, t) {
var ns, regexp, str = $.jqote(elem, data, t),
$$ = !qreg.test(str) ?
function(str) {return $(document.createTextNode(str));} : $;
if ( !!(ns = dotted_ns(lambda(elem))) )
regexp = new RegExp('(^|\\.)'+ns.split('.').join('\\.(.*)?')+'(\\.|$)');
return this.each(function() {
var dom = $$(str);
$(this)[method](dom);
( dom[0].nodeType === 3 ?
$(this) : dom ).trigger('jqote.'+name, [dom, regexp]);
});
};
});
$.extend({
jqote: function(elem, data, t) {
var str = '', t = t || tag,
fn = lambda(elem);
if ( fn === false )
raise(new Error('Empty or undefined template passed to $.jqote'), {type: JQOTE2_TMPL_UNDEF_ERROR});
data = type_of.call(data) !== ARR ?
[data] : data;
for ( var i=0,l=fn.length; i < l; i++ )
for ( var j=0; j < data.length; j++ )
str += fn[i].call(data[j], i, j, data, fn[i]);
return str;
},
jqotec: function(template, t) {
var cache, elem, tmpl, t = t || tag,
type = type_of.call(template);
if ( type === STR && qreg.test(template) ) {
elem = tmpl = template;
if ( cache = $.jqotecache[template] ) return cache;
} else {
elem = type === STR || template.nodeType ?
$(template) : template instanceof jQuery ?
template : null;
if ( !elem[0] || !(tmpl = elem[0].innerHTML) && !(tmpl = elem.text()) )
raise(new Error('Empty or undefined template passed to $.jqotec'), {type: JQOTE2_TMPL_UNDEF_ERROR});
if ( cache = $.jqotecache[$.data(elem[0], 'jqote_id')] ) return cache;
}
var str = '', index,
arr = tmpl.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]/g, '')
.split('<'+t).join(t+'>\x1b')
.split(t+'>');
for ( var m=0,l=arr.length; m < l; m++ )
str += arr[m].charAt(0) !== '\x1b' ?
"out+='" + arr[m].replace(/(\\|["'])/g, '\\$1') + "'" : (arr[m].charAt(1) === '=' ?
';out+=(' + arr[m].substr(2) + ');' : (arr[m].charAt(1) === '!' ?
';out+=$.jqotenc((' + arr[m].substr(2) + '));' : ';' + arr[m].substr(1)));
str = 'try{' +
('var out="";'+str+';return out;')
.split("out+='';").join('')
.split('var out="";out+=').join('var out=') +
'}catch(e){e.type="'+JQOTE2_TMPL_EXEC_ERROR+'";e.args=arguments;e.template=arguments.callee.toString();throw e;}';
try {
var fn = new Function('i, j, data, fn', str);
} catch ( e ) { raise(e, {type: JQOTE2_TMPL_COMP_ERROR}); }
index = elem instanceof jQuery ?
$.data(elem[0], 'jqote_id', n) : elem;
return $.jqotecache[index] = (fn.jqote_id = n++, fn);
},
jqotefn: function(elem) {
var type = type_of.call(elem),
index = type === STR && qreg.test(elem) ?
elem : $.data($(elem)[0], 'jqote_id');
return $.jqotecache[index] || false;
},
jqotetag: function(str) {
if ( type_of.call(str) === STR ) tag = str;
},
jqotenc: function(str) {
return s.toString()
.replace(/&(?!\w+;)/g, '&')
.split('<').join('<').split('>').join('>')
.split('"').join('"').split("'").join(''');
},
jqotecache: {}
});
$.event.special.jqote = {
add: function(obj) {
var ns, handler = obj.handler,
data = !obj.data ?
[] : type_of.call(obj.data) !== ARR ?
[obj.data] : obj.data;
if ( !obj.namespace ) obj.namespace = 'app.pre.sub';
if ( !data.length || !(ns = dotted_ns(lambda(data))) ) return;
obj.handler = function(event, dom, regexp) {
return !regexp || regexp.test(ns) ?
handler.apply(this, [event, dom]) : null;
};
}
};
})(jQuery);
</script>
<!-- http://embeddedjavascript.googlecode.com/files/ejs_0.9_alpha_1_production.js -->
<script>
String.prototype.rsplit=function(F){var E=this;var A=F.exec(E);var G=new Array();while(A!=null){var D=A.index;var C=F.lastIndex;if((D)!=0){var B=E.substring(0,D);G.push(E.substring(0,D));E=E.slice(D)}G.push(A[0]);E=E.slice(A[0].length);A=F.exec(E)}if(!E==""){G.push(E)}return G};String.prototype.chop=function(){return this.substr(0,this.length-1)};var EjsScanner=function(B,C,A){this.left_delimiter=C+"%";this.right_delimiter="%"+A;this.double_left=C+"%%";this.double_right="%%"+A;this.left_equal=C+"%=";this.left_comment=C+"%#";if(C=="["){this.SplitRegexp=/(\[%%)|(%%\])|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/}else{this.SplitRegexp=new RegExp("("+this.double_left+")|(%%"+this.double_right+")|("+this.left_equal+")|("+this.left_comment+")|("+this.left_delimiter+")|("+this.right_delimiter+"\n)|("+this.right_delimiter+")|(\n)")}this.source=B;this.stag=null;this.lines=0};EjsView=function(A){this.data=A};EjsView.prototype.partial=function(A,B){if(!B){B=this.data}return new EJS(A).render(B)};EjsScanner.to_text=function(A){if(A==null||A===undefined){return""}if(A instanceof Date){return A.toDateString()}if(A.toString){return A.toString()}return""};EjsScanner.prototype={scan:function(D){scanline=this.scanline;regex=this.SplitRegexp;if(!this.source==""){var C=this.source.rsplit(/\n/);for(var A=0;A<C.length;A++){var B=C[A];this.scanline(B,regex,D)}}},scanline:function(A,D,G){this.lines++;var E=A.rsplit(D);for(var C=0;C<E.length;C++){var B=E[C];if(B!=null){try{G(B,this)}catch(F){throw {type:"EjsScanner",line:this.lines}}}}}};var EjsBuffer=function(B,C){this.line=new Array();this.script="";this.pre_cmd=B;this.post_cmd=C;for(var A=0;A<this.pre_cmd.length;A++){this.push(B[A])}};EjsBuffer.prototype={push:function(A){this.line.push(A)},cr:function(){this.script=this.script+this.line.join("; ");this.line=new Array();this.script=this.script+"\n"},close:function(){if(this.line.length>0){for(var A=0;A<this.post_cmd.length;A++){this.push(pre_cmd[A])}this.script=this.script+this.line.join("; ");line=null}}};EjsCompiler=function(B,C){this.pre_cmd=['___ejsO = "";'];this.post_cmd=new Array();this.source=" ";if(B!=null){if(typeof B=="string"){B=B.replace(/\r\n/g,"\n");B=B.replace(/\r/g,"\n");this.source=B}else{if(B.innerHTML){this.source=B.innerHTML}}if(typeof this.source!="string"){this.source=""}}C=C||"<";var A=">";switch(C){case"[":A="]";break;case"<":break;default:throw C+" is not a supported deliminator";break}this.scanner=new EjsScanner(this.source,C,A);this.out=""};EjsCompiler.prototype={compile:function(options){options=options||{};this.out="";var put_cmd="___ejsO += ";var insert_cmd=put_cmd;var buff=new EjsBuffer(this.pre_cmd,this.post_cmd);var content="";var clean=function(content){content=content.replace(/\\/g,"\\\\");content=content.replace(/\n/g,"\\n");content=content.replace(/"/g,'\\"');return content};this.scanner.scan(function(token,scanner){if(scanner.stag==null){switch(token){case"\n":content=content+"\n";buff.push(put_cmd+'"'+clean(content)+'";');buff.cr();content="";break;case scanner.left_delimiter:case scanner.left_equal:case scanner.left_comment:scanner.stag=token;if(content.length>0){buff.push(put_cmd+'"'+clean(content)+'"')}content="";break;case scanner.double_left:content=content+scanner.left_delimiter;break;default:content=content+token;break}}else{switch(token){case scanner.right_delimiter:switch(scanner.stag){case scanner.left_delimiter:if(content[content.length-1]=="\n"){content=content.chop();buff.push(content);buff.cr()}else{buff.push(content)}break;case scanner.left_equal:buff.push(insert_cmd+"(EjsScanner.to_text("+content+"))");break}scanner.stag=null;content="";break;case scanner.double_right:content=content+scanner.right_delimiter;break;default:content=content+token;break}}});if(content.length>0){buff.push(put_cmd+'"'+clean(content)+'"')}buff.close();this.out=buff.script+";";var to_be_evaled="this.process = function(_CONTEXT,_VIEW) { try { with(_VIEW) { with (_CONTEXT) {"+this.out+" return ___ejsO;}}}catch(e){e.lineNumber=null;throw e;}};";try{eval(to_be_evaled)}catch(e){if(typeof JSLINT!="undefined"){JSLINT(this.out);for(var i=0;i<JSLINT.errors.length;i++){var error=JSLINT.errors[i];if(error.reason!="Unnecessary semicolon."){error.line++;var e=new Error();e.lineNumber=error.line;e.message=error.reason;if(options.url){e.fileName=options.url}throw e}}}else{throw e}}}};EJS=function(B){this.set_options(B);if(B.url){var C=EJS.get(B.url,this.cache);if(C){return C}if(C==EJS.INVALID_PATH){return null}this.text=EJS.request(B.url);if(this.text==null){throw"There is no template at "+B.url}this.name=B.url}else{if(B.element){if(typeof B.element=="string"){var A=B.element;B.element=document.getElementById(B.element);if(B.element==null){throw A+"does not exist!"}}if(B.element.value){this.text=B.element.value}else{this.text=B.element.innerHTML}this.name=B.element.id;this.type="["}}var C=new EjsCompiler(this.text,this.type);C.compile(B);EJS.update(this.name,this);this.template=C};EJS.config=function(B){EJS.cache=B.cache!=null?B.cache:EJS.cache;EJS.type=B.type!=null?B.type:EJS.type;var A={};EJS.get=function(D,C){if(C==false){return null}if(A[D]){return A[D]}return null};EJS.update=function(D,C){if(D==null){return }A[D]=C};EJS.INVALID_PATH=-1};EJS.config({cache:true,type:"<"});EJS.prototype={render:function(B){var A=new EjsView(B);return this.template.process.call(A,B,A)},out:function(){return this.template.out},set_options:function(A){this.type=A.type!=null?A.type:EJS.type;this.cache=A.cache!=null?A.cache:EJS.cache;this.text=A.text!=null?A.text:null;this.name=A.name!=null?A.name:null},update:function(element,options){if(typeof element=="string"){element=document.getElementById(element)}if(options==null){_template=this;return function(object){EJS.prototype.update.call(_template,element,object)}}if(typeof options=="string"){params={};params.url=options;_template=this;params.onComplete=function(request){var object=eval(request.responseText);EJS.prototype.update.call(_template,element,object)};EJS.ajax_request(params)}else{element.innerHTML=this.render(options)}}};EJS.newRequest=function(){var C=[function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new XMLHttpRequest()},function(){return new ActiveXObject("Microsoft.XMLHTTP")}];for(var A=0;A<C.length;A++){try{var B=C[A]();if(B!=null){return B}}catch(D){continue}}};EJS.request=function(C){var A=new EJS.newRequest();A.open("GET",C,false);try{A.send(null)}catch(B){return null}if(A.status==404||A.status==2||(A.status==0&&A.responseText=="")){return null}return A.responseText};EJS.ajax_request=function(B){B.method=(B.method?B.method:"GET");var A=new EJS.newRequest();A.onreadystatechange=function(){if(A.readyState==4){if(A.status==200){B.onComplete(A)}else{B.onComplete(A)}}};A.open(B.method,B.url);A.send(null)};EjsView.prototype.date_tag=function(C,O,A){if(!(O instanceof Date)){O=new Date()}var B=["January","February","March","April","May","June","July","August","September","October","November","December"];var G=[],D=[],P=[];var J=O.getFullYear();var H=O.getMonth();var N=O.getDate();for(var M=J-15;M<J+15;M++){G.push({value:M,text:M})}for(var E=0;E<12;E++){D.push({value:(E),text:B[E]})}for(var I=0;I<31;I++){P.push({value:(I+1),text:(I+1)})}var L=this.select_tag(C+"[year]",J,G,{id:C+"[year]"});var F=this.select_tag(C+"[month]",H,D,{id:C+"[month]"});var K=this.select_tag(C+"[day]",N,P,{id:C+"[day]"});return L+F+K};EjsView.prototype.form_tag=function(B,A){A=A||{};A.action=B;if(A.multipart==true){A.method="post";A.enctype="multipart/form-data"}return this.start_tag_for("form",A)};EjsView.prototype.form_tag_end=function(){return this.tag_end("form")};EjsView.prototype.hidden_field_tag=function(A,C,B){return this.input_field_tag(A,C,"hidden",B)};EjsView.prototype.input_field_tag=function(A,D,C,B){B=B||{};B.id=B.id||A;B.value=D||"";B.type=C||"text";B.name=A;return this.single_tag_for("input",B)};EjsView.prototype.is_current_page=function(A){return(window.location.href==A||window.location.pathname==A?true:false)};EjsView.prototype.link_to=function(B,A,C){if(!B){var B="null"}if(!C){var C={}}if(C.confirm){C.onclick=' var ret_confirm = confirm("'+C.confirm+'"); if(!ret_confirm){ return false;} ';C.confirm=null}C.href=A;return this.start_tag_for("a",C)+B+this.tag_end("a")};EjsView.prototype.submit_link_to=function(B,A,C){if(!B){var B="null"}if(!C){var C={}}C.onclick=C.onclick||"";if(C.confirm){C.onclick=' var ret_confirm = confirm("'+C.confirm+'"); if(!ret_confirm){ return false;} ';C.confirm=null}C.value=B;C.type="submit";C.onclick=C.onclick+(A?this.url_for(A):"")+"return false;";return this.start_tag_for("input",C)};EjsView.prototype.link_to_if=function(F,B,A,D,C,E){return this.link_to_unless((F==false),B,A,D,C,E)};EjsView.prototype.link_to_unless=function(E,B,A,C,D){C=C||{};if(E){if(D&&typeof D=="function"){return D(B,A,C,D)}else{return B}}else{return this.link_to(B,A,C)}};EjsView.prototype.link_to_unless_current=function(B,A,C,D){C=C||{};return this.link_to_unless(this.is_current_page(A),B,A,C,D)};EjsView.prototype.password_field_tag=function(A,C,B){return this.input_field_tag(A,C,"password",B)};EjsView.prototype.select_tag=function(D,G,H,F){F=F||{};F.id=F.id||D;F.value=G;F.name=D;var B="";B+=this.start_tag_for("select",F);for(var E=0;E<H.length;E++){var C=H[E];var A={value:C.value};if(C.value==G){A.selected="selected"}B+=this.start_tag_for("option",A)+C.text+this.tag_end("option")}B+=this.tag_end("select");return B};EjsView.prototype.single_tag_for=function(A,B){return this.tag(A,B,"/>")};EjsView.prototype.start_tag_for=function(A,B){return this.tag(A,B)};EjsView.prototype.submit_tag=function(A,B){B=B||{};B.type=B.type||"submit";B.value=A||"Submit";return this.single_tag_for("input",B)};EjsView.prototype.tag=function(C,E,D){if(!D){var D=">"}var B=" ";for(var A in E){if(E[A]!=null){var F=E[A].toString()}else{var F=""}if(A=="Class"){A="class"}if(F.indexOf("'")!=-1){B+=A+'="'+F+'" '}else{B+=A+"='"+F+"' "}}return"<"+C+B+D};EjsView.prototype.tag_end=function(A){return"</"+A+">"};EjsView.prototype.text_area_tag=function(A,C,B){B=B||{};B.id=B.id||A;B.name=B.name||A;C=C||"";if(B.size){B.cols=B.size.split("x")[0];B.rows=B.size.split("x")[1];delete B.size}B.cols=B.cols||50;B.rows=B.rows||4;return this.start_tag_for("textarea",B)+C+this.tag_end("textarea")};EjsView.prototype.text_tag=EjsView.prototype.text_area_tag;EjsView.prototype.text_field_tag=function(A,C,B){return this.input_field_tag(A,C,"text",B)};EjsView.prototype.url_for=function(A){return'window.location="'+A+'";'};EjsView.prototype.img_tag=function(B,C,A){A=A||{};A.src=B;A.alt=C;return this.single_tag_for("img",A)}
</script>
<!-- http://github.com/pure/pure/raw/master/libs/pure.js -->
<script>
/*!
PURE Unobtrusive Rendering Engine for HTML
Licensed under the MIT licenses.
More information at: http://www.opensource.org
Copyright (c) 2013 Michael Cvilic - BeeBole.com
Thanks to Rog Peppe for the functional JS jump
revision: 2.83
*/
var $p = function(){
var args = arguments,
sel = args[0],
ctxt = false;
if(typeof sel === 'string'){
ctxt = args[1] || false;
}else if(sel && !sel[0] && !sel.length){
sel = [sel];
}
return $p.core(sel, ctxt);
},
pure = $p;
$p.core = function(sel, ctxt, plugins){
//get an instance of the plugins
var templates = [], i, ii,
// set the signature string that will be replaced at render time
Sig = '_s' + Math.floor( Math.random() * 1000000 ) + '_',
// another signature to prepend to attributes and avoid checks: style, height, on[events]...
attPfx = '_a' + Math.floor( Math.random() * 1000000 ) + '_',
// rx to parse selectors, e.g. "+tr.foo[class]"
selRx = /^(\+)?([^\@\+]+)?\@?([^\+]+)?(\+)?$/,
// set automatically attributes for some tags
autoAttr = {
IMG:'src',
INPUT:'value'
},
// check if the argument is an array - thanks salty-horse (Ori Avtalion)
isArray = Array.isArray ?
function(o) {
return Array.isArray(o);
} :
function(o) {
return Object.prototype.toString.call(o) === "[object Array]";
};
plugins = plugins || getPlugins();
//search for the template node(s)
switch(typeof sel){
case 'string':
templates = plugins.find(ctxt || document, sel);
if(templates.length === 0) {
error('The template "' + sel + '" was not found');
}
break;
case 'undefined':
error('The root of the template is undefined, check your selector');
break;
default:
templates = sel;
}
for( i = 0, ii = templates.length; i < ii; i++){
plugins[i] = templates[i];
}
plugins.length = ii;
/* * * * * * * * * * * * * * * * * * * * * * * * * *
core functions
* * * * * * * * * * * * * * * * * * * * * * * * * */
// error utility
function error(e){
if(typeof console !== 'undefined'){
console.log(e);
//debugger;
}
throw('pure error: ' + e);
}
//return a new instance of plugins
function getPlugins(){
var plugins = $p.plugins,
f = function(){};
f.prototype = plugins;
// do not overwrite functions if external definition
f.prototype.compile = plugins.compile || compile;
f.prototype.render = plugins.render || render;
f.prototype.autoRender = plugins.autoRender || autoRender;
f.prototype.find = plugins.find || find;
// give the compiler and the error handling to the plugin context
f.prototype._compiler = compiler;
f.prototype._error = error;
return new f();
}
// returns the outer HTML of a node
function outerHTML(node){
// if IE, Chrome take the internal method otherwise build one
return node.outerHTML || (
function(n){
var div = document.createElement('div'), h;
div.appendChild( n.cloneNode(true) );
h = div.innerHTML;
div = null;
return h;
}(node));
}
// returns the string generator function
function wrapquote(qfn, f){
return function(ctxt){
return qfn( String( f.call(ctxt.item || ctxt.context, ctxt) ) ) ;
};
}
// default find using querySelector when available on the browser
function find(n, sel){
if(typeof n === 'string'){
sel = n;
n = false;
}
return (n||document).querySelectorAll( sel );
}
// create a function that concatenates constant string
// sections (given in parts) and the results of called
// functions to fill in the gaps between parts (fns).
// fns[n] fills in the gap between parts[n-1] and parts[n];
// fns[0] is unused.
// this is the inner template evaluation loop.
function concatenator(parts, fns){
return function(ctxt){
var strs = [ parts[ 0 ] ],
n = parts.length,
fnVal, pVal, attLine, pos, i;
try{
for(i = 1; i < n; i++){
fnVal = fns[i].call( this, ctxt );
pVal = parts[i];
// if the value is empty and attribute, remove it
if(fnVal === ''){
attLine = strs[ strs.length - 1 ];
if( ( pos = attLine.search( /[^\s]+=\"?$/ ) ) > -1){
strs[ strs.length - 1 ] = attLine.substring( 0, pos );
pVal = pVal.substr( 1 );
}
}
strs[ strs.length ] = fnVal;
strs[ strs.length ] = pVal;
}
return strs.join('');
}catch(e){
if(console && console.log){
console.log(
e.stack ||
e.message + ' (' + e.type + ( e['arguments'] ? ', ' + e['arguments'].join('-') : '' ) + '). Use Firefox or Chromium/Chrome to get a full stack of the error. ' );
}
return '';
}
};
}
// parse and check the loop directive
function parseloopspec(p){
var m = p.match( /^(\w+)\s*<-\s*(\S+)?$/ );
if(m === null){
error('bad loop spec: "' + p + '"');
}
if(m[1] === 'item'){
error('"item<-..." is a reserved word for the current running iteration.\n\nPlease choose another name for your loop.');
}
if( !m[2] || m[2].toLowerCase() === 'context' ){ //undefined or space(IE)
m[2] = function(ctxt){return ctxt.context;};
}else if( (m[2] && m[2].indexOf('context') === 0 ) ){ //undefined or space(IE)
m[2] = dataselectfn( m[2].replace(/^context\.?/, '') );
}
return {name: m[1], sel: m[2]};
}
// parse a data selector and return a function that
// can traverse the data accordingly, given a context.
function dataselectfn (sel){
if( typeof(sel) === 'function' ){
//handle false values in function directive
return function ( ctxt ){
var r = sel.call( ctxt.item || ctxt.context || ctxt, ctxt );
return !r && r !== 0 ? '' : r;
};
}
//check for a valid js variable name with hyphen(for properties only), $, _ and :
var m = sel.match(/^[\da-zA-Z\$_\@\#][\w\$:\-\#]*(\.[\w\$:\-\#]*[^\.])*$/),
found = false, s = sel, parts = [], pfns = [], i = 0, retStr;
if(m === null){
// check if literal
if(/\'|\"/.test( s.charAt(0) )){
if(/\'|\"/.test( s.charAt(s.length-1) )){
retStr = s.substring(1, s.length-1);
return function(){ return retStr; };
}
}else{
// check if literal + #{var}
while((m = s.match(/#\{([^{}]+)\}/)) !== null){
found = true;
parts[i++] = s.slice(0, m.index);
pfns[i] = dataselectfn(m[1]);
s = s.slice(m.index + m[0].length, s.length);
}
}
if(!found){ //constant, return it
return function(){ return sel; };
}
parts[i] = s;
return concatenator(parts, pfns);
}
m = sel.split('.');
return function(ctxt){
var data = ctxt.context || ctxt,
v = ctxt[m[0]],
i = 0,
n,
dm;
if(v && typeof v.item !== 'undefined'){
i += 1;
if(m[i] === 'pos'){
//allow pos to be kept by string. Tx to Adam Freidin
return v.pos;
}
data = v.item;
}
n = m.length;
while( i < n ){
if(!data){break;}
dm = data[ m[i] ];
//if it is a function call it
data = typeof dm === 'function' ? dm.call( data ) : dm;
i++;
}
return (!data && data !== 0) ? '':data;
};
}
// wrap in an object the target node/attr and their properties
function gettarget(dom, sel, isloop){
var osel, prepend, selector, attr, append, target = [], m,
setstr, getstr, quotefn, isStyle, isClass, attName, setfn;
if( typeof sel === 'string' ){
osel = sel;
m = sel.match(selRx);
if( !m ){
error( 'bad selector syntax: ' + sel );
}
prepend = m[1];
selector = m[2];
attr = m[3];
append = m[4];
if(selector === '.' || ( !selector && attr ) ){
target[0] = dom;
}else{
target = plugins.find(dom, selector);
}
if(!target || target.length === 0){
return error('The node "' + sel + '" was not found in the template:\n' + outerHTML(dom).replace(/\t/g,' '));
}
}else{
// autoRender node
prepend = sel.prepend;
attr = sel.attr;
append = sel.append;
target = [dom];
}
if( prepend || append ){
if( prepend && append ){
error('append/prepend cannot take place at the same time');
}else if( isloop ){
error('no append/prepend/replace modifiers allowed for loop target');
}else if( append && isloop ){
error('cannot append with loop (sel: ' + osel + ')');
}
}
if(attr){
isStyle = (/^style$/i).test(attr);
isClass = (/^class$/i).test(attr);
attName = isClass ? 'className' : attr;
setstr = function(node, s) {
node.setAttribute(attPfx + attr, s);
if ( node[attName] && !isStyle) {
try{node[attName] = '';}catch(e){} //FF4 gives an error sometimes
}
if (node.nodeType === 1) {
node.removeAttribute(attr);
if(isClass){
node.removeAttribute(attName);
}
}
};
if (isStyle || isClass) {//IE no quotes special care
if(isStyle){
getstr = function(n){ return n.style.cssText; };
}else{
getstr = function(n){ return n.className; };
}
}else {
getstr = function(n){ return n.getAttribute(attr); };
}
quotefn = function(s){ return s.replace(/\"/g, '"'); };
if(prepend){
setfn = function(node, s){ setstr( node, s + getstr( node )); };
}else if(append){
setfn = function(node, s){ setstr( node, getstr( node ) + s); };
}else{
setfn = function(node, s){ setstr( node, s ); };
}
}else{
if (isloop) {
setfn = function(node, s) {
var pn = node.parentNode;
if (pn) {
//replace node with s
pn.insertBefore(document.createTextNode(s), node.nextSibling);
pn.removeChild(node);
}else{
error('The template root, can\'t be looped.');
}
};
} else {
if (prepend) {
setfn = function(node, s) { node.insertBefore(document.createTextNode(s), node.firstChild); };
} else if (append) {
setfn = function(node, s) { node.appendChild(document.createTextNode(s));};
} else {
setfn = function(node, s) {
while (node.firstChild) { node.removeChild(node.firstChild); }
node.appendChild(document.createTextNode(s));
};
}
}
quotefn = function(s) { return s; };
}
return { attr: attr, nodes: target, set: setfn, sel: osel, quotefn: quotefn };
}
function setsig(target, n){
var sig = Sig + n + ':', i;
for(i = 0; i < target.nodes.length; i++){
// could check for overlapping targets here.
target.set( target.nodes[i], sig );
}
}
// read de loop data, and pass it to the inner rendering function
function loopfn(name, dselect, inner, sorter, filter){
return function(ctxt){
var a = dselect(ctxt),
old = ctxt[name],
temp = { items : a },
filtered = 0,
length,
strs = [],
buildArg = function(idx, temp, ftr, len){
//keep the current loop. Tx to Adam Freidin
var save_pos = ctxt.pos,
save_item = ctxt.item,
save_items = ctxt.items;
ctxt.pos = temp.pos = idx;
ctxt.item = temp.item = a[ idx ];
ctxt.items = a;
//if array, set a length property - filtered items
if(typeof len !== 'undefined'){ (ctxt.length = len); }
//if filter directive
if(typeof ftr === 'function' && ftr.call(ctxt.item, ctxt) === false){
filtered++;
return;
}
strs.push( inner.call(ctxt.item, ctxt ) );
//restore the current loop
ctxt.pos = save_pos;
ctxt.item = save_item;
ctxt.items = save_items;
},
prop, i, ii;
ctxt[name] = temp;
if( isArray(a) ){
length = a.length || 0;
// if sort directive
if(typeof sorter === 'function'){
a.sort(function(a, b){
return sorter.call(ctxt, a, b);
});
}
//loop on array
for(i = 0, ii = length; i < ii; i++){
buildArg(i, temp, filter, length - filtered);
}
}else{
if(a && typeof sorter !== 'undefined'){
error('sort is only available on arrays, not objects');
}
//loop on collections
for( prop in a ){
if( a.hasOwnProperty( prop ) ){
buildArg(prop, temp, filter);
}
}
}
if( typeof old !== 'undefined'){
ctxt[name] = old;
}else{
delete ctxt[name];
}
return strs.join('');
};
}
// generate the template for a loop node
function loopgen(dom, sel, loop, fns){
var already = false, ls, sorter, filter, prop, dsel, spec, itersel, target, nodes, node, inner;
for(prop in loop){
if(loop.hasOwnProperty(prop)){
if(prop === 'sort'){
sorter = loop.sort;
}else if(prop === 'filter'){
filter = loop.filter;
}else if(already){
error('cannot have more than one loop on a target');
}else{
ls = prop;
already = true;
}
}
}
if(!ls){
error('Error in the selector: ' + sel + '\nA directive action must be a string, a function or a loop(<-)');
}
dsel = loop[ls];
// if it's a simple data selector then we default to contents, not replacement.
if(typeof(dsel) === 'string' || typeof(dsel) === 'function'){
loop = {};
loop[ls] = {root: dsel};
return loopgen(dom, sel, loop, fns);
}
spec = parseloopspec(ls);
itersel = dataselectfn(spec.sel);
target = gettarget(dom, sel, true);
nodes = target.nodes;
for(i = 0; i < nodes.length; i++){
node = nodes[i];
inner = compiler(node, dsel);
fns[fns.length] = wrapquote(target.quotefn, loopfn(spec.name, itersel, inner, sorter, filter));
target.nodes = [node]; // N.B. side effect on target.
setsig(target, fns.length - 1);
}
return target;
}
function getAutoNodes(n, data){
var ns = n.getElementsByTagName('*'),
an = [],
openLoops = {a:[],l:{}},
cspec,
isNodeValue,
i, ii, j, jj, ni, cs, cj;
//for each node found in the template
for(i = -1, ii = ns.length; i < ii; i++){
ni = i > -1 ?ns[i]:n;
if(ni.nodeType === 1 && ni.className !== ''){
//when a className is found
cs = ni.className.split(' ');
// for each className
for(j = 0, jj=cs.length;j<jj;j++){
cj = cs[j];
// check if it is related to a context property
cspec = checkClass(cj, ni.tagName);
// if so, store the node, plus the type of data
if(cspec !== false){
isNodeValue = (/nodevalue/i).test(cspec.attr);
if(cspec.sel.indexOf('@') > -1 || isNodeValue){
ni.className = ni.className.replace('@'+cspec.attr, '');
if(isNodeValue){
cspec.attr = false;
}
}
an.push({n:ni, cspec:cspec});
}
}
}
}
function checkClass(c, tagName){
// read the class
var ca = c.match(selRx),
attr = ca[3] || autoAttr[tagName],
cspec = {prepend:!!ca[1], prop:ca[2], attr:attr, append:!!ca[4], sel:c},
i, ii, loopi, loopil, val;
// check in existing open loops
for(i = openLoops.a.length-1; i >= 0; i--){
loopi = openLoops.a[i];
loopil = loopi.l[0];
val = loopil && loopil[cspec.prop];
if(typeof val !== 'undefined'){
cspec.prop = loopi.p + '.' + cspec.prop;
if(openLoops.l[cspec.prop] === true){
val = val[0];
}
break;
}
}
// not found check first level of data
if(typeof val === 'undefined'){
val = dataselectfn(cspec.prop)(isArray(data) ? data[0] : data);
// nothing found return
if(val === ''){
return false;
}
}
// set the spec for autoNode
if(isArray(val)){
openLoops.a.push( {l:val, p:cspec.prop} );
openLoops.l[cspec.prop] = true;
cspec.t = 'loop';
}else{
cspec.t = 'str';
}
return cspec;
}
return an;
}
// returns a function that, given a context argument,
// will render the template defined by dom and directive.
function compiler(dom, directive, data, ans){
var fns = [], j, jj, cspec, n, target, nodes, itersel, node, inner, dsel, sels, sel, sl, i, h, parts, pfns = [], p;
// autoRendering nodes parsing -> auto-nodes
ans = ans || (data && getAutoNodes(dom, data));
if(data){
// for each auto-nodes
while(ans.length > 0){
cspec = ans[0].cspec;
n = ans[0].n;
ans.splice(0, 1);
if(cspec.t === 'str'){
// if the target is a value
target = gettarget(n, cspec, false);
setsig(target, fns.length);
fns[fns.length] = wrapquote(target.quotefn, dataselectfn(cspec.prop));
}else{
// if the target is a loop
itersel = dataselectfn(cspec.sel);
target = gettarget(n, cspec, true);
nodes = target.nodes;
for(j = 0, jj = nodes.length; j < jj; j++){
node = nodes[j];
inner = compiler(node, false, data, ans);
fns[fns.length] = wrapquote(target.quotefn, loopfn(cspec.sel, itersel, inner));
target.nodes = [node];
setsig(target, fns.length - 1);
}
}
}
}
// read directives
for(sel in directive){
if(directive.hasOwnProperty(sel)){
i = 0;
dsel = directive[sel];
sels = sel.split(/\s*,\s*/); //allow selector separation by quotes
sl = sels.length;
do{
if(typeof(dsel) === 'function' || typeof(dsel) === 'string'){
// set the value for the node/attr
sel = sels[i];
target = gettarget(dom, sel, false);
setsig(target, fns.length);
fns[fns.length] = wrapquote(target.quotefn, dataselectfn(dsel));
}else{
// loop on node
loopgen(dom, sel, dsel, fns);
}
}while(++i < sl);
}
}
// convert node to a string
h = outerHTML(dom);
// IE adds an unremovable "selected, value" attribute
// hard replace while waiting for a better solution
h = h.replace(/<([^>]+)\s(value\=""|selected)\s?([^>]*)>/ig, "<$1 $3>");
// remove attribute prefix
h = h.split(attPfx).join('');
// slice the html string at "Sig"
parts = h.split( Sig );
// for each slice add the return string of
for(i = 1; i < parts.length; i++){
p = parts[i];
// part is of the form "fn-number:..." as placed there by setsig.
pfns[i] = fns[ parseInt(p, 10) ];
parts[i] = p.substring( p.indexOf(':') + 1 );
}
return concatenator(parts, pfns);
}
// compile the template with directive
// if a context is passed, the autoRendering is triggered automatically
// return a function waiting the data as argument
function compile(directive, ctxt, template){
var rfn = compiler( ( template || this[0] ).cloneNode(true), directive, ctxt);
return function(context){
return rfn({context:context});
};
}
//compile with the directive as argument
// run the template function on the context argument
// return an HTML string
// should replace the template and return this
function render(ctxt, directive){
var fn = typeof directive === 'function' && directive, i, ii;
for(i = 0, ii = this.length; i < ii; i++){
this[i] = replaceWith( this[i], (fn || plugins.compile( directive, false, this[i] ))( ctxt, false ));
}
return this;
}
// compile the template with autoRender
// run the template function on the context argument
// return an HTML string
function autoRender(ctxt, directive){
var fn = plugins.compile( directive, ctxt, this[0] ), i, ii;
for(i = 0, ii = this.length; i < ii; i++){
this[i] = replaceWith( this[i], fn( ctxt, false));
}
return this;
}
function replaceWith(elm, html) {
var ne,
ep = elm.parentNode,
depth = 0,
tmp;
if(!ep){ //if no parents
ep = document.createElement('DIV');
ep.appendChild(elm);
}
switch (elm.tagName) {
case 'BODY': //thanks to milan.adamovsky@gmail.com
ep.removeChild(elm);
ep.innerHTML += html;
return ep.getElementsByTagName('BODY')[0];
case 'TBODY': case 'THEAD': case 'TFOOT':
html = '<TABLE>' + html + '</TABLE>';
depth = 1;
break;
case 'TR':
html = '<TABLE><TBODY>' + html + '</TBODY></TABLE>';
depth = 2;
break;
case 'TD': case 'TH':
html = '<TABLE><TBODY><TR>' + html + '</TR></TBODY></TABLE>';
depth = 3;
break;
case 'OPTGROUP': case 'OPTION':
html = '<SELECT>' + html + '</SELECT>';
depth = 1;
break;
}
tmp = document.createElement('SPAN');
tmp.style.display = 'none';
document.body.appendChild(tmp);
tmp.innerHTML = html;
ne = tmp.firstChild;
while (depth--) {
ne = ne.firstChild;
}
ep.insertBefore(ne, elm);
ep.removeChild(elm);
document.body.removeChild(tmp);
elm = ne;
ne = ep = null;
return elm;
}
return plugins;
};
$p.plugins = {};
$p.libs = {
dojo:function(){
return function(n, sel){
return dojo.query(sel, n);
};
},
domassistant:function(){
DOMAssistant.attach({
publicMethods : [ 'compile', 'render', 'autoRender'],
compile:function(directive, ctxt){
return $p([this]).compile(directive, ctxt);
},
render:function(ctxt, directive){
return $( $p([this]).render(ctxt, directive) )[0];
},
autoRender:function(ctxt, directive){
return $( $p([this]).autoRender(ctxt, directive) )[0];
}
});
return function(n, sel){
return $(n).cssSelect(sel);
};
},
ext:function(){//Thanks to Greg Steirer
return function(n, sel){
return Ext.query(sel, n);
};
},
jquery:function(){
jQuery.fn.extend({
directives:function(directive){
this._pure_d = directive; return this;
},
compile:function(directive, ctxt){
return $p(this).compile(this._pure_d || directive, ctxt);
},
render:function(ctxt, directive){
return jQuery( $p( this ).render( ctxt, this._pure_d || directive ) );
},
autoRender:function(ctxt, directive){
return jQuery( $p( this ).autoRender( ctxt, this._pure_d || directive ) );
}
});
return function(n, sel){
return jQuery(n).find(sel);
};
},
mootools:function(){
Element.implement({
compile:function(directive, ctxt){
return $p(this).compile(directive, ctxt);
},
render:function(ctxt, directive){
return $p([this]).render(ctxt, directive);
},
autoRender:function(ctxt, directive){
return $p([this]).autoRender(ctxt, directive);
}
});
return function(n, sel){
return $(n).getElements(sel);
};
},
prototype:function(){
Element.addMethods({
compile:function(element, directive, ctxt){
return $p([element]).compile(directive, ctxt);
},
render:function(element, ctxt, directive){
return $p([element]).render(ctxt, directive);
},
autoRender:function(element, ctxt, directive){
return $p([element]).autoRender(ctxt, directive);
}
});
return function(n, sel){
n = n === document ? n.body : n;
return typeof n === 'string' ? $$(n) : $(n).select(sel);
};
},
sizzle:function(){
return function(n, sel){
return Sizzle(sel, n);
};
},
sly:function(){
return function(n, sel){
return Sly(sel, n);
};
},
yui:function(){ //Thanks to https://github.com/soljin
if(typeof document.querySelector === 'undefined'){
YUI().use("node",function(Y){
$p.plugins.find = function(n, sel){
return Y.NodeList.getDOMNodes(Y.one(n).all(sel));
};
});
}
YUI.add("pure-yui",function(Y){
Y.Node.prototype.directives = function(directive){
this._pure_d = directive; return this;
};
Y.Node.prototype.compile = function(directive, ctxt){
return $p([this._node]).compile(this._pure_d || directive, ctxt);
};
Y.Node.prototype.render = function(ctxt, directive){
return Y.one($p([this._node]).render(ctxt, this._pure_d || directive));
};
Y.Node.prototype.autoRender = function(ctxt, directive){
return Y.one($p([this._node]).autoRender(ctxt, this._pure_d || directive));
};
},"0.1",{requires:["node"]});
return true;
}
};
// get lib specifics if available
(function(){
var libSel,
libkey =
(typeof dojo !== 'undefined' && 'dojo') ||
(typeof DOMAssistant !== 'undefined' && 'domassistant') ||
(typeof Ext !== 'undefined' && 'ext') ||
(typeof jQuery !== 'undefined' && 'jquery') ||
(typeof MooTools !== 'undefined' && 'mootools') ||
(typeof Prototype !== 'undefined' && 'prototype') ||
(typeof Sizzle !== 'undefined' && 'sizzle') ||
(typeof Sly !== 'undefined' && 'sly') ||
(typeof YUI !== 'undefined' && 'yui');
//add library methods
if(libkey){
libSel = $p.libs[libkey]();
}
//if no native selector available
if( typeof document.querySelector === 'undefined' ){
//take it from the JS lib
if( typeof libSel === 'function' ){
$p.plugins.find = libSel;
//if nothing throw an error
}else if( !libSel ){
throw('you need a JS library with a CSS selector engine');
}
}
//for node.js
if(typeof exports !== 'undefined'){
exports.$p = $p;
}
}());
</script>
<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>
<ul class='list'>
<li class='item'></li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json2/20130526/json2.min.js"></script>
<!-- http://akdubya.github.com/dustjs/dist/dust-full-0.3.0.min.js -->
<script>
//
// Dust - Asynchronous Templating v0.3.0
// http://akdubya.github.com/dustjs
//
// Copyright (c) 2010, Aleksander Williams
// Released under the MIT License.
//
var dust={};
(function(o){function z(e,k,l){this.stack=e;this.global=k;this.blocks=l}function H(e,k,l,x){this.tail=k;this.isObject=!o.isArray(e)&&e&&typeof e==="object";this.head=e;this.index=l;this.of=x}function p(e){this.head=new B(this);this.callback=e;this.out=""}function J(){this.head=new B(this)}function B(e,k,l){this.root=e;this.next=k;this.data="";this.flushable=false;this.taps=l}function r(e,k){this.head=e;this.tail=k}o.cache={};o.register=function(e,k){if(e)o.cache[e]=k};o.render=function(e,k,l){l=(new p(l)).head;
o.load(e,l,z.wrap(k)).end()};o.stream=function(e,k){var l=new J;o.nextTick(function(){o.load(e,l.head,z.wrap(k)).end()});return l};o.renderSource=function(e,k,l){return o.compileFn(e)(k,l)};o.compileFn=function(e,k){var l=o.loadSource(o.compile(e,k));return function(x,C){var E=C?new p(C):new J;o.nextTick(function(){l(E.head,z.wrap(x)).end()});return E}};o.load=function(e,k,l){var x=o.cache[e];if(x)return x(k,l);else{if(o.onLoad)return k.map(function(C){o.onLoad(e,function(E,M){if(E)return C.setError(E);
o.cache[e]||o.loadSource(o.compile(M,e));o.cache[e](C,l).end()})});return k.setError(Error("Template Not Found: "+e))}};o.loadSource=function(e){return eval(e)};o.isArray=Array.isArray?Array.isArray:function(e){return Object.prototype.toString.call(e)=="[object Array]"};o.nextTick=function(e){setTimeout(e,0)};o.isEmpty=function(e){if(o.isArray(e)&&!e.length)return true;if(e===0)return false;return!e};o.filter=function(e,k,l){if(l)for(var x=0,C=l.length;x<C;x++){var E=l[x];if(E==="s")k=null;else e=
o.filters[E](e)}if(k)e=o.filters[k](e);return e};o.filters={h:function(e){return o.escapeHtml(e)},j:function(e){return o.escapeJs(e)},u:encodeURI,uc:encodeURIComponent};o.makeBase=function(e){return new z(new H,e)};z.wrap=function(e){if(e instanceof z)return e;return new z(new H(e))};z.prototype.get=function(e){for(var k=this.stack,l;k;){if(k.isObject){l=k.head[e];if(l!==undefined)return l}k=k.tail}return this.global?this.global[e]:undefined};z.prototype.getPath=function(e,k){var l=this.stack,x=k.length;
if(e&&x===0)return l.head;if(l.isObject){l=l.head;for(var C=0;l&&C<x;){l=l[k[C]];C++}return l}};z.prototype.push=function(e,k,l){return new z(new H(e,this.stack,k,l),this.global,this.blocks)};z.prototype.rebase=function(e){return new z(new H(e),this.global,this.blocks)};z.prototype.current=function(){return this.stack.head};z.prototype.getBlock=function(e){var k=this.blocks;if(k)for(var l=k.length,x;l--;)if(x=k[l][e])return x};z.prototype.shiftBlocks=function(e){var k=this.blocks;if(e){newBlocks=
k?k.concat([e]):[e];return new z(this.stack,this.global,newBlocks)}return this};p.prototype.flush=function(){for(var e=this.head;e;){if(e.flushable)this.out+=e.data;else{if(e.error){this.callback(e.error);this.flush=function(){}}return}this.head=e=e.next}this.callback(null,this.out)};J.prototype.flush=function(){for(var e=this.head;e;){if(e.flushable)this.emit("data",e.data);else{if(e.error){this.emit("error",e.error);this.flush=function(){}}return}this.head=e=e.next}this.emit("end")};J.prototype.emit=
function(e,k){var l=this.events;l&&l[e]&&l[e](k)};J.prototype.on=function(e,k){if(!this.events)this.events={};this.events[e]=k;return this};B.prototype.write=function(e){var k=this.taps;if(k)e=k.go(e);this.data+=e;return this};B.prototype.end=function(e){e&&this.write(e);this.flushable=true;this.root.flush();return this};B.prototype.map=function(e){var k=new B(this.root,this.next,this.taps),l=new B(this.root,k,this.taps);this.next=l;this.flushable=true;e(l);return k};B.prototype.tap=function(e){var k=
this.taps;this.taps=k?k.push(e):new r(e);return this};B.prototype.untap=function(){this.taps=this.taps.tail;return this};B.prototype.render=function(e,k){return e(this,k)};B.prototype.reference=function(e,k,l,x){if(typeof e==="function"){e=e(this,k,null,{auto:l,filters:x});if(e instanceof B)return e}return o.isEmpty(e)?this:this.write(o.filter(e,l,x))};B.prototype.section=function(e,k,l,x){if(typeof e==="function"){e=e(this,k,l,x);if(e instanceof B)return e}var C=l.block;l=l["else"];if(x)k=k.push(x);
if(o.isArray(e)){if(C){x=e.length;l=this;for(var E=0;E<x;E++)l=C(l,k.push(e[E],E,x));return l}}else if(e===true){if(C)return C(this,k)}else if(e||e===0){if(C)return C(this,k.push(e))}else if(l)return l(this,k);return this};B.prototype.exists=function(e,k,l){var x=l.block;l=l["else"];if(o.isEmpty(e)){if(l)return l(this,k)}else if(x)return x(this,k);return this};B.prototype.notexists=function(e,k,l){var x=l.block;l=l["else"];if(o.isEmpty(e)){if(x)return x(this,k)}else if(l)return l(this,k);return this};
B.prototype.block=function(e,k,l){l=l.block;if(e)l=e;if(l)return l(this,k);return this};B.prototype.partial=function(e,k){if(typeof e==="function")return this.capture(e,k,function(l,x){o.load(l,x,k).end()});return o.load(e,this,k)};B.prototype.helper=function(e,k,l,x){return o.helpers[e](this,k,l,x)};B.prototype.capture=function(e,k,l){return this.map(function(x){var C=new p(function(E,M){E?x.setError(E):l(M,x)});e(C.head,k).end()})};B.prototype.setError=function(e){this.error=e;this.root.flush();
return this};o.helpers={sep:function(e,k,l){if(k.stack.index===k.stack.of-1)return e;return l.block(e,k)},idx:function(e,k,l){return l.block(e,k.push(k.stack.index))}};r.prototype.push=function(e){return new r(e,this)};r.prototype.go=function(e){for(var k=this;k;){e=k.head(e);k=k.tail}return e};var K=RegExp(/[&<>\"]/),q=/&/g,j=/</g,w=/>/g,t=/\"/g;o.escapeHtml=function(e){if(typeof e==="string"){if(!K.test(e))return e;return e.replace(q,"&").replace(j,"<").replace(w,">").replace(t,""")}return e};
var y=/\\/g,A=/\r/g,F=/\u2028/g,L=/\u2029/g,N=/\n/g,V=/\f/g,I=/'/g,Q=/"/g,T=/\t/g;o.escapeJs=function(e){if(typeof e==="string")return e.replace(y,"\\\\").replace(Q,'\\"').replace(I,"\\'").replace(A,"\\r").replace(F,"\\u2028").replace(L,"\\u2029").replace(N,"\\n").replace(V,"\\f").replace(T,"\\t");return e}})(dust);if(typeof exports!=="undefined"){typeof process!=="undefined"&&require("./server")(dust);module.exports=dust}
(function(o){function z(q,j){for(var w=[j[0]],t=1,y=j.length;t<y;t++){var A=o.filterNode(q,j[t]);A&&w.push(A)}return w}function H(q,j){return j}function p(){}function J(q,j){for(var w="",t=1,y=j.length;t<y;t++)w+=o.compileNode(q,j[t]);return w}function B(q,j,w){return"."+w+"("+o.compileNode(q,j[1])+","+o.compileNode(q,j[2])+","+o.compileNode(q,j[4])+","+o.compileNode(q,j[3])+")"}o.compile=function(q,j){var w,t=o.parse(q);w=o.filterNode({},t);t={name:j,bodies:[],blocks:{},index:0,auto:"h"};w="(function(){dust.register("+
(j?'"'+j+'"':"null")+","+o.compileNode(t,w)+");";var y;var A=[],F=t.blocks;for(y in F)A.push(y+":"+F[y]);if(A.length){t.blocks="ctx=ctx.shiftBlocks(blocks);";y="var blocks={"+A.join(",")+"};"}else y=t.blocks="";y=w+y;w=[];A=t.bodies;t=t.blocks;F=0;for(var L=A.length;F<L;F++)w[F]="function body_"+F+"(chk,ctx){"+t+"return chk"+A[F]+";}";t=w.join("");return y+t+"return body_0;})();"};o.filterNode=function(q,j){return o.optimizers[j[0]](q,j)};o.optimizers={body:function(q,j){for(var w=[j[0]],t,y=1,A=
j.length;y<A;y++){var F=o.filterNode(q,j[y]);if(F)if(F[0]==="buffer")if(t)t[1]+=F[1];else{t=F;w.push(F)}else{t=null;w.push(F)}}return w},buffer:H,special:function(q,j){return["buffer",r[j[1]]]},format:p,reference:z,"#":z,"?":z,"^":z,"<":z,"+":z,"@":z,"%":z,partial:z,context:z,params:z,bodies:z,param:z,filters:H,key:H,path:H,literal:H,comment:p};o.pragmas={esc:function(q,j,w){var t=q.auto;j||(j="h");q.auto=j==="s"?"":j;j=J(q,w.block);q.auto=t;return j}};var r={s:" ",n:"\n",r:"\r",lb:"{",rb:"}"};o.compileNode=
function(q,j){return o.nodes[j[0]](q,j)};o.nodes={body:function(q,j){var w=q.index++,t="body_"+w;q.bodies[w]=J(q,j);return t},buffer:function(q,j){return".write("+K(j[1])+")"},format:function(q,j){return".write("+K(j[1]+j[2])+")"},reference:function(q,j){return".reference("+o.compileNode(q,j[1])+",ctx,"+o.compileNode(q,j[2])+")"},"#":function(q,j){return B(q,j,"section")},"?":function(q,j){return B(q,j,"exists")},"^":function(q,j){return B(q,j,"notexists")},"<":function(q,j){for(var w=j[4],t=1,y=
w.length;t<y;t++){var A=w[t];if(A[1][1]==="block"){q.blocks[j[1].text]=o.compileNode(q,A[2]);break}}return""},"+":function(q,j){return".block(ctx.getBlock("+K(j[1].text)+"),"+o.compileNode(q,j[2])+","+o.compileNode(q,j[4])+","+o.compileNode(q,j[3])+")"},"@":function(q,j){return".helper("+K(j[1].text)+","+o.compileNode(q,j[2])+","+o.compileNode(q,j[4])+","+o.compileNode(q,j[3])+")"},"%":function(q,j){var w=j[1][1];if(!o.pragmas[w])return"";for(var t=j[4],y={},A=1,F=t.length;A<F;A++){var L=t[A];y[L[1][1]]=
L[2]}t=j[3];L={};A=1;for(F=t.length;A<F;A++){var N=t[A];L[N[1][1]]=N[2][1]}return o.pragmas[w](q,j[2][1]?j[2][1].text:null,y,L)},partial:function(q,j){return".partial("+o.compileNode(q,j[1])+","+o.compileNode(q,j[2])+")"},context:function(q,j){if(j[1])return"ctx.rebase("+o.compileNode(q,j[1])+")";return"ctx"},params:function(q,j){for(var w=[],t=1,y=j.length;t<y;t++)w.push(o.compileNode(q,j[t]));if(w.length)return"{"+w.join(",")+"}";return"null"},bodies:function(q,j){for(var w=[],t=1,y=j.length;t<
y;t++)w.push(o.compileNode(q,j[t]));return"{"+w.join(",")+"}"},param:function(q,j){return o.compileNode(q,j[1])+":"+o.compileNode(q,j[2])},filters:function(q,j){for(var w=[],t=1,y=j.length;t<y;t++)w.push('"'+j[t]+'"');return'"'+q.auto+'"'+(w.length?",["+w.join(",")+"]":"")},key:function(q,j){return'ctx.get("'+j[1]+'")'},path:function(q,j){for(var w=j[1],t=j[2],y=[],A=0,F=t.length;A<F;A++)y.push('"'+t[A]+'"');return"ctx.getPath("+w+",["+y.join(",")+"])"},literal:function(q,j){return K(j[1])}};var K=
typeof JSON==="undefined"?function(q){return'"'+o.escapeJs(q)+'"'}:JSON.stringify})(typeof exports!=="undefined"?exports:window.dust);
(function(o){var z=function(){var H={parse:function(p){function J(n){var b=n.charCodeAt(0);if(b<255){n="x";var c=2}else{n="u";c=4}n="\\"+n;var d=b.toString(16).toUpperCase();b=d;c=c-d.length;for(d=0;d<c;d++)b="0"+b;return n+b}function B(n){return'"'+n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/[\x80-\uFFFF]/g,J)+'"'}function r(n){if(!(a<R)){if(a>R){R=a;W=[]}W.push(n)}}function K(){var n="body@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=[];for(var c=
q();c!==null;){b.push(c);c=q()}b=b!==null?["body"].concat(b):null;v[n]={nextPos:a,result:b};return b}function q(){var n="part@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=l();if(b!==null)b=b;else{b=j();if(b!==null)b=b;else{b="partial@"+a;var c=v[b];if(c){a=c.nextPos;b=c.result}else{c=h;h=false;var d=a,g=C();if(g!==null){if(p.substr(a,1)===">"){var f=">";a+=1}else{f=null;h&&r('">"')}if(f!==null){var i=I();i=i!==null?["literal",i]:null;if(i!==null)i=i;else{i=Q();i=i!==null?i:null}if(i!==null){var m=
y();if(m!==null){if(p.substr(a,1)==="/"){var s="/";a+=1}else{s=null;h&&r('"/"')}if(s!==null){var u=E();if(u!==null)g=[g,f,i,m,s,u];else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}d=g!==null?["partial",g[2],g[3]]:null;(h=c)&&d===null&&r("partial");v[b]={nextPos:a,result:d};b=d}if(b!==null)b=b;else{b=L();if(b!==null)b=b;else{b=F();if(b!==null)b=b;else{b="buffer@"+a;if(c=v[b]){a=c.nextPos;b=c.result}else{c=h;h=false;d=a;g=M();if(g!==null){f=[];for(i=
U();i!==null;){f.push(i);i=U()}if(f!==null)g=[g,f];else{g=null;a=d}}else{g=null;a=d}d=g!==null?["format",g[0],g[1].join("")]:null;if(d!==null)d=d;else{i=g=a;f=h;h=false;m=x();h=f;if(m===null)f="";else{f=null;a=i}if(f!==null){m=a;i=h;h=false;s=M();h=i;if(s===null)i="";else{i=null;a=m}if(i!==null){m=a;s=h;h=false;u=l();h=s;if(u===null)s="";else{s=null;a=m}if(s!==null){if(p.length>a){m=p.charAt(a);a++}else{m=null;h&&r("any character")}if(m!==null)f=[f,i,s,m];else{f=null;a=g}}else{f=null;a=g}}else{f=
null;a=g}}else{f=null;a=g}g=f!==null?f[3]:null;if(g!==null)for(d=[];g!==null;){d.push(g);i=g=a;f=h;h=false;m=x();h=f;if(m===null)f="";else{f=null;a=i}if(f!==null){m=a;i=h;h=false;s=M();h=i;if(s===null)i="";else{i=null;a=m}if(i!==null){m=a;s=h;h=false;u=l();h=s;if(u===null)s="";else{s=null;a=m}if(s!==null){if(p.length>a){m=p.charAt(a);a++}else{m=null;h&&r("any character")}if(m!==null)f=[f,i,s,m];else{f=null;a=g}}else{f=null;a=g}}else{f=null;a=g}}else{f=null;a=g}g=f!==null?f[3]:null}else d=null;d=d!==
null?["buffer",d.join("")]:null;d=d!==null?d:null}(h=c)&&d===null&&r("buffer");v[b]={nextPos:a,result:d};b=d}b=b!==null?b:null}}}}}v[n]={nextPos:a,result:b};return b}function j(){var n="section@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a,d=w();if(d!==null){var g=E();if(g!==null){var f=K();if(f!==null){var i=A();if(i!==null){var m=t();if(m!==null){var s=d[1].text===m.text?"":null;if(s!==null)d=[d,g,f,i,m,s];else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}}else{d=
null;a=c}}else{d=null;a=c}c=d!==null?function(u,D,O){O.push(["param",["literal","block"],D]);u.push(O);return u}(d[0],d[2],d[3],d[4]):null;if(c!==null)c=c;else{c=a;d=w();if(d!==null){if(p.substr(a,1)==="/"){g="/";a+=1}else{g=null;h&&r('"/"')}if(g!==null){f=E();if(f!==null)d=[d,g,f];else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}c=d!==null?function(u){u.push(["bodies"]);return u}(d[0]):null;c=c!==null?c:null}(h=b)&&c===null&&r("section");v[n]={nextPos:a,result:c};return c}function w(){var n="sec_tag_start@"+
a,b=v[n];if(b){a=b.nextPos;return b.result}b=a;var c=C();if(c!==null){if(p.substr(a).match(/^[#?^<+@%]/)!==null){var d=p.charAt(a);a++}else{d=null;h&&r("[#?^<+@%]")}if(d!==null){var g=N();if(g!==null){var f=y();if(f!==null){var i;i="params@"+a;var m=v[i];if(m){a=m.nextPos;i=m.result}else{m=h;h=false;var s=[],u=a,D=U();if(D!==null){var O=I();if(O!==null){if(p.substr(a,1)==="="){var P="=";a+=1}else{P=null;h&&r('"="')}if(P!==null){var G=N();if(G!==null)G=G;else{G=Q();G=G!==null?G:null}if(G!==null)D=
[D,O,P,G];else{D=null;a=u}}else{D=null;a=u}}else{D=null;a=u}}else{D=null;a=u}for(u=D!==null?["param",["literal",D[1]],D[3]]:null;u!==null;){s.push(u);u=a;D=U();if(D!==null){O=I();if(O!==null){if(p.substr(a,1)==="="){P="=";a+=1}else{P=null;h&&r('"="')}if(P!==null){G=N();if(G!==null)G=G;else{G=Q();G=G!==null?G:null}if(G!==null)D=[D,O,P,G];else{D=null;a=u}}else{D=null;a=u}}else{D=null;a=u}}else{D=null;a=u}u=D!==null?["param",["literal",D[1]],D[3]]:null}s=s!==null?["params"].concat(s):null;(h=m)&&s===
null&&r("params");v[i]={nextPos:a,result:s};i=s}if(i!==null)c=[c,d,g,f,i];else{c=null;a=b}}else{c=null;a=b}}else{c=null;a=b}}else{c=null;a=b}}else{c=null;a=b}b=c!==null?[c[1],c[2],c[3],c[4]]:null;v[n]={nextPos:a,result:b};return b}function t(){var n="end_tag@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a,d=C();if(d!==null){if(p.substr(a,1)==="/"){var g="/";a+=1}else{g=null;h&&r('"/"')}if(g!==null){var f=N();if(f!==null){var i=E();if(i!==null)d=[d,g,f,i];else{d=null;a=c}}else{d=null;
a=c}}else{d=null;a=c}}else{d=null;a=c}c=d!==null?d[2]:null;(h=b)&&c===null&&r("end tag");v[n]={nextPos:a,result:c};return c}function y(){var n="context@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=a;if(p.substr(a,1)===":"){var c=":";a+=1}else{c=null;h&&r('":"')}if(c!==null){var d=N();if(d!==null)c=[c,d];else{c=null;a=b}}else{c=null;a=b}b=c!==null?c[1]:null;b=b!==null?b:"";b=b!==null?b?["context",b]:["context"]:null;v[n]={nextPos:a,result:b};return b}function A(){var n="bodies@"+a,b=v[n];if(b){a=
b.nextPos;return b.result}b=h;h=false;var c=[],d=a,g=C();if(g!==null){if(p.substr(a,1)===":"){var f=":";a+=1}else{f=null;h&&r('":"')}if(f!==null){var i=I();if(i!==null){var m=E();if(m!==null){var s=K();if(s!==null)g=[g,f,i,m,s];else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}for(d=g!==null?["param",["literal",g[2]],g[4]]:null;d!==null;){c.push(d);d=a;g=C();if(g!==null){if(p.substr(a,1)===":"){f=":";a+=1}else{f=null;h&&r('":"')}if(f!==null){i=I();if(i!==null){m=
E();if(m!==null){s=K();if(s!==null)g=[g,f,i,m,s];else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}}else{g=null;a=d}d=g!==null?["param",["literal",g[2]],g[4]]:null}c=c!==null?["bodies"].concat(c):null;(h=b)&&c===null&&r("bodies");v[n]={nextPos:a,result:c};return c}function F(){var n="reference@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a,d=C();if(d!==null){var g=N();if(g!==null){var f;f="filters@"+a;var i=v[f];if(i){a=i.nextPos;f=i.result}else{i=h;h=false;var m=
[],s=a;if(p.substr(a,1)==="|"){var u="|";a+=1}else{u=null;h&&r('"|"')}if(u!==null){var D=I();if(D!==null)u=[u,D];else{u=null;a=s}}else{u=null;a=s}for(s=u!==null?u[1]:null;s!==null;){m.push(s);s=a;if(p.substr(a,1)==="|"){u="|";a+=1}else{u=null;h&&r('"|"')}if(u!==null){D=I();if(D!==null)u=[u,D];else{u=null;a=s}}else{u=null;a=s}s=u!==null?u[1]:null}m=m!==null?["filters"].concat(m):null;(h=i)&&m===null&&r("filters");v[f]={nextPos:a,result:m};f=m}if(f!==null){i=E();if(i!==null)d=[d,g,f,i];else{d=null;
a=c}}else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}c=d!==null?["reference",d[1],d[2]]:null;(h=b)&&c===null&&r("reference");v[n]={nextPos:a,result:c};return c}function L(){var n="special@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a,d=C();if(d!==null){if(p.substr(a,1)==="~"){var g="~";a+=1}else{g=null;h&&r('"~"')}if(g!==null){var f=I();if(f!==null){var i=E();if(i!==null)d=[d,g,f,i];else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}c=d!==null?["special",d[2]]:
null;(h=b)&&c===null&&r("special");v[n]={nextPos:a,result:c};return c}function N(){var n="identifier@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=V();c=c!==null?X(["path"].concat(c),n):null;if(c!==null)c=c;else{c=I();c=c!==null?X(["key",c],n):null;c=c!==null?c:null}(h=b)&&c===null&&r("identifier");v[n]={nextPos:a,result:c};return c}function V(){var n="path@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a,d=I();d=d!==null?d:"";if(d!==null){var g=a;if(p.substr(a,1)===
"."){var f=".";a+=1}else{f=null;h&&r('"."')}if(f!==null){var i=I();if(i!==null)f=[f,i];else{f=null;a=g}}else{f=null;a=g}g=f!==null?f[1]:null;if(g!==null)for(var m=[];g!==null;){m.push(g);g=a;if(p.substr(a,1)==="."){f=".";a+=1}else{f=null;h&&r('"."')}if(f!==null){i=I();if(i!==null)f=[f,i];else{f=null;a=g}}else{f=null;a=g}g=f!==null?f[1]:null}else m=null;if(m!==null)d=[d,m];else{d=null;a=c}}else{d=null;a=c}c=d!==null?function(s,u){if(s){u.unshift(s);return[false,u]}return[true,u]}(d[0],d[1]):null;if(c!==
null)c=c;else{if(p.substr(a,1)==="."){c=".";a+=1}else{c=null;h&&r('"."')}c=c!==null?[true,[]]:null;c=c!==null?c:null}(h=b)&&c===null&&r("path");v[n]={nextPos:a,result:c};return c}function I(){var n="key@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a;if(p.substr(a).match(/^[a-zA-Z_$]/)!==null){var d=p.charAt(a);a++}else{d=null;h&&r("[a-zA-Z_$]")}if(d!==null){var g=[];if(p.substr(a).match(/^[0-9a-zA-Z_$]/)!==null){var f=p.charAt(a);a++}else{f=null;h&&r("[0-9a-zA-Z_$]")}for(;f!==null;){g.push(f);
if(p.substr(a).match(/^[0-9a-zA-Z_$]/)!==null){f=p.charAt(a);a++}else{f=null;h&&r("[0-9a-zA-Z_$]")}}if(g!==null)d=[d,g];else{d=null;a=c}}else{d=null;a=c}c=d!==null?d[0]+d[1].join(""):null;(h=b)&&c===null&&r("key");v[n]={nextPos:a,result:c};return c}function Q(){var n="inline@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a;if(p.substr(a,1)==='"'){var d='"';a+=1}else{d=null;h&&r('"\\""')}if(d!==null){if(p.substr(a,1)==='"'){var g='"';a+=1}else{g=null;h&&r('"\\""')}if(g!==null)d=[d,
g];else{d=null;a=c}}else{d=null;a=c}c=d!==null?["literal",""]:null;if(c!==null)c=c;else{c=a;if(p.substr(a,1)==='"'){d='"';a+=1}else{d=null;h&&r('"\\""')}if(d!==null){g=e();if(g!==null){if(p.substr(a,1)==='"'){var f='"';a+=1}else{f=null;h&&r('"\\""')}if(f!==null)d=[d,g,f];else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}c=d!==null?["literal",d[1]]:null;if(c!==null)c=c;else{c=a;if(p.substr(a,1)==='"'){d='"';a+=1}else{d=null;h&&r('"\\""')}if(d!==null){f=T();if(f!==null)for(g=[];f!==null;){g.push(f);
f=T()}else g=null;if(g!==null){if(p.substr(a,1)==='"'){f='"';a+=1}else{f=null;h&&r('"\\""')}if(f!==null)d=[d,g,f];else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}c=d!==null?["body"].concat(d[1]):null;c=c!==null?c:null}}(h=b)&&c===null&&r("inline");v[n]={nextPos:a,result:c};return c}function T(){var n="inline_part@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=L();if(b!==null)b=b;else{b=F();if(b!==null)b=b;else{b=e();b=b!==null?["buffer",b]:null;b=b!==null?b:null}}v[n]={nextPos:a,result:b};return b}
function e(){var n="literal@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a,d=a,g=h;h=false;var f=x();h=g;if(f===null)g="";else{g=null;a=d}if(g!==null){f=a;d=h;h=false;var i=M();h=d;if(i===null)d="";else{d=null;a=f}if(d!==null){f=k();if(f!==null)f=f;else{if(p.substr(a).match(/^[^"]/)!==null){f=p.charAt(a);a++}else{f=null;h&&r('[^"]')}f=f!==null?f:null}if(f!==null)g=[g,d,f];else{g=null;a=c}}else{g=null;a=c}}else{g=null;a=c}c=g!==null?g[2]:null;if(c!==null)for(var m=[];c!==null;){m.push(c);
d=c=a;g=h;h=false;f=x();h=g;if(f===null)g="";else{g=null;a=d}if(g!==null){f=a;d=h;h=false;i=M();h=d;if(i===null)d="";else{d=null;a=f}if(d!==null){f=k();if(f!==null)f=f;else{if(p.substr(a).match(/^[^"]/)!==null){f=p.charAt(a);a++}else{f=null;h&&r('[^"]')}f=f!==null?f:null}if(f!==null)g=[g,d,f];else{g=null;a=c}}else{g=null;a=c}}else{g=null;a=c}c=g!==null?g[2]:null}else m=null;m=m!==null?m.join(""):null;(h=b)&&m===null&&r("literal");v[n]={nextPos:a,result:m};return m}function k(){var n="esc@"+a,b=v[n];
if(b){a=b.nextPos;return b.result}if(p.substr(a,2)==='\\"'){b='\\"';a+=2}else{b=null;h&&r('"\\\\\\""')}b=b!==null?'"':null;v[n]={nextPos:a,result:b};return b}function l(){var n="comment@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=h;h=false;var c=a;if(p.substr(a,2)==="{!"){var d="{!";a+=2}else{d=null;h&&r('"{!"')}if(d!==null){var g=[],f=a,i=a,m=h;h=false;if(p.substr(a,2)==="!}"){var s="!}";a+=2}else{s=null;h&&r('"!}"')}h=m;if(s===null)m="";else{m=null;a=i}if(m!==null){if(p.length>a){i=p.charAt(a);
a++}else{i=null;h&&r("any character")}if(i!==null)i=[m,i];else{i=null;a=f}}else{i=null;a=f}for(f=i!==null?i[1]:null;f!==null;){g.push(f);i=f=a;m=h;h=false;if(p.substr(a,2)==="!}"){s="!}";a+=2}else{s=null;h&&r('"!}"')}h=m;if(s===null)m="";else{m=null;a=i}if(m!==null){if(p.length>a){i=p.charAt(a);a++}else{i=null;h&&r("any character")}if(i!==null)i=[m,i];else{i=null;a=f}}else{i=null;a=f}f=i!==null?i[1]:null}if(g!==null){if(p.substr(a,2)==="!}"){f="!}";a+=2}else{f=null;h&&r('"!}"')}if(f!==null)d=[d,g,
f];else{d=null;a=c}}else{d=null;a=c}}else{d=null;a=c}c=d!==null?["comment",d[1].join("")]:null;(h=b)&&c===null&&r("comment");v[n]={nextPos:a,result:c};return c}function x(){var n="tag@"+a,b=v[n];if(b){a=b.nextPos;return b.result}b=a;var c=C();if(c!==null){if(p.substr(a).match(/^[#?^><+%:@\/~%]/)!==null){var d=p.charAt(a);a++}else{d=null;h&&r("[#?^><+%:@\\/~%]")}if(d!==null){var g=a,f=a,i=h;h=false;var m=E();h=i;if(m===null)i="";else{i=null;a=f}if(i!==null){f=a;m=h;h=false;var s=M();h=m;if(s===null)m=
"";else{m=null;a=f}if(m!==null){if(p.length>a){f=p.charAt(a);a++}else{f=null;h&&r("any character")}if(f!==null)i=[i,m,f];else{i=null;a=g}}else{i=null;a=g}}else{i=null;a=g}if(i!==null)for(var u=[];i!==null;){u.push(i);f=g=a;i=h;h=false;m=E();h=i;if(m===null)i="";else{i=null;a=f}if(i!==null){f=a;m=h;h=false;s=M();h=m;if(s===null)m="";else{m=null;a=f}if(m!==null){if(p.length>a){f=p.charAt(a);a++}else{f=null;h&&r("any character")}if(f!==null)i=[i,m,f];else{i=null;a=g}}else{i=null;a=g}}else{i=null;a=g}}else u=
null;if(u!==null){g=E();if(g!==null)c=[c,d,u,g];else{c=null;a=b}}else{c=null;a=b}}else{c=null;a=b}}else{c=null;a=b}if(c!==null)b=c;else{b=F();b=b!==null?b:null}v[n]={nextPos:a,result:b};return b}function C(){var n="ld@"+a,b=v[n];if(b){a=b.nextPos;return b.result}if(p.substr(a,1)==="{"){b="{";a+=1}else{b=null;h&&r('"{"')}v[n]={nextPos:a,result:b};return b}function E(){var n="rd@"+a,b=v[n];if(b){a=b.nextPos;return b.result}if(p.substr(a,1)==="}"){b="}";a+=1}else{b=null;h&&r('"}"')}v[n]={nextPos:a,result:b};
return b}function M(){var n="eol@"+a,b=v[n];if(b){a=b.nextPos;return b.result}if(p.substr(a,1)==="\n"){b="\n";a+=1}else{b=null;h&&r('"\\n"')}if(b!==null)b=b;else{if(p.substr(a,2)==="\r\n"){b="\r\n";a+=2}else{b=null;h&&r('"\\r\\n"')}if(b!==null)b=b;else{if(p.substr(a,1)==="\r"){b="\r";a+=1}else{b=null;h&&r('"\\r"')}if(b!==null)b=b;else{if(p.substr(a,1)==="\u2028"){b="\u2028";a+=1}else{b=null;h&&r('"\\u2028"')}if(b!==null)b=b;else{if(p.substr(a,1)==="\u2029"){b="\u2029";a+=1}else{b=null;h&&r('"\\u2029"')}b=
b!==null?b:null}}}}v[n]={nextPos:a,result:b};return b}function U(){var n="ws@"+a,b=v[n];if(b){a=b.nextPos;return b.result}if(p.substr(a).match(/^[\t\u000b\u000c \xA0\uFEFF]/)!==null){b=p.charAt(a);a++}else{b=null;h&&r("[\t\u000b\u000c \\xA0\\uFEFF]")}v[n]={nextPos:a,result:b};return b}function Y(){var n=function(c){c.sort();for(var d=null,g=[],f=0;f<c.length;f++)if(c[f]!==d){g.push(c[f]);d=c[f]}switch(g.length){case 0:return"end of input";case 1:return g[0];default:return g.slice(0,g.length-1).join(", ")+
" or "+g[g.length-1]}}(W),b=Math.max(a,R);b=b<p.length?B(p.charAt(b)):"end of input";return"Expected "+n+" but "+b+" found."}function Z(){for(var n=1,b=1,c=false,d=0;d<R;d++){var g=p.charAt(d);if(g==="\n"){c||n++;b=1;c=false}else if(g==="\r"|g==="\u2028"||g==="\u2029"){n++;b=1;c=true}else{b++;c=false}}return{line:n,column:b}}function X(n,b){n.text=p.substring(b.split("@")[1],a);return n}var a=0,h=true,R=0,W=[],v={},S=K();if(S===null||a!==p.length){S=Z();throw new SyntaxError(Y(),S.line,S.column);
}return S},toSource:function(){return this._source}};H.SyntaxError=function(p,J,B){this.name="SyntaxError";this.message=p;this.line=J;this.column=B};H.SyntaxError.prototype=Error.prototype;return H}();o.parse=z.parse})(typeof exports!=="undefined"?exports:window.dust);
</script>
<!-- https://github.com/premasagar/tim/raw/master/tim.js -->
<script>
/*!
* Tim
* github.com/premasagar/tim
*
*//*
A tiny, secure JavaScript micro-templating script.
*//*
by Premasagar Rose
dharmafly.com
license
opensource.org/licenses/mit-license.php
**
creates global object
tim
**
v0.3.0
*//*global window */
/*
TODO:
* a way to prevent a delimiter (e.g. ", ") appearing last in a loop template
* Sorted constructor for auto-sorting arrays - used for parsers -> two parsers are added, one for identifying and parsing single-tokens and one for open/close tokens - the parsers then create two new Sorted instance, one for single-token plugins and one for open/close token plugins
*/
(function(name, definition, context) {
if (typeof module != 'undefined' && module.exports) {
module.exports = definition();
} else if (typeof context['define'] == 'function' && context['define']['amd']) {
define(definition);
} else {
context[name] = definition();
}
})('tim', function() {
var tim = (function createTim(initSettings){
"use strict";
var settings = {
start: "{{",
end : "}}",
path : "[a-z0-9_$][\\.a-z0-9_]*" // e.g. config.person.name
},
templates = {},
filters = {},
stopThisFilter, pattern, initialized, undef;
/////
// Update cached regex pattern
function patternCache(){
pattern = new RegExp(settings.start + "\\s*("+ settings.path +")\\s*" + settings.end, "gi");
}
// settingsCache: Get and set settings
/*
Example usage:
settingsCache(); // get settings object
settingsCache({start:"<%", end:"%>", attr:"id"}); // set new settings
*/
function settingsCache(newSettings){
var s;
if (newSettings){
for (s in newSettings){
if (newSettings.hasOwnProperty(s)){
settings[s] = newSettings[s];
}
}
patternCache();
}
return settings;
}
// Apply custom settings
if (initSettings){
settingsCache(initSettings);
}
else {
patternCache();
}
/////
// templatesCache: Get and set the templates cache object
/*
Example usage:
templatesCache("foo"); // get template named "foo"
templatesCache("foo", "bar"); // set template named "foo" to "bar"
templatesCache("foo", false); // delete template named "foo"
templatesCache({foo:"bar", blah:false}); // set multiple templates
templatesCache(false); // delete all templates
*/
function templatesCache(key, value){
var t;
switch (typeof key){
case "string":
if (value === undef){
return templates[key] || "";
}
else if (value === false){
delete templates[key];
}
else {
templates[key] = value;
}
break;
case "object":
for (t in key){
if (key.hasOwnProperty(t)){
templatesCache(t, key[t]);
}
}
break;
case "boolean":
if (!key){
templates = {};
}
break;
}
return templates;
}
function extend(obj1, obj2){
var key;
for (key in obj2){
if (obj2.hasOwnProperty(key)){
obj1[key] = obj2[key];
}
}
return obj1;
}
/////
// FILTERS
function sortByPriority(a, b){
return a[1] - b[1];
}
// Add filter to the stack
function addFilter(filterName, fn, priority){
var fns = filters[filterName];
if (!fns){
fns = filters[filterName] = [];
}
fns.push([fn, priority || 0]);
fns.sort(sortByPriority);
return fn;
}
function applyFilter(filterName, payload){
var fns = filters[filterName],
args, i, len, substituted;
if (fns){
args = [payload];
i = 2;
len = arguments.length;
for (; i < len; i++){
args.push(arguments[i]);
}
i = 0;
len = fns.length;
for (; i < len; i++){
args[0] = payload;
substituted = fns[i][0].apply(null, args);
if (payload !== undef && substituted !== undef){
payload = substituted;
}
if (substituted === null){
payload = '';
}
if (stopThisFilter){
stopThisFilter = false;
break;
}
}
}
return payload;
}
// Router for adding and applying filters, for Tim API
function filter(filterName, payload){
return (typeof payload === "function" ? addFilter : applyFilter)
.apply(null, arguments);
}
filter.stop = function(){
stopThisFilter = true;
};
/////
// Merge data into template
/*
// simpler alternative, without support for iteration:
template = template.replace(pattern, function(tag, token){
return applyFilter("token", token, data, template);
});
*/
// TODO: all an array to be passed to tim(), so that the template is called for each element in it
function substitute(template, data){
var match, tag, token, substituted, startPos, endPos, templateStart, templateEnd, subTemplate, closeToken, closePos, key, loopData, loop;
while((match = pattern.exec(template)) !== null) {
token = match[1];
substituted = applyFilter("token", token, data, template);
startPos = match.index;
endPos = pattern.lastIndex;
templateStart = template.slice(0, startPos);
templateEnd = template.slice(endPos);
// If the final value is a function call it and use the returned
// value in its place.
if (typeof substituted === "function") {
substituted = substituted.call(data);
}
if (typeof substituted !== "boolean" && typeof substituted !== "object"){
template = templateStart + substituted + templateEnd;
} else {
subTemplate = "";
closeToken = settings.start + "/" + token + settings.end;
closePos = templateEnd.indexOf(closeToken);
if (closePos >= 0){
templateEnd = templateEnd.slice(0, closePos);
if (typeof substituted === "boolean") {
subTemplate = substituted ? templateEnd : '';
} else {
for (key in substituted){
if (substituted.hasOwnProperty(key)){
pattern.lastIndex = 0;
// Allow {{_key}} and {{_content}} in templates
loopData = extend({_key:key, _content:substituted[key]}, substituted[key]);
loopData = applyFilter("loopData", loopData, loop, token);
loop = tim(templateEnd, loopData);
subTemplate += applyFilter("loop", loop, token, loopData);
}
}
subTemplate = applyFilter("loopEnd", subTemplate, token, loopData);
}
template = templateStart + subTemplate + template.slice(endPos + templateEnd.length + closeToken.length);
}
else {
throw "tim: '" + token + "' not closed";
}
}
pattern.lastIndex = 0;
}
return template;
}
// TIM - MAIN FUNCTION
function tim(template, data){
var templateLookup;
// On first run, call init plugins
if (!initialized){
initialized = 1;
applyFilter("init");
}
template = applyFilter("templateBefore", template);
// No template tags found in template
if (template.indexOf(settings.start) < 0){
// Is this a key for a cached template?
templateLookup = templatesCache(template);
if (templateLookup){
template = templateLookup;
}
}
template = applyFilter("template", template);
// Substitute tokens in template
if (template && data !== undef){
template = substitute(template, data);
}
template = applyFilter("templateAfter", template);
return template;
}
// Get and set settings, e.g. tim({attr:"id"});
tim.settings = settingsCache;
// Get and set cached templates
tim.templates = templatesCache;
// Create new Tim function, based on supplied settings, if any
tim.parser = createTim;
// Add new filters and trigger existing ones. Use tim.filter.stop() during processing, if required.
tim.filter = filter;
/////
// dotSyntax default plugin: uses dot syntax to parse a data object for substitutions
addFilter("token", function(token, data, tag){
var path = token.split("."),
len = path.length,
dataLookup = data,
i = 0;
for (; i < len; i++){
dataLookup = dataLookup[path[i]];
// Property not found
if (dataLookup === undef){
throw "tim: '" + path[i] + "' not found" + (i ? " in " + tag : "");
}
// Return the required value
if (i === len - 1){
return dataLookup;
}
}
});
/////
// Dom plugin: finds micro-templates in <script>'s in the DOM
// This block of code can be removed if unneeded - e.g. with server-side JS
// Default: <script type="text/tim" class="foo">{{TEMPLATE}}<\/script>
if (window && window.document){
tim.dom = function(domSettings){
domSettings = domSettings || {};
var type = domSettings.type || settings.type || "text/tim",
attr = domSettings.attr || settings.attr || "class",
document = window.document,
hasQuery = !!document.querySelectorAll,
elements = hasQuery ?
document.querySelectorAll(
"script[type='" + type + "']"
) :
document.getElementsByTagName("script"),
i = 0,
len = elements.length,
elem, key,
templatesInDom = {};
for (; i < len; i++){
elem = elements[i];
// Cannot access "class" using el.getAttribute()
key = attr === "class" ? elem.className : elem.getAttribute(attr);
if (key && (hasQuery || elem.type === type)){
templatesInDom[key] = elem.innerHTML;
}
}
templatesCache(templatesInDom);
return templatesInDom;
};
addFilter("init", function(){
tim.dom();
});
}
return tim;
}());
return tim;
}, this);
/*jslint browser: true, onevar: true, undef: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */
</script>
<!-- https://gist.github.com/raw/875670/d52752ead19a4eebc7237602438ae08a2541a5b5/tim-lite-cached-min.js -->
<script>
var timLiteCached=function(){function i(b,e){return b.replace(m,function(g,c){for(var j=c.split("."),k=j.length,h=e,f=0;f<k;f++){h=h[j[f]];if(f===k-1)return h}})}var m=RegExp("{{\\s*([a-z0-9_][\\.a-z0-9_]*)\\s*}}","gi"),d={},l=window.JSON;return l?function(b,e){var g=l.stringify(e),c=d[b]&&d[b][g];if(c)return c;d[b]||(d[b]={});return c=d[b][g]=i(b,e)}:i}();
</script>
<script src="http://www.kuwata-lab.com/tenjin/shotenjin.js"></script>
<!-- https://github.com/QLeelulu/nTenjin/raw/master/nTenjin.js -->
<script>
/*
* $Rev: 39 $
* $Release: 0.0.0 $
* $Copyright$
* License: MIT License
*/
/**
* namespace
*/
var nTenjin = {
version: '0.1.1',
_escape_table: { '&': '&', '<': '<', '>': '>', '"': '"' },
_escape_func: function(m) { return nTenjin._escape_table[m]; },
escapeXml: function(s) {
//if (s == null) return '';
return typeof(s) != 'string' ? s : s.replace(/[&<>"]/g, nTenjin._escape_func); //"
//return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); //"
},
escapeXml2: function(s) {
if (s == null) return '';
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); //"
},
strip: function(s) {
if (! s) return s;
//return s.replace(/^\s+|\s+$/g, '');
return s.replace(/^\s+/, '').replace(/\s+$/, '');
},
_end: undefined // dummy property to escape strict warning (not legal in ECMA-262)
};
delete(nTenjin._end);
// 因为用 new Function 创建的函数,其[[scope]]的作用域链只包含全局对象,所以这里定义为全局变量
_nTenjinEscapeXml = nTenjin.escapeXml;
/**
* Template class
*/
nTenjin.Template = function(properties) {
if (properties) {
var p = properties;
if (p['escaefunc']) this.escapefunc = p['escapefunc'];
}
};
nTenjin.Template.prototype = {
escapefunc: '_nTenjinEscapeXml',
convert: function(input) {
var buf = [];
buf.push("var _buf='';");
this.parseStatements(buf, input);
buf.push("return _buf;");
buf = buf.join('').split("_buf+='';").join('')
.split("var _buf='';_buf+=").join('var _buf=');
try {
return this.render = new Function('it', buf);
//eval('this.render = function(it){' + buf + '};');
//return this.render;
} catch (e) {
if (typeof console !== 'undefined') console.log("Could not create a template function: " + buf);
throw e;
}
},
parseStatements: function(buf, input) {
var regexp = /<\?js(\s(.|\n)*?) ?\?>/mg;
var pos = 0;
var m;
while ((m = regexp.exec(input)) != null) {
var stmt = m[1];
var text = input.substring(pos, m.index);
pos = m.index + m[0].length;
//
if (text) this.parseExpressions(buf, text);
if (stmt) buf.push(stmt);
}
var rest = pos == 0 ? input : input.substring(pos);
this.parseExpressions(buf, rest);
},
parseExpressions: function(buf, input) {
if (! input) return;
//buf.push(" _buf+=");
var regexp = /([$#])\{(.*?)\}/g;
var pos = 0;
var m;
while ((m = regexp.exec(input)) != null) {
var text = input.substring(pos, m.index);
var s = m[0];
pos = m.index + s.length;
this.addText(buf, text);
buf.push(";_buf+=");
var indicator = m[1];
var expr = m[2];
if (indicator == "$")
buf.push(this.escapefunc, "(", expr, ");");
else
buf.push(expr, ";");
}
var rest = pos == 0 ? input : input.substring(pos);
rest ? this.addText(buf, rest, true) : buf.push('""');
buf.push(";");
if (input.charAt(input.length-1) == "\n")
buf.push("\n");
},
addText: function(buf, text, encode_newline) {
if (! text) return;
var s = text.replace(/[\'\\]/g, '\\$&').replace(/\n/g, '\\n\\\n');
buf.push("_buf+='", s, "'");
},
_end: undefined // dummy property to escape strict warning (not legal in ECMA-262)
};
delete(nTenjin.Template.prototype._end);
/*
* convenient function
*/
nTenjin.render = function(template_str, context) {
var template = new nTenjin.Template();
template.convert(template_str);
var output = template.render(context);
return output;
};
/**
* compile str to Function
*
* @param {String} str, template string
* @return {Function}
* @api public
*/
nTenjin.compile = function(str, options) {
var tpl = new nTenjin.Template();
return tpl.convert(str);
};
/*
* node.js
*/
if (typeof module !== 'undefined' && module.exports) {
module.exports = nTenjin;
}
</script>
<script src="https://rawgithub.com/adius/shaven/gh-pages/shaven.min.js"></script>
<script>
window.mustacheTemplate = "<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>";
// note: exactly the same as the mustacheTemplate above.
window.kiteTemplate = "<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>";
window.kiteCompiledTemplate = kite(kiteTemplate); // seems like others are testing compiled versions.
window.handlebarsTemplate = 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>");
window.micro = "<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.micro2 = "<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>";
window.underscoreTemplate = _.template(micro);
window.resigTemplate = tmpl(micro);
window.resigTemplate2 = tmpl2(micro2);
window.resigTemplate3 = tmpl3(micro2);
window.sharedVariables = {
header: "Header",
header2: "Header2",
header3: "Header3",
header4: "Header4",
header5: "Header5",
header6: "Header6",
list: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
};
window.jadeTemplate = "div\n\th1.header!= header\n\th2.header2!= header2\n\th3.header3!= header3\n\th4.header4!= header4\n\th5.header5!= header5\n\th6.header6!= header6\n\tul.list\n\t\teach item in list\n\t\t\tli.item!= item";
window.hamlTemplate = 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 %ul.list\n :each item in list\n %li.item= item");
window.ecoTemplate = 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><ul class='list'><% for item in @list: %><li class='item'><%- item %></li><% end %></ul></div>");
window.jQueryTemplate = $.template(null, "<div><h1 class='header'>{{html header}}</h1><h2 class='header2'>{{html header2}}</h2><h3 class='header3'>{{html header3}}</h3><h4 class='header4'>{{html header4}}</h4><h5 class='header5'>{{html header5}}</h5><h6 class='header6'>{{html header6}}</h6><ul class='list'>{{each list}}<li class='item'>{{html $value}}</li>{{/each}}</ul></div>");
window.doTtemplate = 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>");
window.doUtemplate = 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>");
//window.jqote2 = $.jqotec(jqote_tmpl);
window.ejs = new EJS({
text: micro
});
window.baseHtml = "<div><h1 class='header'></h1><h2 class='header2'></h2><h3 class='header3'></h3><h4 class='header4'></h4><h5 class='header5'></h5><h6 class='header6'></h6><ul class='list'><li class='item'></li></ul></div>";
window.pureTemplate = $p('div.pure').compile({
h1: 'header',
h2: 'header2',
h3: 'header3',
h4: 'header4',
h5: 'header5',
h6: 'header6',
li: {
'itm<-list': {
'.': 'itm'
}
}
});
window.hamlTemplate_2 = "%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 %ul.list\n :each item in list\n %li.item= item";
window.hamlCompiled = Haml.compile(hamlTemplate_2);
window.hamlOptimized = Haml.optimize(hamlCompiled);
dust.loadSource(dust.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>", "dustTemplate"));
window.timTemplate = "<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'>{{_content}}</li>{{/list}}</ul></div>";
window.timLiteTemplate = "<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'><li class='item'>{{list.0}}</li><li class='item'>{{list.1}}</li><li class='item'>{{list.2}}</li><li class='item'>{{list.3}}</li><li class='item'>{{list.4}}</li><li class='item'>{{list.5}}</li><li class='item'>{{list.6}}</li><li class='item'>{{list.7}}</li><li class='item'>{{list.8}}</li><li class='item'>{{list.9}}</li></ul></div>";
window.tenjinTemplate = "<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'><?js for (var i = 0, l = list.length; i < l; i++) { ?><li class='item'>#{ list[i] }</li><?js } ?></ul></div>";
window.convertedTenjinTemplate = new Shotenjin.Template();
window.convertedTenjinTemplate.convert(tenjinTemplate);
window.nTenjinTemplate = "<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'><?js for (var i = 0, l = it.list.length; i < l; i++) { ?><li class='item'>#{ it.list[i] }</li><?js } ?></ul></div>";
window.convertednTenjinTemplate = new nTenjin.Template();
window.convertednTenjinTemplate.convert(nTenjinTemplate);
window.shavenTemplate = function (data){
return ['div',['h1.header', data.header],['h2.header2', data.header2],['h3.header3', data.header3],['h4.header4', data.header4],['h5.header5', data.header5],['h6.header6', data.header6],['ul.list',['li.item', data.list[0]],['li.item', data.list[1]],['li.item', data.list[2]],['li.item', data.list[3]],['li.item', data.list[4]],['li.item', data.list[5]],['li.item', data.list[6]],['li.item', data.list[7]],['li.item', data.list[8]],['li.item', data.list[9]]]]
}
</script>
Ready to run.
Test | Ops/sec | |
---|---|---|
Mustache.js Template |
| ready |
Resig Micro-Templating. |
| ready |
Creationix's Haml-js Template |
| ready |
Jade Template |
| ready |
Underscore.js Template |
| ready |
Eco Template |
| ready |
jQuery Templates |
| ready |
Handlebars.js |
| ready |
doT.js |
| ready |
doU.js |
| ready |
ejs |
| ready |
Pure |
| ready |
Creationix's Haml-js Template (compiled & optimized) |
| ready |
dust |
| ready |
KiTE |
| ready |
Resig Micro-Templating without with(obj) |
| ready |
Resig Micro-Templating with += instead of push and join |
| ready |
Milk |
| ready |
Tim |
| ready |
Tim (lite, cached) |
| ready |
jsTenjin(not converted) |
| ready |
jsTenjin(converted) |
| ready |
nTenjin(converted) |
| ready |
Shaven |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.